diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Fri Oct 11 21:23:04 2002
+++ b/Documentation/Changes	Fri Oct 11 21:23:04 2002
@@ -53,7 +53,7 @@
 o  binutils               2.9.5.0.25              # ld -v
 o  util-linux             2.10o                   # fdformat --version
 o  modutils               2.4.2                   # insmod -V
-o  e2fsprogs              1.25                    # tune2fs
+o  e2fsprogs              1.29                    # tune2fs
 o  jfsutils               1.0.14                  # fsck.jfs -V
 o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
 o  xfsprogs               2.1.0                   # xfs_db -V
diff -Nru a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
--- a/Documentation/DMA-mapping.txt	Fri Oct 11 21:22:59 2002
+++ b/Documentation/DMA-mapping.txt	Fri Oct 11 21:22:59 2002
@@ -759,14 +759,12 @@
 	unsigned int offset;
 	unsigned int length;
 
-   This means that your pci_{map,unmap}_sg() and all other
-   interfaces dealing with scatterlists must be able to cope
-   properly with page being non NULL.
+   The base address is specified by a "page+offset" pair.
 
-   A scatterlist is in one of two states.  The base address is
-   either specified by "address" or by a "page+offset" pair.
-   If "address" is NULL, then "page+offset" is being used.
-   If "page" is NULL, then "address" is being used.
+   Previous versions of struct scatterlist contained a "void *address"
+   field that was sometimes used instead of page+offset.  As of Linux
+   2.5., page+offset is always used, and the "address" field has been
+   deleted.
 
 2) More to come...
 
diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile	Fri Oct 11 21:22:58 2002
+++ b/Documentation/DocBook/Makefile	Fri Oct 11 21:22:58 2002
@@ -11,8 +11,16 @@
 	    kernel-locking.sgml via-audio.sgml mousedrivers.sgml \
 	    deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
 	    writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \
-	    kernel-api.sgml
+	    kernel-api.sgml journal-api.sgml lsm.sgml
 
+JBDSOURCES :=  $(TOPDIR)/include/linux/jbd.h \
+	$(TOPDIR)/fs/jbd/journal.c \
+	$(TOPDIR)/fs/jbd/recovery.c \
+	$(TOPDIR)/fs/jbd/transaction.c
+
+journal-api.sgml: journal-api.tmpl $(JBDSOURCES)
+	$(TOPDIR)/scripts/docgen   $(JBDSOURCES) \
+	<journal-api.tmpl >journal-api.sgml
 ###
 # The build process is as follows (targets):
 #              (sgmldocs)
@@ -154,7 +162,6 @@
 OUT     :=      $(patsubst %.sgml, %.out, $(BOOKS))
 
 clean:
-	@rm -f core *~
 	@rm -f $(BOOKS)
 	@rm -f $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
 	@rm -f $(PNG-parportbook) $(EPS-parportbook)
diff -Nru a/Documentation/DocBook/journal-api.tmpl b/Documentation/DocBook/journal-api.tmpl
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/DocBook/journal-api.tmpl	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,297 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<book id="LinuxJBDAPI">
+ <bookinfo>
+  <title>The Linux Journalling API</title>
+  <authorgroup>
+  <author>
+     <firstname>Roger</firstname>
+     <surname>Gammans</surname>
+     <affiliation>
+     <address>
+      <email>rgammans@computer-surgery.co.uk</email>
+     </address>
+    </affiliation>
+     </author> 
+  </authorgroup>
+  
+  <authorgroup>
+   <author>
+    <firstname>Stephen</firstname>
+    <surname>Tweedie</surname>
+    <affiliation>
+     <address>
+      <email>sct@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2002</year>
+   <holder>Roger Gammans</holder>
+  </copyright>
+
+<legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+      
+   <para>
+     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.
+   </para>
+      
+   <para>
+     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., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+      
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="Overview">
+     <title>Overview</title>
+  <sect1>
+     <title>Details</title>
+<para>
+The journalling layer is  easy to use. You need to 
+first of all create a journal_t data structure. There are
+two calls to do this dependent on how you decide to allocate the physical
+media on which the journal resides. The journal_init_inode() call 
+is for journals stored in filesystem inodes, or the journal_init_dev()
+call can be use for journal stored on a raw device (in a continuous range 
+of blocks). A journal_t is a typedef for a struct pointer, so when
+you are finally finished make sure you call journal_destroy() on it
+to free up any used kernel memory.
+</para>
+
+<para>
+Once you have got your journal_t object you need to 'mount' or load the journal
+file, unless of course you haven't initialised it yet - in which case you
+need to call journal_create().
+</para>
+
+<para>
+Most of the time however your journal file will already have been created, but
+before you load it you must call journal_wipe() to empty the journal file.
+Hang on, you say , what if the filesystem wasn't cleanly umount()'d . Well, it is the 
+job of the client file system to detect this and skip the call to journal_wipe().
+</para>
+
+<para>
+In either case the next call should be to journal_load() which prepares the
+journal file for use. Note that journal_wipe(..,0) calls journal_skip_recovery() 
+for you if it detects any outstanding transactions in the journal and similarly
+journal_load() will call journal_recover() if necessary.
+I would advise reading fs/ext3/super.c for examples on this stage.
+[RGG: Why is the journal_wipe() call necessary - doesn't this needlessly 
+complicate the API. Or isn't a good idea for the journal layer to hide 
+dirty mounts from the client fs]
+</para>
+
+<para>
+Now you can go ahead and start modifying the underlying 
+filesystem. Almost.
+</para>
+
+
+<para>
+
+You still need to actually journal your filesystem changes, this
+is done by wrapping them into transactions. Additionally you
+also need to wrap the modification of each of the the buffers
+with calls to the journal layer, so it knows what the modifications
+you are actually making are. To do this use  journal_start() which
+returns a transaction handle.
+</para>
+
+<para>
+journal_start()
+and its counterpart journal_stop(), which indicates the end of a transaction
+are nestable calls, so you can reenter a transaction if necessary,
+but remember you must call journal_stop() the same number of times as
+journal_start() before the transaction is completed (or more accurately
+leaves the the update phase). Ext3/VFS makes use of this feature to simplify 
+quota support.
+</para>
+
+<para>
+Inside each transaction you need to wrap the modifications to the
+individual buffers (blocks). Before you start to modify a buffer you
+need to call journal_get_{create,write,undo}_access() as appropriate,
+this allows the journalling layer to copy the unmodified data if it
+needs to. After all the buffer may be part of a previously uncommitted
+transaction. 
+At this point you are at last ready to modify a buffer, and once
+you are have done so you need to call journal_dirty_{meta,}data().
+Or if you've asked for access to a buffer you now know is now longer 
+required to be pushed back on the device you can call journal_forget()
+in much the same way as you might have used bforget() in the past.
+
+</para>
+
+
+
+<para>
+A journal_flush() may be called at any time to commit and checkpoint
+all your transactions.
+</para>
+<para>
+
+Then at umount time , in your put_super() (2.4) or write_super() (2.5)
+you can then call journal_destroy() to clean up your in-core journal object.
+</para>
+
+
+<para>
+Unfortunately there a couple of ways the journal layer can cause a deadlock.
+The first thing to note is that each task can only have
+a single outstanding transaction at any one time, remember nothing
+commits until the outermost journal_stop(). This means
+you must complete the transaction at the end of each file/inode/address
+etc. operation you perform, so that the journalling system isn't re-entered
+on another journal. Since transactions can't be nested/batched 
+across differing journals, and another filesystem other than
+yours (say ext3) may be modified in a later syscall.
+</para>
+<para>
+
+The second case to bear in mind is that journal_start() can 
+block if there isn't enough space in the journal for your transaction 
+(based on the passed nblocks param) - when it blocks it merely(!) needs to
+wait for transactions to complete and be committed from other tasks, 
+so essentially we are waiting for journal_stop(). So to avoid 
+deadlocks you must treat journal_start/stop() as if they
+were semaphores and include them in your semaphore ordering rules to prevent 
+deadlocks. Note that journal_extend() has similar blocking behaviour to
+journal_start() so you can deadlock here just as easily as on journal_start().
+</para>
+<para>
+
+Try to reserve the right number of blocks the first time. ;-).
+</para>
+<para>
+Another wriggle to watch out for is your on-disk block allocation strategy.
+why? Because, if you undo a delete, you need to ensure you haven't reused any
+of the freed blocks in a later transaction. One simple way of doing this
+is make sure any blocks you allocate only have checkpointed transactions
+listed against them. Ext3 does this in ext3_test_allocatable(). 
+</para>
+
+<para>
+Lock is also providing through journal_{un,}lock_updates(),
+ext3 uses this when it wants a window with a clean and stable fs for a moment.
+eg. 
+<programlisting>
+
+	journal_lock_updates() //stop new stuff happening..
+	journal_flush()        // checkpoint everything.
+	..do stuff on stable fs
+	journal_unlock_updates() // carry on with filesystem use.
+</programlisting>
+
+The opportunities for abuse and DOS attacks with this should be obvious,
+if you allow unprivileged userspace to trigger codepaths containing these
+calls.
+
+<para>
+</sect1>
+<sect1>
+<title>Summary</title>
+<para>
+Using the journal is a matter of wrapping the different context changes,
+being each mount, each modification (transaction) and each changed buffer
+to tell the journalling layer about them.
+
+Here is a some pseudo code to give you an idea of how it works, as
+an example.
+<programlisting>
+  journal_t* my_jnrl = journal_create();
+  journal_init_{dev,inode}(jnrl,...)
+  if (clean) journal_wipe();
+  journal_load();
+
+   foreach(transaction) { /*transactions must be 
+                            completed before
+                            a syscall returns to 
+                            userspace*/
+
+          handle_t * xct=journal_start(my_jnrl);
+          foreach(bh) {
+                journal_get_{create,write,undo}_access(xact,bh);
+                if ( myfs_modify(bh) ) { /* returns true 
+                                        if makes changes */
+                           journal_dirty_{meta,}data(xact,bh);
+                } else {
+                           journal_forget(bh);
+                }
+          }
+          journal_stop(xct);
+   }
+   journal_destroy(my_jrnl);
+</programlisting>
+
+</chapter>
+
+  <chapter id="adt">
+     <title>Data Types</title>
+     <para>	
+	The journalling layer uses typedefs to 'hide' the concrete definitions
+	of the structures used. As a client of the JBD layer you can
+	just rely on the using the pointer as a magic cookie  of some sort.
+	
+	Obviously the hiding is not enforced as this is 'C'.
+	</para>
+	<sect1><title>Structures</title>
+!Iinclude/linux/jbd.h
+	</sect1>
+</chapter>
+
+  <chapter id="calls">
+     <title>Functions</title>
+     <para>	
+	The functions here are split into two groups those that
+	affect a journal as a whole, and those which are used to
+	manage transactions
+</para>
+	<sect1><title>Journal Level</title>
+!Efs/jbd/journal.c
+!Efs/jbd/recovery.c
+	</sect1>
+	<sect1><title>Transasction Level</title>
+!Efs/jbd/transaction.c	
+	</sect1>
+</chapter>
+<chapter>
+     <title>See also</title>
+	<para>
+	<citation>
+	   <ulink url="ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/journal-design.ps.gz">
+	   	Journaling the Linux ext2fs Filesystem,LinuxExpo 98, Stephen Tweedie
+	   </ulink>
+	   </citation>
+	   </para>
+	   <para>
+	   <citation>
+	   <ulink url="http://olstrans.sourceforge.net/release/OLS2000-ext3/OLS2000-ext3.html">
+	   	Ext3 Journalling FileSystem , OLS 2000, Dr. Stephen Tweedie
+	   </ulink>
+	   </citation>
+	   </para>
+</chapter>
+
+</book>
diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl	Fri Oct 11 21:22:50 2002
+++ b/Documentation/DocBook/kernel-api.tmpl	Fri Oct 11 21:22:50 2002
@@ -185,6 +185,11 @@
 !Efs/devfs/base.c
   </chapter>
 
+  <chapter id="security">
+     <title>Security Framework</title>
+!Esecurity/security.c
+  </chapter>
+
   <chapter id="pmfuncs">
      <title>Power Management</title>
 !Ekernel/pm.c
diff -Nru a/Documentation/DocBook/lsm.tmpl b/Documentation/DocBook/lsm.tmpl
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/DocBook/lsm.tmpl	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,285 @@
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<article class="whitepaper" id="LinuxSecurityModule" lang="en">
+ <artheader>
+ <title>Linux Security Modules:  General Security Hooks for Linux</title>
+ <authorgroup>
+ <author>
+ <firstname>Stephen</firstname> 
+ <surname>Smalley</surname>
+ <affiliation>
+ <orgname>NAI Labs</orgname>
+ <address><email>ssmalley@nai.com</email></address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Timothy</firstname> 
+ <surname>Fraser</surname>
+ <affiliation>
+ <orgname>NAI Labs</orgname>
+ <address><email>tfraser@nai.com</email></address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Chris</firstname> 
+ <surname>Vance</surname>
+ <affiliation>
+ <orgname>NAI Labs</orgname>
+ <address><email>cvance@nai.com</email></address>
+ </affiliation>
+ </author>
+ </authorgroup
+ </artheader>
+
+<sect1><title>Introduction</title>
+
+<para>
+In March 2001, the National Security Agency (NSA) gave a presentation
+about Security-Enhanced Linux (SELinux) at the 2.5 Linux Kernel
+Summit.  SELinux is an implementation of flexible and fine-grained
+nondiscretionary access controls in the Linux kernel, originally
+implemented as its own particular kernel patch.  Several other
+security projects (e.g. RSBAC, Medusa) have also developed flexible
+access control architectures for the Linux kernel, and various
+projects have developed particular access control models for Linux
+(e.g. LIDS, DTE, SubDomain).  Each project has developed and
+maintained its own kernel patch to support its security needs.
+</para>
+
+<para>
+In response to the NSA presentation, Linus Torvalds made a set of
+remarks that described a security framework he would be willing to
+consider for inclusion in the mainstream Linux kernel.  He described a
+general framework that would provide a set of security hooks to
+control operations on kernel objects and a set of opaque security
+fields in kernel data structures for maintaining security attributes.
+This framework could then be used by loadable kernel modules to
+implement any desired model of security.  Linus also suggested the
+possibility of migrating the Linux capabilities code into such a
+module.
+</para>
+
+<para>
+The Linux Security Modules (LSM) project was started by WireX to
+develop such a framework.  LSM is a joint development effort by
+several security projects, including Immunix, SELinux, SGI and Janus,
+and several individuals, including Greg Kroah-Hartman and James
+Morris, to develop a Linux kernel patch that implements this
+framework.  The patch is currently tracking the 2.4 series and is
+targeted for integration into the 2.5 development series.  This
+technical report provides an overview of the framework and the example
+capabilities security module provided by the LSM kernel patch.
+</para>
+
+</sect1>
+
+<sect1 id="framework"><title>LSM Framework</title>
+
+<para>
+The LSM kernel patch provides a general kernel framework to support
+security modules.  In particular, the LSM framework is primarily
+focused on supporting access control modules, although future
+development is likely to address other security needs such as
+auditing.  By itself, the framework does not provide any additional
+security; it merely provides the infrastructure to support security
+modules.  The LSM kernel patch also moves most of the capabilities
+logic into an optional security module, with the system defaulting
+to the traditional superuser logic.  This capabilities module
+is discussed further in <XRef LinkEnd="cap">.
+</para>
+
+<para>
+The LSM kernel patch adds security fields to kernel data structures
+and inserts calls to hook functions at critical points in the kernel
+code to manage the security fields and to perform access control.  It
+also adds functions for registering and unregistering security
+modules, and adds a general <function>security</function> system call
+to support new system calls for security-aware applications.
+</para>
+
+<para>
+The LSM security fields are simply <type>void*</type> pointers.  For
+process and program execution security information, security fields
+were added to <structname>struct task_struct</structname> and 
+<structname>struct linux_binprm</structname>.  For filesystem security
+information, a security field was added to 
+<structname>struct super_block</structname>.  For pipe, file, and socket
+security information, security fields were added to 
+<structname>struct inode</structname> and 
+<structname>struct file</structname>.  For packet and network device security
+information, security fields were added to
+<structname>struct sk_buff</structname> and
+<structname>struct net_device</structname>.  For System V IPC security
+information, security fields were added to
+<structname>struct kern_ipc_perm</structname> and
+<structname>struct msg_msg</structname>; additionally, the definitions
+for <structname>struct msg_msg</structname>, <structname>struct 
+msg_queue</structname>, and <structname>struct 
+shmid_kernel</structname> were moved to header files
+(<filename>include/linux/msg.h</filename> and
+<filename>include/linux/shm.h</filename> as appropriate) to allow
+the security modules to use these definitions.
+</para>
+
+<para>
+Each LSM hook is a function pointer in a global table,
+security_ops. This table is a
+<structname>security_operations</structname> structure as defined by
+<filename>include/linux/security.h</filename>.  Detailed documentation
+for each hook is included in this header file.  At present, this
+structure consists of a collection of substructures that group related
+hooks based on the kernel object (e.g. task, inode, file, sk_buff,
+etc) as well as some top-level hook function pointers for system
+operations.  This structure is likely to be flattened in the future
+for performance.  The placement of the hook calls in the kernel code
+is described by the "called:" lines in the per-hook documentation in
+the header file.  The hook calls can also be easily found in the
+kernel code by looking for the string "security_ops->".
+
+</para>
+
+<para>
+Linus mentioned per-process security hooks in his original remarks as a
+possible alternative to global security hooks.  However, if LSM were
+to start from the perspective of per-process hooks, then the base
+framework would have to deal with how to handle operations that
+involve multiple processes (e.g. kill), since each process might have
+its own hook for controlling the operation.  This would require a
+general mechanism for composing hooks in the base framework.
+Additionally, LSM would still need global hooks for operations that
+have no process context (e.g. network input operations).
+Consequently, LSM provides global security hooks, but a security
+module is free to implement per-process hooks (where that makes sense)
+by storing a security_ops table in each process' security field and
+then invoking these per-process hooks from the global hooks.
+The problem of composition is thus deferred to the module.
+</para>
+
+<para>
+The global security_ops table is initialized to a set of hook
+functions provided by a dummy security module that provides
+traditional superuser logic.  A <function>register_security</function>
+function (in <filename>security/security.c</filename>) is provided to
+allow a security module to set security_ops to refer to its own hook
+functions, and an <function>unregister_security</function> function is
+provided to revert security_ops to the dummy module hooks.  This
+mechanism is used to set the primary security module, which is
+responsible for making the final decision for each hook.
+</para>
+
+<para>
+LSM also provides a simple mechanism for stacking additional security
+modules with the primary security module.  It defines
+<function>register_security</function> and
+<function>unregister_security</function> hooks in the
+<structname>security_operations</structname> structure and provides
+<function>mod_reg_security</function> and
+<function>mod_unreg_security</function> functions that invoke these
+hooks after performing some sanity checking.  A security module can
+call these functions in order to stack with other modules.  However,
+the actual details of how this stacking is handled are deferred to the
+module, which can implement these hooks in any way it wishes
+(including always returning an error if it does not wish to support
+stacking).  In this manner, LSM again defers the problem of
+composition to the module.
+</para>
+
+<para>
+Although the LSM hooks are organized into substructures based on
+kernel object, all of the hooks can be viewed as falling into two
+major categories: hooks that are used to manage the security fields
+and hooks that are used to perform access control.  Examples of the
+first category of hooks include the
+<function>alloc_security</function> and
+<function>free_security</function> hooks defined for each kernel data
+structure that has a security field.  These hooks are used to allocate
+and free security structures for kernel objects.  The first category
+of hooks also includes hooks that set information in the security
+field after allocation, such as the <function>post_lookup</function>
+hook in <structname>struct inode_security_ops</structname>.  This hook
+is used to set security information for inodes after successful lookup
+operations.  An example of the second category of hooks is the
+<function>permission</function> hook in 
+<structname>struct inode_security_ops</structname>.  This hook checks
+permission when accessing an inode.
+</para>
+
+<para>
+LSM adds a general <function>security</function> system call that
+simply invokes the <function>sys_security</function> hook.  This
+system call and hook permits security modules to implement new system
+calls for security-aware applications.  The interface is similar to
+socketcall, but also has an <parameter>id</parameter> to help identify
+the security module whose call is being invoked.  
+To eliminate the need for a central registry of ids,
+the recommended convention for creating the hexadecimal id value is:
+<programlisting>
+<![CDATA[
+ echo "Name_of_module" | md5sum | cut -c -8
+]]>
+</programlisting>
+C code will need to prefix this result with ``0x''.
+For example, the id for ``SGI Trusted Linux'' could be used in C as:
+<programlisting>
+<![CDATA[
+ #define SYS_SECURITY_MODID 0xc4c7be22
+]]>
+</programlisting>
+</para>
+
+</sect1>
+
+<sect1 id="cap"><title>LSM Capabilities Module</title>
+
+<para>
+The LSM kernel patch moves most of the existing POSIX.1e capabilities
+logic into an optional security module stored in the file
+<filename>security/capability.c</filename>.  This change allows
+users who do not want to use capabilities to omit this code entirely
+from their kernel, instead using the dummy module for traditional
+superuser logic or any other module that they desire.  This change
+also allows the developers of the capabilities logic to maintain and
+enhance their code more freely, without needing to integrate patches
+back into the base kernel.
+</para>
+
+<para>
+In addition to moving the capabilities logic, the LSM kernel patch
+could move the capability-related fields from the kernel data
+structures into the new security fields managed by the security
+modules.  However, at present, the LSM kernel patch leaves the
+capability fields in the kernel data structures.  In his original
+remarks, Linus suggested that this might be preferable so that other
+security modules can be easily stacked with the capabilities module
+without needing to chain multiple security structures on the security field.
+It also avoids imposing extra overhead on the capabilities module
+to manage the security fields.  However, the LSM framework could
+certainly support such a move if it is determined to be desirable,
+with only a few additional changes described below.
+</para>
+
+<para>
+At present, the capabilities logic for computing process capabilities
+on <function>execve</function> and <function>set*uid</function>,
+checking capabilities for a particular process, saving and checking
+capabilities for netlink messages, and handling the
+<function>capget</function> and <function>capset</function> system
+calls have been moved into the capabilities module.  There are still a
+few locations in the base kernel where capability-related fields are
+directly examined or modified, but the current version of the LSM
+patch does allow a security module to completely replace the
+assignment and testing of capabilities.  These few locations would
+need to be changed if the capability-related fields were moved into
+the security field.  The following is a list of known locations that
+still perform such direct examination or modification of
+capability-related fields:
+<itemizedlist>
+<listitem><para><filename>fs/open.c</filename>:<function>sys_access</function></para></listitem>
+<listitem><para><filename>fs/lockd/host.c</filename>:<function>nlm_bind_host</function></para></listitem>
+<listitem><para><filename>fs/nfsd/auth.c</filename>:<function>nfsd_setuser</function></para></listitem>
+<listitem><para><filename>fs/proc/array.c</filename>:<function>task_cap</function></para></listitem>
+</itemizedlist>
+</para>
+
+</sect1>
+
+</article>
diff -Nru a/Documentation/DocBook/parportbook.tmpl b/Documentation/DocBook/parportbook.tmpl
--- a/Documentation/DocBook/parportbook.tmpl	Fri Oct 11 21:22:52 2002
+++ b/Documentation/DocBook/parportbook.tmpl	Fri Oct 11 21:22:52 2002
@@ -595,7 +595,7 @@
    So, the first thing for the device driver to do is tell
    <literal>parport</literal> that it wants to know what parallel
    ports are on the system.  To do this, it uses the
-   <function>parport_register_device</function> function:
+   <function>parport_register_driver</function> function:
   </para>
 
   <funcsynopsis>
diff -Nru a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
--- a/Documentation/SubmittingDrivers	Fri Oct 11 21:23:02 2002
+++ b/Documentation/SubmittingDrivers	Fri Oct 11 21:23:02 2002
@@ -2,9 +2,8 @@
 ---------------------------------------
 
 This document is intended to explain how to submit device drivers to the
-Linux 2.2 and 2.4 kernel trees. Note that if you are interested in video
-card drivers you should probably talk to XFree86 (http://www.xfree86.org) 
-instead.
+various kernel trees. Note that if you are interested in video card drivers
+you should probably talk to XFree86 (http://www.xfree86.org) instead.
 
 Also read the Documentation/SubmittingPatches document.
 
@@ -35,21 +34,23 @@
 	maintainer then please contact Alan Cox <alan@lxorguk.ukuu.org.uk>
 
 Linux 2.4:
-	This kernel tree is under active development. The same rules apply
-	as 2.2 but you may wish to submit your driver via linux-kernel (see
-	resources) and follow that list to track changes in API's. These
-	should no longer be occuring as we are now in a code freeze.
-	The final contact point for Linux 2.4 submissions is 	
-	<torvalds@transmeta.com>.
+	The same rules apply as 2.2 but this kernel tree is under active
+	development. The final contact point for Linux 2.4 submissions is
+	Marcelo Tosatti <marcelo@conectiva.com.br>.
+
+Linux 2.5:
+	The same rules apply as 2.4 except that you should follow linux-kernel
+	to track changes in API's. The final contact point for Linux 2.5
+	submissions is Linus Torvalds <torvalds@transmeta.com>.
 
 What Criteria Determine Acceptance
 ----------------------------------
 
-Licensing:	The code must be released to us under the GNU General Public License. 
-		We don't insist on any kind of exclusively GPL licensing,
-		and if you wish the driver to be useful to other communities
-		such as BSD you may well wish to release under multiple
-		licenses.
+Licensing:	The code must be released to us under the
+		GNU General Public License. We don't insist on any kind
+		of exclusively GPL licensing, and if you wish the driver
+		to be useful to other communities such as BSD you may well
+		wish to release under multiple licenses.
 
 Interfaces:	If your driver uses existing interfaces and behaves like
 		other drivers in the same class it will be much more likely
@@ -64,12 +65,13 @@
 		maintain them just once seperate them out nicely and note
 		this fact.
 
-Portability:	Pointers are not always 32bits, people do not all have
-		floating point and you shouldn't use inline x86 assembler in 
-		your driver without careful thought. Pure x86 drivers
-		generally are not popular. If you only have x86 hardware it 
-		is hard to test portability but it is easy to make sure the
-		code can easily be made portable.
+Portability:	Pointers are not always 32bits, not all computers are little
+		endian, people do not all have floating point and you
+		shouldn't use inline x86 assembler in your driver without
+		careful thought. Pure x86 drivers generally are not popular.
+		If you only have x86 hardware it is hard to test portability
+		but it is easy to make sure the code can easily be made
+		portable.
 
 Clarity:	It helps if anyone can see how to fix the driver. It helps
 		you because you get patches not bug reports. If you submit a
diff -Nru a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
--- a/Documentation/filesystems/00-INDEX	Fri Oct 11 21:23:05 2002
+++ b/Documentation/filesystems/00-INDEX	Fri Oct 11 21:23:05 2002
@@ -8,6 +8,8 @@
 	- info and mount options for the Amiga Fast File System.
 bfs.txt
 	- info for the SCO UnixWare Boot Filesystem (BFS).
+cifs.txt
+	- description of the CIFS filesystem
 coda.txt
 	- description of the CODA filesystem.
 cramfs.txt
diff -Nru a/Documentation/filesystems/cifs.txt b/Documentation/filesystems/cifs.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/filesystems/cifs.txt	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,26 @@
+This module, cifs, is a filesystem that implements the SMB/CIFS protocol, which is the
+protocol used by Windows based operating systems (including Windows 2000 and its successors)
+as well as Samba, OS/2 and many others operating systems and network file server appliances.
+The Cifs VFS filesystem module is designed to work well with servers that implement the newer versions
+(dialects) of the SMB/CIFS protocol such as Samba, the program written by Andrew Tridgell
+that turns any Unix host into a file server for DOS or Windows clients, as well as Windows NT,
+Windows 2000 and its successors.  It is not designed to handle older smb servers well, those that
+implement older versions of the dialect (such as OS/2 or Windows 95), for this purpose use smbfs.  
+
+This module can support mounting without a mount helper program.  The mount syntax is:
+        mount //server_ip_address/share_name  /mnt -o user=username,password=your_password
+where "username", "your_password" and "server_ip_address" and "share_name" should be replaced
+with specific values (supplied by the user) e.g.  
+	mount //9.53.216.16/public /mnt -o user=jsmith,password=openup  
+
+This cifs implementation is designed to handle network caching (safely) as well as to implement locking,
+large file (64 bit access), distributed file system ("dfs") and other advanced protocol features. It
+also implements the SNIA standard for Unix extensions to CIFS (when communicating with servers such as
+Samba 2.2.3 or later which support it).
+
+For more information contact sfrench@us.ibm.com
+
+Cifs is an SMB client (or gateway). For more info on the SMB/CIFS protocol and Samba, including
+documentation, please go to http://www.samba.org/ and then on to your nearest mirror.  For more
+information about the cifs vfs, go to the project page at:
+	http://us1.samba.org/samba/Linux_CIFS_client.html
diff -Nru a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
--- a/Documentation/filesystems/proc.txt	Fri Oct 11 21:22:55 2002
+++ b/Documentation/filesystems/proc.txt	Fri Oct 11 21:22:55 2002
@@ -728,36 +728,26 @@
 used ones  is  far  behind,  you've  encountered  a peak in your usage of file
 handles and you don't need to increase the maximum.
 
-inode-state, inode-nr and inode-max
------------------------------------
-
-As with  file  handles, the kernel allocates the inode structures dynamically,
-but can't free them yet.
-
-The value  in  inode-max  denotes  the  maximum number of inode handlers. This
-value should  be  3 to 4 times larger than the value in file-max, since stdin,
-stdout, and  network  sockets also need an inode struct to handle them. If you
-regularly run out of inodes, you should increase this value.
+inode-state and inode-nr
+------------------------
 
 The file inode-nr contains the first two items from inode-state, so we'll skip
 to that file...
 
-inode-state contains  three  actual numbers and four dummy values. The numbers
-are nr_inodes, nr_free_inodes, and preshrink (in order of appearance).
+inode-state contains  two  actual numbers and five dummy values. The numbers
+are nr_inodes and nr_free_inodes (in order of appearance).
 
 nr_inodes
 ~~~~~~~~~
 
-Denotes the  number  of  inodes the system has allocated. This can be slightly
-more than inode-max because Linux allocates them one pageful at a time.
+Denotes the  number  of  inodes the system has allocated. This number will
+grow and shrink dynamically.
 
 nr_free_inodes
 --------------
 
-Represents the  number  of free inodes and preshrink is nonzero when nr_inodes
-is greater than inode-max and the system needs to prune the inode list instead
-of allocating more.
-
+Represents the  number of free inodes. Ie. The number of inuse inodes is
+(nr_inodes - nr_free_inodes).
 
 super-nr and super-max
 ----------------------
diff -Nru a/Documentation/isapnp.txt b/Documentation/isapnp.txt
--- a/Documentation/isapnp.txt	Fri Oct 11 21:23:05 2002
+++ b/Documentation/isapnp.txt	Fri Oct 11 21:23:05 2002
@@ -29,6 +29,7 @@
 poke <reg> <value>	- poke configuration byte to selected register
 pokew <reg> <value>	- poke configuration word to selected register
 poked <reg> <value>	- poke configuration dword to selected register
+allow_dma0 <value>	- allow dma channel 0 during auto activation: 0=off, 1=on
 
 Explanation:
 	- variable <idx> begins with zero
diff -Nru a/Documentation/kbuild/random.txt b/Documentation/kbuild/random.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/kbuild/random.txt	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,47 @@
+Code by Ghozlane Toumi <gtoumi@messel.emse.fr>, documentation by
+Keith Owens <kaos@ocs.com.au>
+
+In addition to the normal config targets you can make
+
+  randconfig	random configuration.
+
+  allyes	reply 'y' to all options, maximal kernel.
+
+  allno		reply 'n' to all options, minimal kernel.
+
+  allmod	build everything as modules where possible.
+
+
+All random configurations will satisfy the config rules, that is, all
+configurations should be valid.  Any build errors indicate bugs in the
+config dependency rules or in the Makefiles.
+
+You can constrain the random configuration, e.g. you may want to force
+the use of modules or the absence of /proc or cramfs must be a module.
+If file .force_default exists then it is read to preset selected
+values, all other values will be randomly selected, subject to the
+config rules.  The syntax of .force_default is:
+
+CONFIG_foo=value
+  Force this value, for example CONFIG_MODULES=y, CONFIG_PROC_FS=n,
+  CONFIG_RAMFS=m.
+
+# CONFIG_foo is not set
+  Equivalent to CONFIG_foo=n, supported because this is the format used
+  in .config.  NOTE: The leading '#' is required.
+
+# list CONFIG_foo val1,val2,val3
+  Pick a value for CONFIG_foo from the list.  CONFIG_foo must be an int
+  or hex option.  NOTE: The leading '#' is required.
+
+# range CONFIG_foo min max
+  Pick a value for CONFIG_foo in the range min <=> max.  CONFIG_foo
+  must be an int option.  NOTE: The leading '#' is required.
+
+If you have repeated settings of the same option in .force_default then
+values take precedence over lists which take precedence over range.
+Within each group the last setting for an option is used.
+
+Answers "randomised" are bool(), tristate(), dep_tristate() and
+choice().  Unless specified in .force_default, int, hex, and string
+options use the default values from config.in.
diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	Fri Oct 11 21:23:06 2002
+++ b/Documentation/kernel-parameters.txt	Fri Oct 11 21:23:06 2002
@@ -127,7 +127,7 @@
 
 	BusLogic=	[HW,SCSI]
 
-	cachesize=	[BUGS=ix86] Override level 2 CPU cache size detection.
+	cachesize=	[BUGS=IA-32] Override level 2 CPU cache size detection.
 			Sometimes CPU hardware bugs make them report the cache
 			size incorrectly. The kernel will attempt work arounds
 			to fix known problems, but for some CPUs it is not
@@ -319,7 +319,9 @@
 
 	max_scsi_luns=	[SCSI]
 
-	mca-pentium	[BUGS=ix86]
+	mca		[IA-32] On some pentium machines the mce support defaults
+				to off as the mainboard support is not always present.
+				You must activate it as a boot option
 
 	mcd=		[HW,CD]
 
@@ -339,6 +341,9 @@
 
 	memfrac=	[KNL]
 
+	mem=nopentium	[BUGS=IA-32] Disable usage of 4MB pages for kernel
+			memory.
+
 	mga=		[HW,DRM]
 
 	mpu401=		[HW,SOUND]
@@ -365,9 +370,9 @@
 
 	nfsroot=	[NFS] nfs root filesystem for disk-less boxes.
 
-	nmi_watchdog=	[KNL,BUGS=ix86] debugging features for SMP kernels.
+	nmi_watchdog=	[KNL,BUGS=IA-32] debugging features for SMP kernels.
 
-	no387		[BUGS=ix86] Tells the kernel to use the 387 maths
+	no387		[BUGS=IA-32] Tells the kernel to use the 387 maths
 			emulation library even if a 387 maths coprocessor
 			is present.
 
@@ -385,7 +390,9 @@
 
 	nohlt		[BUGS=ARM]
  
-	no-hlt		[BUGS=ix86]
+	no-hlt		[BUGS=IA-32]
+
+	noht		[SMP,IA-32] Disables P4 Xeon(tm) HyperThreading.
 
 	noisapnp	[ISAPNP] Disables ISA PnP code.
 
@@ -402,7 +409,7 @@
 
 	nosync		[HW, M68K] Disables sync negotiation for all devices.
 
-	notsc           [BUGS=ix86] Disable Time Stamp Counter
+	notsc           [BUGS=IA-32] Disable Time Stamp Counter
 
 	nowb		[ARM]
  
@@ -518,7 +525,7 @@
 	ramdisk_start=	[RAM] Starting block of RAM disk image (so you can
 			place it after the kernel image on a boot floppy).
 
-	reboot=		[BUGS=ix86]
+	reboot=		[BUGS=IA-32]
 
 	reserve=	[KNL,BUGS] force the kernel to ignore some iomem area.
 
@@ -607,7 +614,7 @@
  
 	video=		[FB] frame buffer configuration.
 
-	vga=		[BOOT] on ix386, select a particular video mode
+	vga=		[BOOT] on IA-32, select a particular video mode
 			(use vga=ask for menu).  This is actually a
 			boot loader parameter; the value is passed to
 			the kernel using a special protocol.  See
diff -Nru a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt
--- a/Documentation/networking/decnet.txt	Fri Oct 11 21:22:51 2002
+++ b/Documentation/networking/decnet.txt	Fri Oct 11 21:22:51 2002
@@ -28,8 +28,36 @@
 that you need it, in general you won't and it can cause ifconfig to
 malfunction.
 
+Run time configuration has changed slightly from the 2.4 system. If you
+want to configure an endnode, then the simplified procedure is as follows:
+
+ o Set the MAC address on your ethernet card before starting _any_ other
+   network protocols.
+
+As soon as your network card is brought into the UP state, DECnet should
+start working. If you need something more complicated or are unsure how
+to set the MAC address, see the next section. Also all configurations which
+worked with 2.4 will work under 2.5 with no change.
+
 3) Command line options
 
+You can set a DECnet address on the kernel command line for compatibility
+with the 2.4 configuration procedure, but in general its not needed any more.
+If you do st a DECnet address on the command line, it has only one purpose
+which is that its added to the addresses on the loopback device.
+
+With 2.4 kernels, DECnet would only recognise addresses as local if they
+were added to the loopback device. In 2.5, any local interface address
+can be used to loop back to the local machine. Of course this does not
+prevent you adding further addresses to the loopback device if you
+want to.
+
+N.B. Since the address list of an interface determines the addresses for
+which "hello" messages are sent, if you don't set an address on the loopback
+interface then you won't see any entries in /proc/net/neigh for the local
+host until such time as you start a connection. This doesn't affect the
+operation of the local communications in any other way though.
+
 The kernel command line takes options looking like the following:
 
     decnet=1,2
@@ -51,7 +79,7 @@
 
 Currently the only supported devices are ethernet and ip_gre. The
 ethernet address of your ethernet card has to be set according to the DECnet
-address of the node in order for it to be recognised (and thus appear in
+address of the node in order for it to be autoconfigured (and then appear in
 /proc/net/decnet_dev). There is a utility available at the above
 FTP sites called dn2ethaddr which can compute the correct ethernet
 address to use. The address can be set by ifconfig either before at
@@ -61,14 +89,22 @@
     MACADDR=AA:00:04:00:03:04
 
 or something similar, to /etc/sysconfig/network-scripts/ifcfg-eth0 or
-wherever your network card's configuration lives.
+wherever your network card's configuration lives. Setting the MAC address
+of your ethernet card to an address starting with "hi-ord" will cause a
+DECnet address which matches to be added to the interface (which you can
+verify with iproute2).
 
-You will also need to set /proc/sys/net/decnet/default_device to the
+The default device for routing can be set through the /proc filesystem
+by setting /proc/sys/net/decnet/default_device to the
 device you want DECnet to route packets out of when no specific route
 is available. Usually this will be eth0, for example:
 
     echo -n "eth0" >/proc/sys/net/decnet/default_device
 
+If you don't set the default device, then it will default to the first
+ethernet card which has been autoconfigured as described above. You can
+confirm that by looking in the default_device file of course.
+
 There is a list of what the other files under /proc/sys/net/decnet/ do
 on the kernel patch web site (shown above).
 
@@ -149,7 +185,36 @@
    You may also need to increase the length grabbed with the -s flag. The
    -e flag also provides very useful information (ethernet MAC addresses))
 
-7) Mailing list
+7) MAC FAQ
+
+A quick FAQ on ethernet MAC addresses to explain how Linux and DECnet
+interact and how to get the best performance from your hardware. 
+
+Ethernet cards are designed to normally only pass received network frames 
+to a host computer when they are addressed to it, or to the broadcast address.
+
+Linux has an interface which allows the setting of extra addresses for
+an ethernet card to listen to. If the ethernet card supports it, the
+filtering operation will be done in hardware, if not the extra unwanted packets
+received will be discarded by the host computer. In the latter case,
+significant processor time and bus bandwidth can be used up on a busy
+network (see the NAPI documentation for a longer explanation of these
+effects).
+
+DECnet makes use of this interface to allow running DECnet on an ethernet 
+card which has already been configured using TCP/IP (presumably using the 
+built in MAC address of the card, as usual) and/or to allow multiple DECnet
+addresses on each physical interface. If you do this, be aware that if your
+ethernet card doesn't support perfect hashing in its MAC address filter
+then your computer will be doing more work than required. Some cards
+will simply set themselves into promiscuous mode in order to receive
+packets from the DECnet specified addresses. So if you have one of these
+cards its better to set the MAC address of the card as described above
+to gain the best efficiency. Better still is to use a card which supports
+NAPI as well.
+
+
+8) Mailing list
 
 If you are keen to get involved in development, or want to ask questions
 about configuration, or even just report bugs, then there is a mailing
@@ -157,7 +222,7 @@
 
 http://sourceforge.net/mail/?group_id=4993
 
-8) Legal Info
+9) Legal Info
 
 The Linux DECnet project team have placed their code under the GPL. The
 software is provided "as is" and without warranty express or implied.
diff -Nru a/Documentation/networking/ewrk3.txt b/Documentation/networking/ewrk3.txt
--- a/Documentation/networking/ewrk3.txt	Fri Oct 11 21:22:54 2002
+++ b/Documentation/networking/ewrk3.txt	Fri Oct 11 21:22:54 2002
@@ -24,6 +24,7 @@
     kernel with the ewrk3 configuration turned off and reboot.
     5) insmod ewrk3.o
           [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
+          [Adam Kropelin: Multiple cards now supported by irq=x1,x2 io=y1,y2]
     6) run the net startup bits for your new eth?? interface manually 
     (usually /etc/rc.inet[12] at boot time). 
     7) enjoy!
diff -Nru a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
--- a/Documentation/networking/ip-sysctl.txt	Fri Oct 11 21:22:56 2002
+++ b/Documentation/networking/ip-sysctl.txt	Fri Oct 11 21:22:56 2002
@@ -185,7 +185,7 @@
 	
 tcp_max_syn_backlog - INTEGER
 	Maximal number of remembered connection requests, which are
-	still did not receive an acknowledgement from connecting client.
+	still did not receive an acknowledgment from connecting client.
 	Default value is 1024 for systems with more than 128Mb of memory,
 	and 128 for low memory machines. If server suffers of overload,
 	try to increase this number.
diff -Nru a/Documentation/rpc-cache.txt b/Documentation/rpc-cache.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/rpc-cache.txt	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,171 @@
+This document gives a brief introduction to the caching
+mechanisms in the sunrpc layer that is used, in particular,
+for NFS authentication.
+
+CACHES
+======
+The caching replaces the old exports table and allows for
+a wide variety of values to be caches.
+
+There are a number of caches that are similar in structure though
+quite possibly very different in content and use.  There is a corpus
+of common code for managing these caches.
+
+Examples of caches that are likely to be needed are:
+  - mapping from IP address to client name
+  - mapping from client name and filesystem to export options
+  - mapping from UID to list of GIDs, to work around NFS's limitation
+    of 16 gids.
+  - mappings between local UID/GID and remote UID/GID for sites that
+    do not have uniform uid assignment
+  - mapping from network identify to public key for crypto authentication.
+
+The common code handles such things as:
+   - general cache lookup with correct locking
+   - supporting 'NEGATIVE' as well as positive entries
+   - allowing an EXPIRED time on cache items, and removing
+     items after they expire, and are no longe in-use.
+
+   Future code extensions are expect to handle
+   - making requests to user-space to fill in cache entries
+   - allowing user-space to directly set entries in the cache
+   - delaying RPC requests that depend on as-yet incomplete
+     cache entries, and replaying those requests when the cache entry
+     is complete.
+   - maintaining last-access times on cache entries
+   - clean out old entries when the caches become full
+
+The code for performing a cache lookup is also common, but in the form
+of a template.  i.e. a #define.
+Each cache defines a lookup function by using the DefineCacheLookup
+macro, or the simpler DefineSimpleCacheLookup macro
+
+Creating a Cache
+----------------
+
+1/ A cache needs a datum to cache.  This is in the form of a
+   structure definition that must contain a
+     struct cache_head
+   as an element, usually the first.
+   It will also contain a key and some content.
+   Each cache element is reference counted and contains
+   expiry and update times for use in cache management.
+2/ A cache needs a "cache_detail" structure that
+   describes the cache.  This stores the hash table, and some
+   parameters for cache management.
+3/ A cache needs a lookup function.  This is created using
+   the DefineCacheLookup macro.  This lookup function is used both
+   to find entries and to update entries.  The normal mode for
+   updating an entry is to replace the old entry with a new
+   entry.  However it is possible to allow update-in-place
+   for those caches where it makes sense (no atomicity issues
+   or indirect reference counting issue)
+4/ A cache needs to be registered using cache_register().  This
+   includes in on a list of caches that will be regularly
+   cleaned to discard old data.  For this to work, some
+   thread must periodically call cache_clean
+   
+Using a cache
+-------------
+
+To find a value in a cache, call the lookup function passing it a the
+datum which contains key, and possibly content, and a flag saying
+whether to update the cache with new data from the datum.   Depending
+on how the cache lookup function was defined, it may take an extra
+argument to identify the particular cache in question.
+
+Except in cases of kmalloc failure, the lookup function
+will return a new datum which will store the key and
+may contain valid content, or may not.
+This datum is typically passed to cache_check which determines the
+validity of the datum and may later initiate an upcall to fill
+in the data.
+
+cache_check can be passed a "struct cache_req *".  This structure is
+typically embedded in the actual request and can be used to create a
+deferred copy of the request (struct cache_deferred_req).  This is
+done when the found cache item is not uptodate, but the is reason to
+believe that userspace might provide information soon.  When the cache
+item does become valid, the deferred copy of the request will be
+revisited (->revisit).  It is expected that this method will
+reschedule the request for processing.
+
+
+Populating a cache
+------------------
+
+Each cache has a name, and when the cache is registered, a directory
+with that name is created in /proc/net/rpc
+
+This directory contains a file called 'channel' which is a channel
+for communicating between kernel and user for populating the cache.
+This directory may later contain other files of interacting
+with the cache.
+
+The 'channel' works a bit like a datagram socket. Each 'write' is
+passed as a whole to the cache for parsing and interpretation.
+Each cache can treat the write requests differently, but it is
+expected that a message written will contain:
+  - a key
+  - an expiry time
+  - a content.
+with the intention that an item in the cache with the give key
+should be create or updated to have the given content, and the
+expiry time should be set on that item.
+
+Reading from a channel is a bit more interesting.  When a cache
+lookup fail, or when it suceeds but finds an entry that may soon
+expiry, a request is lodged for that cache item to be updated by
+user-space.  These requests appear in the channel file.
+
+Successive reads will return successive requests.
+If there are no more requests to return, read will return EOF, but a
+select or poll for read will block waiting for another request to be
+added.
+
+Thus a user-space helper is likely to:
+  open the channel.
+    select for readable
+    read a request
+    write a response
+  loop.
+
+If it dies and needs to be restarted, any requests that have not be
+answered will still appear in the file and will be read by the new
+instance of the helper.
+
+Each cache should define a "cache_parse" method which takes a message
+written from user-space and processes it.  It should return an error
+(which propagates back to the write syscall) or 0.
+
+Each cache should also define a "cache_request" method which
+takes a cache item and encodes a request into the buffer
+provided.
+
+
+Note: If a cache has no active readers on the channel, and has had not
+active readers for more than 60 seconds, further requests will not be
+added to the channel but instead all looks that do not find a valid
+entry will fail.  This is partly for backward compatability: The
+previous nfs exports table was deemed to be authoritative and a
+failed lookup meant a definate 'no'.
+
+request/response format
+-----------------------
+
+While each cache is free to use it's own format for requests
+and responses over channel, the following is recommended are
+appropriate and support routines are available to help:
+Each request or response record should be printable ASCII
+with precisely one newline character which should be at the end.
+Fields within the record should be separated by spaces, normally one.
+If spaces, newlines, or nul characters are needed in a field they
+much be quotes.  two mechanisms are available:
+1/ If a field begins '\x' then it must contain an even number of
+   hex digits, and pairs of these digits provide the bytes in the
+   field.
+2/ otherwise a \ in the field must be followed by 3 octal digits
+   which give the code for a byte.  Other characters are treated
+   as them selves.  At the very least, space, newlines nul, and
+   '\' must be quoted in this way.
+   
diff -Nru a/Documentation/s390/3270.ChangeLog b/Documentation/s390/3270.ChangeLog
--- a/Documentation/s390/3270.ChangeLog	Fri Oct 11 21:22:52 2002
+++ b/Documentation/s390/3270.ChangeLog	Fri Oct 11 21:22:52 2002
@@ -1,5 +1,34 @@
 ChangeLog for the UTS Global 3270-support patch
 
+Sep 2002:	Get bootup colors right on 3270 console
+	* In tubttybld.c, substantially revise ESC processing so that
+	  ESC sequences (especially coloring ones) and the strings
+	  they affect work as right as 3270 can get them.  Also, set
+	  screen height to omit the two rows used for input area, in
+	  tty3270_open() in tubtty.c.
+
+Sep 2002:	Dynamically get 3270 input buffer
+	* Oversize 3270 screen widths may exceed GEOM_MAXINPLEN columns,
+	  so get input-area buffer dynamically when sizing the device in
+	  tubmakemin() in tuball.c (if it's the console) or tty3270_open()
+	  in tubtty.c (if needed).  Change tubp->tty_input to be a
+	  pointer rather than an array, in tubio.h.
+
+Sep 2002:	Fix tubfs kmalloc()s
+	* Do read and write lengths correctly in fs3270_read()
+	  and fs3270_write(), whilst never asking kmalloc()
+	  for more than 0x800 bytes.  Affects tubfs.c and tubio.h.
+
+Sep 2002:	Recognize 3270 control unit type 3174
+	* Recognize control-unit type 0x3174 as well as 0x327?.
+	  The IBM 2047 device emulates a 3174 control unit.
+	  Modularize control-unit recognition in tuball.c by
+	  adding and invoking new tub3270_is_ours().
+
+Apr 2002:	Fix 3270 console reboot loop
+	* (Belated log entry) Fixed reboot loop if 3270 console,
+	  in tubtty.c:ttu3270_bh().
+
 Feb 6, 2001:
 	* This changelog is new
 	* tub3270 now supports 3270 console:
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Fri Oct 11 21:23:00 2002
+++ b/MAINTAINERS	Fri Oct 11 21:23:00 2002
@@ -738,7 +738,7 @@
 
 IBM ServeRAID RAID DRIVER
 P:	Jack Hammer
-P:	Dave Jeffrey	
+P:	Dave Jeffery
 M:	ipslinux@adaptec.com
 W:	http://www.developer.ibm.com/welcome/netfinity/serveraid.html
 S:	Supported 
@@ -929,10 +929,9 @@
 KERNEL NFSD
 P:	Neil Brown
 M:	neilb@cse.unsw.edu.au
-L:	nfs-devel@linux.kernel.org (Linux NFS)
 L:	nfs@lists.sourceforge.net
 W:	http://nfs.sourceforge.net/
-W:	http://www.cse.unsw.edu.au/~neilb/oss/knfsd/
+W:	http://www.cse.unsw.edu.au/~neilb/patches/linux-devel/
 S:	Maintained
 
 LANMEDIA WAN CARD DRIVER
@@ -1720,7 +1719,7 @@
 W:	http://www.suse.cz/development/input/
 S:	Maintained
 
-USB HUB
+USB HUB DRIVER
 P:	Johannes Erdfelt
 M:	johannes@erdfelt.com
 L:	linux-usb-users@lists.sourceforge.net
@@ -1863,13 +1862,12 @@
 S:	Supported
 
 USB UHCI DRIVER
-P:	Georg Acher
-M:	usb@in.tum.de
+P:	Johannes Erdfelt
+M:	johannes@erdfelt.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
-W:	http://usb.in.tum.de
 S:	Maintained
-	
+
 USB "USBNET" DRIVER
 P:	David Brownell
 M:	dbrownell@users.sourceforge.net
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Fri Oct 11 21:22:53 2002
+++ b/Makefile	Fri Oct 11 21:22:53 2002
@@ -1,12 +1,12 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 41
+SUBLEVEL = 42
 EXTRAVERSION =
 
 # *DOCUMENTATION*
-# Too see a list of typical targets execute "make help"
+# To see a list of typical targets execute "make help"
 # More info can be located in ./Documentation/kbuild
-# Comments in this file is targeted only to the developer, do not
+# Comments in this file are targeted only to the developer, do not
 # expect to learn how to build the kernel reading this file.
 
 # We are using a recursive build, so we need to do a little thinking
@@ -142,7 +142,7 @@
 STRIP		= $(CROSS_COMPILE)strip
 OBJCOPY		= $(CROSS_COMPILE)objcopy
 OBJDUMP		= $(CROSS_COMPILE)objdump
-MAKEFILES	= $(TOPDIR)/.config
+MAKEFILES	= .config
 GENKSYMS	= /sbin/genksyms
 DEPMOD		= /sbin/depmod
 KALLSYMS	= /sbin/kallsyms
@@ -387,17 +387,17 @@
 # Single targets
 # ---------------------------------------------------------------------------
 
-%.s: %.c FORCE
+%.s: %.c scripts FORCE
 	+@$(call descend,$(@D),$@)
-%.i: %.c FORCE
+%.i: %.c scripts FORCE
 	+@$(call descend,$(@D),$@)
-%.o: %.c FORCE
+%.o: %.c scripts FORCE
 	+@$(call descend,$(@D),$@)
-%.lst: %.c FORCE
+%.lst: %.c scripts FORCE
 	+@$(call descend,$(@D),$@)
-%.s: %.S FORCE
+%.s: %.S scripts FORCE
 	+@$(call descend,$(@D),$@)
-%.o: %.S FORCE
+%.o: %.S scripts FORCE
 	+@$(call descend,$(@D),$@)
 
 # 	FIXME: The asm symlink changes when $(ARCH) changes. That's
@@ -704,6 +704,8 @@
 	sound/oss/pndspini.c \
 	drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \
 	.version .config* config.in config.old \
+	scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \
+	scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
 	.menuconfig.log \
 	include/asm \
 	.hdepend include/linux/modversions.h \
@@ -881,7 +883,7 @@
 	@set -e; \
 	$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))';) \
 	$(cmd_$(1)); \
-	$(TOPDIR)/scripts/fixdep $(depfile) $@ $(TOPDIR) '$(cmd_$(1))' > $(@D)/.$(@F).tmp; \
+	scripts/fixdep $(depfile) $@ '$(cmd_$(1))' > $(@D)/.$(@F).tmp; \
 	rm -f $(depfile); \
 	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
 
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Fri Oct 11 21:22:55 2002
+++ b/Rules.make	Fri Oct 11 21:22:55 2002
@@ -209,10 +209,10 @@
 	$(if $($(quiet)cmd_cc_ver_c),echo '  $($(quiet)cmd_cc_ver_c)';) \
 	$(cmd_cc_ver_c); \
 	if [ ! -r $(depfile) ]; then exit 1; fi; \
-	$(TOPDIR)/scripts/fixdep $(depfile) $@ $(TOPDIR) '$(cmd_cc_ver_c)' > $(@D)/.$(@F).tmp; \
+	scripts/fixdep $(depfile) $@ '$(cmd_cc_ver_c)' > $(@D)/.$(@F).tmp; \
 	rm -f $(depfile); \
 	if [ ! -r $@ ] || cmp -s $@ $@.tmp; then \
-	  touch $(TOPDIR)/include/linux/modversions.h; \
+	  touch include/linux/modversions.h; \
 	fi; \
 	mv -f $@.tmp $@
 	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd
@@ -312,7 +312,7 @@
 	$(call if_changed_dep,cc_o_c)
 
 quiet_cmd_cc_lst_c = MKLST   $(echo_target)
-cmd_cc_lst_c       = $(CC) $(c_flags) -g -c -o $*.o $< && $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) > $@
+cmd_cc_lst_c       = $(CC) $(c_flags) -g -c -o $*.o $< && sh scripts/makelst $*.o System.map $(OBJDUMP) > $@
 
 %.lst: %.c FORCE
 	$(call if_changed_dep,cc_lst_c)
@@ -561,7 +561,7 @@
 	@set -e; \
 	$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))';) \
 	$(cmd_$(1)); \
-	$(TOPDIR)/scripts/fixdep $(depfile) $@ $(TOPDIR) '$(cmd_$(1))' > $(@D)/.$(@F).tmp; \
+	scripts/fixdep $(depfile) $@ '$(cmd_$(1))' > $(@D)/.$(@F).tmp; \
 	rm -f $(depfile); \
 	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
 
diff -Nru a/arch/alpha/Config.help b/arch/alpha/Config.help
--- a/arch/alpha/Config.help	Fri Oct 11 21:22:53 2002
+++ b/arch/alpha/Config.help	Fri Oct 11 21:22:53 2002
@@ -251,6 +251,10 @@
 CONFIG_ALPHA_GAMMA
   Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx.
 
+CONFIG_ALPHA_EV67
+  Is this a machine based on the EV67 core?  If in doubt, select N here
+  and the machine will be treated as an EV6.
+
 CONFIG_ALPHA_SRM
   There are two different types of booting firmware on Alphas: SRM,
   which is command line driven, and ARC, which uses menus and arrow
@@ -609,4 +613,15 @@
   and certain other kinds of spinlock errors commonly made.  This is
   best used in conjunction with the NMI watchdog so that spinlock
   deadlocks are also debuggable.
+
+CONFIG_DEBUG_RWLOCK
+  If you say Y here then read-write lock processing will count how many
+  times it has tried to get the lock and issue an error message after
+  too many attempts.  If you suspect a rwlock problem or a kernel
+  hacker asks for this option then say Y.  Otherwise say N.
+
+CONFIG_DEBUG_SEMAPHORE
+  If you say Y here then semaphore processing will issue lots of
+  verbose debugging messages.  If you suspect a semaphore problem or a
+  kernel hacker asks for this option then say Y.  Otherwise say N.
 
diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile
--- a/arch/alpha/Makefile	Fri Oct 11 21:23:00 2002
+++ b/arch/alpha/Makefile	Fri Oct 11 21:23:00 2002
@@ -99,30 +99,32 @@
 
 MAKEBOOT = $(MAKE) -C arch/alpha/boot
 
-rawboot:
+rawboot:	vmlinux
 	@$(MAKEBOOT) rawboot
 
+boot:	vmlinux
+	@$(MAKEBOOT)
+
 #
 # My boot writes directly to a specific disk partition, I doubt most
 # people will want to do that without changes..
 #
-msb my-special-boot:
+msb my-special-boot:	vmlinux
 	@$(MAKEBOOT) msb
 
-bootimage:
+bootimage:	vmlinux
 	@$(MAKEBOOT) bootimage
 
-srmboot:
+srmboot:	vmlinux
 	@$(MAKEBOOT) srmboot
 
 archclean:
-	@$(MAKE) -C arch/alpha/kernel clean
 	@$(MAKEBOOT) clean
 
 archmrproper:
 	rm -f include/asm-alpha/asm_offsets.h
 
-bootpfile:
+bootpfile:	vmlinux
 	@$(MAKEBOOT) bootpfile
 
 
diff -Nru a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
--- a/arch/alpha/boot/Makefile	Fri Oct 11 21:22:54 2002
+++ b/arch/alpha/boot/Makefile	Fri Oct 11 21:22:54 2002
@@ -8,7 +8,9 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-LINKFLAGS = -static -T bootloader.lds #-N -relax
+LINKFLAGS = -static -T bootloader.lds -uvsprintf #-N -relax
+
+CFLAGS := $(CFLAGS) -I$(TOPDIR)/include
 
 .S.s:
 	$(CPP) $(AFLAGS) -traditional -o $*.o $<
diff -Nru a/arch/alpha/config.in b/arch/alpha/config.in
--- a/arch/alpha/config.in	Fri Oct 11 21:22:54 2002
+++ b/arch/alpha/config.in	Fri Oct 11 21:22:54 2002
@@ -233,6 +233,7 @@
 
 if [ "$CONFIG_SMP" = "y" ]; then
    define_bool CONFIG_HAVE_DEC_LOCK y
+   int  'Maximum number of CPUs (2-64)' CONFIG_NR_CPUS 64
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -Nru a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
--- a/arch/alpha/kernel/Makefile	Fri Oct 11 21:22:56 2002
+++ b/arch/alpha/kernel/Makefile	Fri Oct 11 21:22:56 2002
@@ -8,8 +8,9 @@
 
 export-objs := alpha_ksyms.o
 
-obj-y    := entry.o traps.o process.o init_task.o osf_sys.o irq.o irq_alpha.o \
-	    signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o
+obj-y    := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
+	    irq_alpha.o signal.o setup.o ptrace.o time.o semaphore.o \
+	    alpha_ksyms.o systbls.o
 
 #
 # FIXME!
diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
--- a/arch/alpha/kernel/alpha_ksyms.c	Fri Oct 11 21:22:53 2002
+++ b/arch/alpha/kernel/alpha_ksyms.c	Fri Oct 11 21:22:53 2002
@@ -161,7 +161,6 @@
 EXPORT_SYMBOL(sys_lseek);
 EXPORT_SYMBOL(__kernel_execve);
 EXPORT_SYMBOL(sys_setsid);
-EXPORT_SYMBOL(sys_sync);
 EXPORT_SYMBOL(sys_wait4);
 
 /* Networking helper routines. */
diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
--- a/arch/alpha/kernel/entry.S	Fri Oct 11 21:22:50 2002
+++ b/arch/alpha/kernel/entry.S	Fri Oct 11 21:22:50 2002
@@ -9,8 +9,7 @@
 #include <asm/cache.h>
 #include <asm/asm_offsets.h>
 #include <asm/thread_info.h>
-
-#define NR_SYSCALLS 381
+#include <asm/unistd.h>
 
 /*
  * stack offsets
@@ -677,6 +676,7 @@
 .end entSys
 
 .align 3
+.globl sys_sigreturn
 .ent sys_sigreturn
 sys_sigreturn:
 	mov	$30,$17
@@ -688,6 +688,7 @@
 .end sys_sigreturn
 
 .align 3
+.globl sys_rt_sigreturn
 .ent sys_rt_sigreturn
 sys_rt_sigreturn:
 	mov	$30,$17
@@ -699,6 +700,7 @@
 .end sys_rt_sigreturn
 
 .align 3
+.globl sys_sigsuspend
 .ent sys_sigsuspend
 sys_sigsuspend:
 	mov	$30,$17
@@ -713,6 +715,7 @@
 .end sys_sigsuspend
 
 .align 3
+.globl sys_rt_sigsuspend
 .ent sys_rt_sigsuspend
 sys_rt_sigsuspend:
 	mov	$30,$18
@@ -725,421 +728,3 @@
 	lda	$30,SWITCH_STACK_SIZE+16($30)
 	ret	$31,($26),1
 .end sys_rt_sigsuspend
-
-	.data
-	.align 3
-	.globl sys_call_table
-sys_call_table:
-	.quad alpha_ni_syscall			/* 0 */
-	.quad sys_exit
-	.quad sys_fork
-	.quad sys_read
-	.quad sys_write
-	.quad alpha_ni_syscall			/* 5 */
-	.quad sys_close
-	.quad osf_wait4
-	.quad alpha_ni_syscall
-	.quad sys_link
-	.quad sys_unlink			/* 10 */
-	.quad alpha_ni_syscall
-	.quad sys_chdir
-	.quad sys_fchdir
-	.quad sys_mknod
-	.quad sys_chmod				/* 15 */
-	.quad sys_chown
-	.quad osf_brk
-	.quad alpha_ni_syscall
-	.quad sys_lseek
-	.quad sys_getxpid			/* 20 */
-	.quad osf_mount
-	.quad sys_umount
-	.quad sys_setuid
-	.quad sys_getxuid
-	.quad alpha_ni_syscall			/* 25 */
-	.quad sys_ptrace
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 30 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad sys_access
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 35 */
-	.quad sys_sync
-	.quad sys_kill
-	.quad alpha_ni_syscall
-	.quad sys_setpgid
-	.quad alpha_ni_syscall			/* 40 */
-	.quad sys_dup
-	.quad sys_pipe
-	.quad osf_set_program_attributes
-	.quad alpha_ni_syscall
-	.quad sys_open				/* 45 */
-	.quad alpha_ni_syscall
-	.quad sys_getxgid
-	.quad osf_sigprocmask
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 50 */
-	.quad sys_acct
-	.quad sys_sigpending
-	.quad alpha_ni_syscall
-	.quad sys_ioctl
-	.quad alpha_ni_syscall			/* 55 */
-	.quad alpha_ni_syscall
-	.quad sys_symlink
-	.quad sys_readlink
-	.quad sys_execve
-	.quad sys_umask				/* 60 */
-	.quad sys_chroot
-	.quad alpha_ni_syscall
-	.quad sys_getpgrp
-	.quad sys_getpagesize
-	.quad alpha_ni_syscall			/* 65 */
-	.quad sys_vfork
-	.quad sys_newstat
-	.quad sys_newlstat
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 70 */
-	.quad osf_mmap
-	.quad alpha_ni_syscall
-	.quad sys_munmap
-	.quad sys_mprotect
-	.quad sys_madvise			/* 75 */
-	.quad sys_vhangup
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad sys_getgroups
-	/* map BSD's setpgrp to sys_setpgid for binary compatibility: */
-	.quad sys_setgroups			/* 80 */
-	.quad alpha_ni_syscall
-	.quad sys_setpgid
-	.quad osf_setitimer
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 85 */
-	.quad osf_getitimer
-	.quad sys_gethostname
-	.quad sys_sethostname
-	.quad sys_getdtablesize
-	.quad sys_dup2				/* 90 */
-	.quad sys_newfstat
-	.quad sys_fcntl
-	.quad osf_select
-	.quad sys_poll
-	.quad sys_fsync				/* 95 */
-	.quad sys_setpriority
-	.quad sys_socket
-	.quad sys_connect
-	.quad sys_accept
-	.quad osf_getpriority			/* 100 */
-	.quad sys_send
-	.quad sys_recv
-	.quad sys_sigreturn
-	.quad sys_bind
-	.quad sys_setsockopt			/* 105 */
-	.quad sys_listen
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 110 */
-	.quad sys_sigsuspend
-	.quad osf_sigstack
-	.quad sys_recvmsg
-	.quad sys_sendmsg
-	.quad alpha_ni_syscall			/* 115 */
-	.quad osf_gettimeofday
-	.quad osf_getrusage
-	.quad sys_getsockopt
-	.quad alpha_ni_syscall
-#ifdef CONFIG_OSF4_COMPAT
-	.quad osf_readv				/* 120 */
-	.quad osf_writev
-#else
-	.quad sys_readv				/* 120 */
-	.quad sys_writev
-#endif
-	.quad osf_settimeofday
-	.quad sys_fchown
-	.quad sys_fchmod
-	.quad sys_recvfrom			/* 125 */
-	.quad sys_setreuid
-	.quad sys_setregid
-	.quad sys_rename
-	.quad sys_truncate
-	.quad sys_ftruncate			/* 130 */
-	.quad sys_flock
-	.quad sys_setgid
-	.quad sys_sendto
-	.quad sys_shutdown
-	.quad sys_socketpair			/* 135 */
-	.quad sys_mkdir
-	.quad sys_rmdir
-	.quad osf_utimes
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 140 */
-	.quad sys_getpeername
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad sys_getrlimit
-	.quad sys_setrlimit			/* 145 */
-	.quad alpha_ni_syscall
-	.quad sys_setsid
-	.quad sys_quotactl
-	.quad alpha_ni_syscall
-	.quad sys_getsockname			/* 150 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 155 */
-	.quad osf_sigaction
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad osf_getdirentries
-	.quad osf_statfs			/* 160 */
-	.quad osf_fstatfs
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad osf_getdomainname			/* 165 */
-	.quad sys_setdomainname
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 170 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 175 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 180 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 185 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 190 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 195 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad osf_swapon
-	.quad sys_msgctl			/* 200 */
-	.quad sys_msgget
-	.quad sys_msgrcv
-	.quad sys_msgsnd
-	.quad sys_semctl
-	.quad sys_semget			/* 205 */
-	.quad sys_semop
-	.quad osf_utsname
-	.quad sys_lchown
-	.quad osf_shmat
-	.quad sys_shmctl			/* 210 */
-	.quad sys_shmdt
-	.quad sys_shmget
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 215 */
-	.quad alpha_ni_syscall
-	.quad sys_msync
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 220 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 225 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 230 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad sys_getpgid
-	.quad sys_getsid
-	.quad sys_sigaltstack			/* 235 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 240 */
-	.quad osf_sysinfo
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad osf_proplist_syscall
-	.quad alpha_ni_syscall			/* 245 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 250 */
-	.quad osf_usleep_thread
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad sys_sysfs
-	.quad alpha_ni_syscall			/* 255 */
-	.quad osf_getsysinfo
-	.quad osf_setsysinfo
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 260 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 265 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 270 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 275 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 280 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 285 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 290 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall			/* 295 */
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-/* linux-specific system calls start at 300 */
-	.quad sys_bdflush			/* 300 */
-	.quad sys_sethae
-	.quad sys_mount
-	.quad sys_old_adjtimex
-	.quad sys_swapoff
-	.quad sys_getdents			/* 305 */
-	.quad alpha_create_module
-	.quad sys_init_module
-	.quad sys_delete_module
-	.quad sys_get_kernel_syms
-	.quad sys_syslog			/* 310 */
-	.quad sys_reboot
-	.quad sys_clone
-	.quad sys_uselib
-	.quad sys_mlock
-	.quad sys_munlock			/* 315 */
-	.quad sys_mlockall
-	.quad sys_munlockall
-	.quad sys_sysinfo
-	.quad sys_sysctl
-	.quad sys_ni_syscall			/* 320 */
-	.quad sys_oldumount
-	.quad sys_swapon
-	.quad sys_times
-	.quad sys_personality
-	.quad sys_setfsuid			/* 325 */
-	.quad sys_setfsgid
-	.quad sys_ustat
-	.quad sys_statfs
-	.quad sys_fstatfs
-	.quad sys_sched_setparam		/* 330 */
-	.quad sys_sched_getparam
-	.quad sys_sched_setscheduler
-	.quad sys_sched_getscheduler
-	.quad sys_sched_yield
-	.quad sys_sched_get_priority_max	/* 335 */
-	.quad sys_sched_get_priority_min
-	.quad sys_sched_rr_get_interval
-	.quad sys_ni_syscall			/* sys_afs_syscall */
-	.quad sys_newuname
-	.quad sys_nanosleep			/* 340 */
-	.quad sys_mremap
-	.quad sys_nfsservctl
-	.quad sys_setresuid
-	.quad sys_getresuid
-	.quad sys_pciconfig_read		/* 345 */
-	.quad sys_pciconfig_write
-	.quad sys_query_module
-	.quad sys_prctl
-	.quad sys_pread64
-	.quad sys_pwrite64			/* 350 */
-	.quad sys_rt_sigreturn
-	.quad sys_rt_sigaction
-	.quad sys_rt_sigprocmask
-	.quad sys_rt_sigpending
-	.quad sys_rt_sigtimedwait		/* 355 */
-	.quad sys_rt_sigqueueinfo
-	.quad sys_rt_sigsuspend
-	.quad sys_select
-	.quad sys_gettimeofday
-	.quad sys_settimeofday			/* 360 */
-	.quad sys_getitimer
-	.quad sys_setitimer
-	.quad sys_utimes
-	.quad sys_getrusage
-	.quad sys_wait4				/* 365 */
-	.quad sys_adjtimex
-	.quad sys_getcwd
-	.quad sys_capget
-	.quad sys_capset
-	.quad sys_sendfile			/* 370 */
-	.quad sys_setresgid
-	.quad sys_getresgid
-	.quad sys_ni_syscall			/* sys_dipc */
-	.quad sys_pivot_root
-	.quad sys_mincore			/* 375 */
-	.quad sys_pciconfig_iobase
-	.quad sys_getdents64
-	.quad sys_gettid
-	.quad sys_readahead
-	.quad sys_ni_syscall			/* 380, sys_security */
-	.quad sys_tkill
-	.quad sys_setxattr
-	.quad sys_lsetxattr
-	.quad sys_fsetxattr
-	.quad sys_getxattr
-	.quad sys_lgetxattr
-	.quad sys_fgetxattr
-	.quad sys_listxattr
-	.quad sys_llistxattr
-	.quad sys_flistxattr			/* 390 */
-	.quad sys_removexattr
-	.quad sys_lremovexattr
-	.quad sys_fremovexattr
-	.quad sys_futex
-	.quad sys_sched_setaffinity
-	.quad sys_sched_getaffinity
-	.quad sys_ni_syscall			/* 397, tux */
-	.quad sys_io_setup
-	.quad sys_io_destroy
-	.quad sys_io_getevents			/* 400 */
-	.quad sys_io_submit
-	.quad sys_io_cancel
-	.quad sys_ni_syscall			/* 403, sys_alloc_hugepages */
-	.quad sys_ni_syscall			/* 404, sys_free_hugepages */
-	.quad sys_exit_group
diff -Nru a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
--- a/arch/alpha/kernel/osf_sys.c	Fri Oct 11 21:22:50 2002
+++ b/arch/alpha/kernel/osf_sys.c	Fri Oct 11 21:22:50 2002
@@ -44,8 +44,9 @@
 #include <asm/processor.h>
 
 extern int do_pipe(int *);
-
 extern asmlinkage unsigned long sys_brk(unsigned long);
+extern int sys_getpriority(int, int);
+extern asmlinkage unsigned long sys_create_module(char *, unsigned long);
 
 /*
  * Brk needs to return an error.  Still support Linux's brk(0) query idiom,
@@ -53,7 +54,8 @@
  * identical to OSF as we don't return 0 on success, but doing otherwise
  * would require changes to libc.  Hopefully this is good enough.
  */
-asmlinkage unsigned long osf_brk(unsigned long brk)
+asmlinkage unsigned long
+osf_brk(unsigned long brk)
 {
 	unsigned long retval = sys_brk(brk);
 	if (brk && brk != retval)
@@ -64,9 +66,9 @@
 /*
  * This is pure guess-work..
  */
-asmlinkage int osf_set_program_attributes(
-	unsigned long text_start, unsigned long text_len,
-	unsigned long bss_start, unsigned long bss_len)
+asmlinkage int
+osf_set_program_attributes(unsigned long text_start, unsigned long text_len,
+			   unsigned long bss_start, unsigned long bss_len)
 {
 	struct mm_struct *mm;
 
@@ -106,8 +108,9 @@
 	int error;
 };
 
-static int osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
-		       ino_t ino, unsigned int d_type)
+static int
+osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
+	    ino_t ino, unsigned int d_type)
 {
 	struct osf_dirent *dirent;
 	struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
@@ -134,8 +137,9 @@
 	return 0;
 }
 
-asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
-				 unsigned int count, long *basep)
+asmlinkage int
+osf_getdirentries(unsigned int fd, struct osf_dirent *dirent,
+		  unsigned int count, long *basep)
 {
 	int error;
 	struct file *file;
@@ -159,9 +163,9 @@
 	if (count != buf.count)
 		error = count - buf.count;
 
-out_putf:
+ out_putf:
 	fput(file);
-out:
+ out:
 	return error;
 }
 
@@ -172,8 +176,9 @@
  * Alpha syscall convention has no problem returning negative
  * values:
  */
-asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4,
-			       int a5, struct pt_regs regs)
+asmlinkage int
+osf_getpriority(int which, int who,
+		int a2, int a3, int a4, int a5, struct pt_regs regs)
 {
 	extern int sys_getpriority(int, int);
 	int prio;
@@ -194,24 +199,24 @@
 /*
  * No need to acquire the kernel lock, we're local..
  */
-asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4,
-				     int a5, struct pt_regs regs)
+asmlinkage unsigned long
+sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
 {
 	struct task_struct * tsk = current;
 	(&regs)->r20 = tsk->euid;
 	return tsk->uid;
 }
 
-asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4,
-				     int a5, struct pt_regs regs)
+asmlinkage unsigned long
+sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
 {
 	struct task_struct * tsk = current;
 	(&regs)->r20 = tsk->egid;
 	return tsk->gid;
 }
 
-asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4,
-				     int a5, struct pt_regs regs)
+asmlinkage unsigned long
+sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
 {
 	struct task_struct *tsk = current;
 
@@ -226,9 +231,9 @@
 	return tsk->tgid;
 }
 
-asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
-	       unsigned long prot, unsigned long flags, unsigned long fd,
-				  unsigned long off)
+asmlinkage unsigned long
+osf_mmap(unsigned long addr, unsigned long len, unsigned long prot,
+         unsigned long flags, unsigned long fd, unsigned long off)
 {
 	struct file *file = NULL;
 	unsigned long ret = -EBADF;
@@ -249,7 +254,7 @@
 	up_write(&current->mm->mmap_sem);
 	if (file)
 		fput(file);
-out:
+ out:
 	return ret;
 }
 
@@ -271,7 +276,9 @@
 	__kernel_fsid_t f_fsid;
 } *osf_stat;
 
-static int linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat, unsigned long bufsiz)
+static int
+linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat,
+		    unsigned long bufsiz)
 {
 	struct osf_statfs tmp_stat;
 
@@ -291,7 +298,9 @@
 	return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
 }
 
-static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz)
+static int
+do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer,
+	      unsigned long bufsiz)
 {
 	struct statfs linux_stat;
 	int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat);
@@ -300,7 +309,8 @@
 	return error;	
 }
 
-asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long bufsiz)
+asmlinkage int
+osf_statfs(char *path, struct osf_statfs *buffer, unsigned long bufsiz)
 {
 	struct nameidata nd;
 	int retval;
@@ -313,7 +323,8 @@
 	return retval;
 }
 
-asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
+asmlinkage int
+osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
 {
 	struct file *file;
 	int retval;
@@ -342,10 +353,9 @@
 	char *devname;
 	int flags;
 	uid_t exroot;
-/*
- * This has lots more here, which Linux handles with the option block
- * but I'm too lazy to do the translation into ASCII.
- */
+
+	/* This has lots more here, which Linux handles with the option block
+	   but I'm too lazy to do the translation into ASCII.  */
 };
 
 struct procfs_args {
@@ -362,7 +372,8 @@
  * Just how long ago was it written? OTOH our UFS driver may be still
  * unhappy with OSF UFS. [CHECKME]
  */
-static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
+static int
+osf_ufs_mount(char *dirname, struct ufs_args *args, int flags)
 {
 	int retval;
 	struct cdfs_args tmp;
@@ -377,11 +388,12 @@
 		goto out;
 	retval = do_mount(devname, dirname, "ext2", flags, NULL);
 	putname(devname);
-out:
+ out:
 	return retval;
 }
 
-static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
+static int
+osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags)
 {
 	int retval;
 	struct cdfs_args tmp;
@@ -396,11 +408,12 @@
 		goto out;
 	retval = do_mount(devname, dirname, "iso9660", flags, NULL);
 	putname(devname);
-out:
+ out:
 	return retval;
 }
 
-static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
+static int
+osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
 {
 	struct procfs_args tmp;
 
@@ -410,7 +423,8 @@
 	return do_mount("", dirname, "proc", flags, NULL);
 }
 
-asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
+asmlinkage int
+osf_mount(unsigned long typenr, char *path, int flag, void *data)
 {
 	int retval = -EINVAL;
 	char *name;
@@ -435,12 +449,13 @@
 		printk("osf_mount(%ld, %x)\n", typenr, flag);
 	}
 	putname(name);
-out:
+ out:
 	unlock_kernel();
 	return retval;
 }
 
-asmlinkage int osf_utsname(char *name)
+asmlinkage int
+osf_utsname(char *name)
 {
 	int error;
 
@@ -458,12 +473,13 @@
 		goto out;
 
 	error = 0;
-out:
+ out:
 	up_read(&uts_sem);	
 	return error;
 }
 
-asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat)
+asmlinkage int
+osf_swapon(const char *path, int flags, int lowat, int hiwat)
 {
 	int ret;
 
@@ -474,35 +490,36 @@
 	return ret;
 }
 
-asmlinkage unsigned long sys_getpagesize(void)
+asmlinkage unsigned long
+sys_getpagesize(void)
 {
 	return PAGE_SIZE;
 }
 
-asmlinkage unsigned long sys_getdtablesize(void)
+asmlinkage unsigned long
+sys_getdtablesize(void)
 {
 	return NR_OPEN;
 }
 
-asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5,
-			struct pt_regs regs)
+asmlinkage int
+sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
 {
-	int fd[2];
-	int error;
+	int fd[2], error;
 
 	error = do_pipe(fd);
-	if (error)
-		goto out;
-	(&regs)->r20 = fd[1];
-	error = fd[0];
-out:
+	if (!error) {
+		regs.r20 = fd[1];
+		error = fd[0];
+	}
 	return error;
 }
 
 /*
  * For compatibility with OSF/1 only.  Use utsname(2) instead.
  */
-asmlinkage int osf_getdomainname(char *name, int namelen)
+asmlinkage int
+osf_getdomainname(char *name, int namelen)
 {
 	unsigned len;
 	int i, error;
@@ -522,12 +539,12 @@
 			break;
 	}
 	up_read(&uts_sem);
-out:
+ out:
 	return error;
 }
 
-
-asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg)
+asmlinkage long
+osf_shmat(int shmid, void *shmaddr, int shmflg)
 {
 	unsigned long raddr;
 	long err;
@@ -541,7 +558,7 @@
 	 * non-negative longs!
 	 */
 	err = raddr;
-out:
+ out:
 	unlock_kernel();
 	return err;
 }
@@ -612,7 +629,8 @@
 	PL_DEL = 5, PL_FDEL = 6
 };
 
-asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args)
+asmlinkage long
+osf_proplist_syscall(enum pl_code code, union pl_args *args)
 {
 	long error;
 	int *min_buf_size_ptr;
@@ -655,7 +673,8 @@
 	return error;
 }
 
-asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
+asmlinkage int
+osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
 {
 	unsigned long usp = rdusp();
 	unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size;
@@ -691,7 +710,7 @@
 	}
 
 	error = 0;
-out:
+ out:
 	return error;
 }
 
@@ -702,32 +721,28 @@
  * create_module() because it's one of the few system calls
  * that return kernel addresses (which are negative).
  */
-asmlinkage unsigned long alpha_create_module(char *module_name, unsigned long size,
-					  int a3, int a4, int a5, int a6,
-					     struct pt_regs regs)
+
+asmlinkage unsigned long
+alpha_create_module(char *module_name, unsigned long size,
+		    int a3, int a4, int a5, int a6, struct pt_regs regs)
 {
-	asmlinkage unsigned long sys_create_module(char *, unsigned long);
 	long retval;
 
 	lock_kernel();
 	retval = sys_create_module(module_name, size);
-	/*
-	 * we get either a module address or an error number,
-	 * and we know the error number is a small negative
-	 * number, while the address is always negative but
-	 * much larger.
-	 */
-	if (retval + 1000 > 0)
-		goto out;
 
-	/* tell entry.S:syscall_error that this is NOT an error: */
-	regs.r0 = 0;
-out:
-	unlock_kernel();
+	/* We get either a module address or an error number, and we know
+	   the error number is a small negative number, while the address
+	   is always negative but much larger.  */
+	if (retval + 1000 < 0)
+		regs.r0 = 0;
+
+        unlock_kernel();
 	return retval;
 }
 
-asmlinkage long osf_sysinfo(int command, char *buf, long count)
+asmlinkage long
+osf_sysinfo(int command, char *buf, long count)
 {
 	static char * sysinfo_table[] = {
 		system_utsname.sysname,
@@ -761,13 +776,13 @@
 	else
 		err = 0;
 	up_read(&uts_sem);
-out:
+ out:
 	return err;
 }
 
-asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
-					unsigned long nbytes,
-					int *start, void *arg)
+asmlinkage unsigned long
+osf_getsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
+	       int *start, void *arg)
 {
 	unsigned long w;
 	struct percpu_struct *cpu;
@@ -823,9 +838,9 @@
 	return -EOPNOTSUPP;
 }
 
-asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
-					unsigned long nbytes,
-					int *start, void *arg)
+asmlinkage unsigned long
+osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
+	       int *start, void *arg)
 {
 	switch (op) {
 	case SSI_IEEE_FP_CONTROL: {
@@ -925,21 +940,24 @@
     struct timeval32 it_value;
 };
 
-static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+static inline long
+get_tv32(struct timeval *o, struct timeval32 *i)
 {
 	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 		(__get_user(o->tv_sec, &i->tv_sec) |
 		 __get_user(o->tv_usec, &i->tv_usec)));
 }
 
-static inline long put_tv32(struct timeval32 *o, struct timeval *i)
+static inline long
+put_tv32(struct timeval32 *o, struct timeval *i)
 {
 	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 		(__put_user(i->tv_sec, &o->tv_sec) |
 		 __put_user(i->tv_usec, &o->tv_usec)));
 }
 
-static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
+static inline long
+get_it32(struct itimerval *o, struct itimerval32 *i)
 {
 	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 		(__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
@@ -948,7 +966,8 @@
 		 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
 }
 
-static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+static inline long
+put_it32(struct itimerval32 *o, struct itimerval *i)
 {
 	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 		(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
@@ -964,7 +983,8 @@
 	value->tv_sec = jiffies / HZ;
 }
 
-asmlinkage int osf_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+asmlinkage int
+osf_gettimeofday(struct timeval32 *tv, struct timezone *tz)
 {
 	if (tv) {
 		struct timeval ktv;
@@ -979,7 +999,8 @@
 	return 0;
 }
 
-asmlinkage int osf_settimeofday(struct timeval32 *tv, struct timezone *tz)
+asmlinkage int
+osf_settimeofday(struct timeval32 *tv, struct timezone *tz)
 {
 	struct timeval ktv;
 	struct timezone ktz;
@@ -996,7 +1017,8 @@
 	return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
 }
 
-asmlinkage int osf_getitimer(int which, struct itimerval32 *it)
+asmlinkage int
+osf_getitimer(int which, struct itimerval32 *it)
 {
 	struct itimerval kit;
 	int error;
@@ -1008,8 +1030,8 @@
 	return error;
 }
 
-asmlinkage int osf_setitimer(int which, struct itimerval32 *in,
-			     struct itimerval32 *out)
+asmlinkage int
+osf_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out)
 {
 	struct itimerval kin, kout;
 	int error;
@@ -1031,7 +1053,8 @@
 
 }
 
-asmlinkage int osf_utimes(const char *filename, struct timeval32 *tvs)
+asmlinkage int
+osf_utimes(const char *filename, struct timeval32 *tvs)
 {
 	char *kfilename;
 	struct timeval ktvs[2];
@@ -1136,9 +1159,9 @@
 	set_fd_set(n, outp->fds_bits, fds.res_out);
 	set_fd_set(n, exp->fds_bits, fds.res_ex);
 
-out:
+ out:
 	kfree(bits);
-out_nofds:
+ out_nofds:
 	return ret;
 }
 
@@ -1161,7 +1184,8 @@
 	long	ru_nivcsw;		/* involuntary " */
 };
 
-asmlinkage int osf_getrusage(int who, struct rusage32 *ru)
+asmlinkage int
+osf_getrusage(int who, struct rusage32 *ru)
 {
 	struct rusage32 r;
 
@@ -1198,8 +1222,8 @@
 	return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
 }
 
-asmlinkage int osf_wait4(pid_t pid, int *ustatus, int options,
-			 struct rusage32 *ur)
+asmlinkage int
+osf_wait4(pid_t pid, int *ustatus, int options, struct rusage32 *ur)
 {
 	if (!ur) {
 		return sys_wait4(pid, ustatus, options, NULL);
@@ -1245,7 +1269,8 @@
  * seems to be a timeval pointer, and I suspect the second
  * one is the time remaining.. Ho humm.. No documentation.
  */
-asmlinkage int osf_usleep_thread(struct timeval32 *sleep, struct timeval32 *remain)
+asmlinkage int
+osf_usleep_thread(struct timeval32 *sleep, struct timeval32 *remain)
 {
 	struct timeval tmp;
 	unsigned long ticks;
@@ -1268,7 +1293,7 @@
 	}
 	
 	return 0;
-fault:
+ fault:
 	return -EFAULT;
 }
 
@@ -1302,7 +1327,8 @@
 	int  :32; int  :32; int  :32; int  :32;
 };
 
-asmlinkage int sys_old_adjtimex(struct timex32 *txc_p)
+asmlinkage int
+sys_old_adjtimex(struct timex32 *txc_p)
 {
         struct timex txc;
 	int ret;
diff -Nru a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
--- a/arch/alpha/kernel/process.c	Fri Oct 11 21:22:55 2002
+++ b/arch/alpha/kernel/process.c	Fri Oct 11 21:22:55 2002
@@ -191,26 +191,13 @@
 	common_shutdown(LINUX_REBOOT_CMD_POWER_OFF, NULL);
 }
 
+/* Used by sysrq-p, among others.  I don't believe r9-r15 are ever
+   saved in the context it's used.  */
+
 void
-show_regs(struct pt_regs * regs)
+show_regs(struct pt_regs *regs)
 {
-	printk("\n");
-	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
-	printk("ps: %04lx pc: [<%016lx>] CPU %d    %s\n",
-	       regs->ps, regs->pc, smp_processor_id(), print_tainted());
-	printk("rp: [<%016lx>] sp: %p\n", regs->r26, regs+1);
-	printk(" r0: %016lx  r1: %016lx  r2: %016lx  r3: %016lx\n",
-	       regs->r0, regs->r1, regs->r2, regs->r3);
-	printk(" r4: %016lx  r5: %016lx  r6: %016lx  r7: %016lx\n",
-	       regs->r4, regs->r5, regs->r6, regs->r7);
-	printk(" r8: %016lx r16: %016lx r17: %016lx r18: %016lx\n",
-	       regs->r8, regs->r16, regs->r17, regs->r18);
-	printk("r19: %016lx r20: %016lx r21: %016lx r22: %016lx\n",
-	       regs->r19, regs->r20, regs->r21, regs->r22);
-	printk("r23: %016lx r24: %016lx r25: %016lx r26: %016lx\n",
-	       regs->r23, regs->r24, regs->r25, regs->r26);
-	printk("r27: %016lx r28: %016lx r29: %016lx hae: %016lx\n",
-	       regs->r27, regs->r28, regs->gp, regs->hae);
+	dik_show_regs(regs, 0);
 }
 
 /*
diff -Nru a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
--- a/arch/alpha/kernel/setup.c	Fri Oct 11 21:22:54 2002
+++ b/arch/alpha/kernel/setup.c	Fri Oct 11 21:22:54 2002
@@ -37,6 +37,11 @@
 #include <linux/blk.h>
 #endif
 
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#include <linux/reboot.h>
+#endif
+
 #include <linux/notifier.h>
 extern struct notifier_block *panic_notifier_list;
 static int alpha_panic_event(struct notifier_block *, unsigned long, void *);
@@ -538,6 +543,15 @@
 	if (alpha_using_srm && srmcons_output) {
 		register_srm_console();
 	}
+
+#ifdef CONFIG_MAGIC_SYSRQ
+	/* If we're using SRM, make sysrq-b halt back to the prom,
+	   not auto-reboot.  */
+	if (alpha_using_srm) {
+		struct sysrq_key_op *op = __sysrq_get_key_op('b');
+		op->handler = (void *) machine_halt;
+	}
+#endif
 
 	/*
 	 * Indentify and reconfigure for the current system.
diff -Nru a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/alpha/kernel/systbls.S	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,433 @@
+/*
+ * arch/alpha/kernel/systbls.S
+ *
+ * The system call table. 
+ */
+
+#include <asm/unistd.h>
+
+	.data
+	.align 3
+	.globl sys_call_table
+sys_call_table:
+	.quad alpha_ni_syscall			/* 0 */
+	.quad sys_exit
+	.quad sys_fork
+	.quad sys_read
+	.quad sys_write
+	.quad alpha_ni_syscall			/* 5 */
+	.quad sys_close
+	.quad osf_wait4
+	.quad alpha_ni_syscall
+	.quad sys_link
+	.quad sys_unlink			/* 10 */
+	.quad alpha_ni_syscall
+	.quad sys_chdir
+	.quad sys_fchdir
+	.quad sys_mknod
+	.quad sys_chmod				/* 15 */
+	.quad sys_chown
+	.quad osf_brk
+	.quad alpha_ni_syscall
+	.quad sys_lseek
+	.quad sys_getxpid			/* 20 */
+	.quad osf_mount
+	.quad sys_umount
+	.quad sys_setuid
+	.quad sys_getxuid
+	.quad alpha_ni_syscall			/* 25 */
+	.quad sys_ptrace
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 30 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad sys_access
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 35 */
+	.quad sys_sync
+	.quad sys_kill
+	.quad alpha_ni_syscall
+	.quad sys_setpgid
+	.quad alpha_ni_syscall			/* 40 */
+	.quad sys_dup
+	.quad sys_pipe
+	.quad osf_set_program_attributes
+	.quad alpha_ni_syscall
+	.quad sys_open				/* 45 */
+	.quad alpha_ni_syscall
+	.quad sys_getxgid
+	.quad osf_sigprocmask
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 50 */
+	.quad sys_acct
+	.quad sys_sigpending
+	.quad alpha_ni_syscall
+	.quad sys_ioctl
+	.quad alpha_ni_syscall			/* 55 */
+	.quad alpha_ni_syscall
+	.quad sys_symlink
+	.quad sys_readlink
+	.quad sys_execve
+	.quad sys_umask				/* 60 */
+	.quad sys_chroot
+	.quad alpha_ni_syscall
+	.quad sys_getpgrp
+	.quad sys_getpagesize
+	.quad alpha_ni_syscall			/* 65 */
+	.quad sys_vfork
+	.quad sys_newstat
+	.quad sys_newlstat
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 70 */
+	.quad osf_mmap
+	.quad alpha_ni_syscall
+	.quad sys_munmap
+	.quad sys_mprotect
+	.quad sys_madvise			/* 75 */
+	.quad sys_vhangup
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad sys_getgroups
+	/* map BSD's setpgrp to sys_setpgid for binary compatibility: */
+	.quad sys_setgroups			/* 80 */
+	.quad alpha_ni_syscall
+	.quad sys_setpgid
+	.quad osf_setitimer
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 85 */
+	.quad osf_getitimer
+	.quad sys_gethostname
+	.quad sys_sethostname
+	.quad sys_getdtablesize
+	.quad sys_dup2				/* 90 */
+	.quad sys_newfstat
+	.quad sys_fcntl
+	.quad osf_select
+	.quad sys_poll
+	.quad sys_fsync				/* 95 */
+	.quad sys_setpriority
+	.quad sys_socket
+	.quad sys_connect
+	.quad sys_accept
+	.quad osf_getpriority			/* 100 */
+	.quad sys_send
+	.quad sys_recv
+	.quad sys_sigreturn
+	.quad sys_bind
+	.quad sys_setsockopt			/* 105 */
+	.quad sys_listen
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 110 */
+	.quad sys_sigsuspend
+	.quad osf_sigstack
+	.quad sys_recvmsg
+	.quad sys_sendmsg
+	.quad alpha_ni_syscall			/* 115 */
+	.quad osf_gettimeofday
+	.quad osf_getrusage
+	.quad sys_getsockopt
+	.quad alpha_ni_syscall
+#ifdef CONFIG_OSF4_COMPAT
+	.quad osf_readv				/* 120 */
+	.quad osf_writev
+#else
+	.quad sys_readv				/* 120 */
+	.quad sys_writev
+#endif
+	.quad osf_settimeofday
+	.quad sys_fchown
+	.quad sys_fchmod
+	.quad sys_recvfrom			/* 125 */
+	.quad sys_setreuid
+	.quad sys_setregid
+	.quad sys_rename
+	.quad sys_truncate
+	.quad sys_ftruncate			/* 130 */
+	.quad sys_flock
+	.quad sys_setgid
+	.quad sys_sendto
+	.quad sys_shutdown
+	.quad sys_socketpair			/* 135 */
+	.quad sys_mkdir
+	.quad sys_rmdir
+	.quad osf_utimes
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 140 */
+	.quad sys_getpeername
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad sys_getrlimit
+	.quad sys_setrlimit			/* 145 */
+	.quad alpha_ni_syscall
+	.quad sys_setsid
+	.quad sys_quotactl
+	.quad alpha_ni_syscall
+	.quad sys_getsockname			/* 150 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 155 */
+	.quad osf_sigaction
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad osf_getdirentries
+	.quad osf_statfs			/* 160 */
+	.quad osf_fstatfs
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad osf_getdomainname			/* 165 */
+	.quad sys_setdomainname
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 170 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 175 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 180 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 185 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 190 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 195 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad osf_swapon
+	.quad sys_msgctl			/* 200 */
+	.quad sys_msgget
+	.quad sys_msgrcv
+	.quad sys_msgsnd
+	.quad sys_semctl
+	.quad sys_semget			/* 205 */
+	.quad sys_semop
+	.quad osf_utsname
+	.quad sys_lchown
+	.quad osf_shmat
+	.quad sys_shmctl			/* 210 */
+	.quad sys_shmdt
+	.quad sys_shmget
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 215 */
+	.quad alpha_ni_syscall
+	.quad sys_msync
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 220 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 225 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 230 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad sys_getpgid
+	.quad sys_getsid
+	.quad sys_sigaltstack			/* 235 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 240 */
+	.quad osf_sysinfo
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad osf_proplist_syscall
+	.quad alpha_ni_syscall			/* 245 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 250 */
+	.quad osf_usleep_thread
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad sys_sysfs
+	.quad alpha_ni_syscall			/* 255 */
+	.quad osf_getsysinfo
+	.quad osf_setsysinfo
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 260 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 265 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 270 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 275 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 280 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 285 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 290 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall			/* 295 */
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+	.quad alpha_ni_syscall
+/* linux-specific system calls start at 300 */
+	.quad sys_bdflush			/* 300 */
+	.quad sys_sethae
+	.quad sys_mount
+	.quad sys_old_adjtimex
+	.quad sys_swapoff
+	.quad sys_getdents			/* 305 */
+	.quad alpha_create_module
+	.quad sys_init_module
+	.quad sys_delete_module
+	.quad sys_get_kernel_syms
+	.quad sys_syslog			/* 310 */
+	.quad sys_reboot
+	.quad sys_clone
+	.quad sys_uselib
+	.quad sys_mlock
+	.quad sys_munlock			/* 315 */
+	.quad sys_mlockall
+	.quad sys_munlockall
+	.quad sys_sysinfo
+	.quad sys_sysctl
+	.quad sys_ni_syscall			/* 320 */
+	.quad sys_oldumount
+	.quad sys_swapon
+	.quad sys_times
+	.quad sys_personality
+	.quad sys_setfsuid			/* 325 */
+	.quad sys_setfsgid
+	.quad sys_ustat
+	.quad sys_statfs
+	.quad sys_fstatfs
+	.quad sys_sched_setparam		/* 330 */
+	.quad sys_sched_getparam
+	.quad sys_sched_setscheduler
+	.quad sys_sched_getscheduler
+	.quad sys_sched_yield
+	.quad sys_sched_get_priority_max	/* 335 */
+	.quad sys_sched_get_priority_min
+	.quad sys_sched_rr_get_interval
+	.quad sys_ni_syscall			/* sys_afs_syscall */
+	.quad sys_newuname
+	.quad sys_nanosleep			/* 340 */
+	.quad sys_mremap
+	.quad sys_nfsservctl
+	.quad sys_setresuid
+	.quad sys_getresuid
+	.quad sys_pciconfig_read		/* 345 */
+	.quad sys_pciconfig_write
+	.quad sys_query_module
+	.quad sys_prctl
+	.quad sys_pread64
+	.quad sys_pwrite64			/* 350 */
+	.quad sys_rt_sigreturn
+	.quad sys_rt_sigaction
+	.quad sys_rt_sigprocmask
+	.quad sys_rt_sigpending
+	.quad sys_rt_sigtimedwait		/* 355 */
+	.quad sys_rt_sigqueueinfo
+	.quad sys_rt_sigsuspend
+	.quad sys_select
+	.quad sys_gettimeofday
+	.quad sys_settimeofday			/* 360 */
+	.quad sys_getitimer
+	.quad sys_setitimer
+	.quad sys_utimes
+	.quad sys_getrusage
+	.quad sys_wait4				/* 365 */
+	.quad sys_adjtimex
+	.quad sys_getcwd
+	.quad sys_capget
+	.quad sys_capset
+	.quad sys_sendfile			/* 370 */
+	.quad sys_setresgid
+	.quad sys_getresgid
+	.quad sys_ni_syscall			/* sys_dipc */
+	.quad sys_pivot_root
+	.quad sys_mincore			/* 375 */
+	.quad sys_pciconfig_iobase
+	.quad sys_getdents64
+	.quad sys_gettid
+	.quad sys_readahead
+	.quad sys_ni_syscall			/* 380, sys_security */
+	.quad sys_tkill
+	.quad sys_setxattr
+	.quad sys_lsetxattr
+	.quad sys_fsetxattr
+	.quad sys_getxattr			/* 385 */
+	.quad sys_lgetxattr
+	.quad sys_fgetxattr
+	.quad sys_listxattr
+	.quad sys_llistxattr
+	.quad sys_flistxattr			/* 390 */
+	.quad sys_removexattr
+	.quad sys_lremovexattr
+	.quad sys_fremovexattr
+	.quad sys_futex
+	.quad sys_sched_setaffinity		/* 395 */
+	.quad sys_sched_getaffinity
+	.quad sys_ni_syscall			/* 397, tux */
+	.quad sys_io_setup
+	.quad sys_io_destroy
+	.quad sys_io_getevents			/* 400 */
+	.quad sys_io_submit
+	.quad sys_io_cancel
+	.quad sys_ni_syscall			/* 403, sys_alloc_hugepages */
+	.quad sys_ni_syscall			/* 404, sys_free_hugepages */
+	.quad sys_exit_group
+
+	.size sys_call_table, . - sys_call_table
+	.type sys_call_table, @object
+
+/* Remember to update everything, kids.  */
+.ifne (. - sys_call_table) - (NR_SYSCALLS * 8)
+.err
+.endif
diff -Nru a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile
--- a/arch/alpha/lib/Makefile	Fri Oct 11 21:23:04 2002
+++ b/arch/alpha/lib/Makefile	Fri Oct 11 21:23:04 2002
@@ -51,14 +51,16 @@
 
 include $(TOPDIR)/Rules.make
 
-__divqu.o: $(ev6)divide.S
-	$(CC) $(AFLAGS) -DDIV -c -o __divqu.o $(ev6)divide.S
+$(obj)/__divqu.o: $(obj)/$(ev6)divide.S
+	$(CC) $(AFLAGS) -DDIV -c -o $(obj)/__divqu.o $(obj)/$(ev6)divide.S
 
-__remqu.o: $(ev6)divide.S
-	$(CC) $(AFLAGS) -DREM -c -o __remqu.o $(ev6)divide.S
+$(obj)/__remqu.o: $(obj)/$(ev6)divide.S
+	$(CC) $(AFLAGS) -DREM -c -o $(obj)/__remqu.o $(obj)/$(ev6)divide.S
 
-__divlu.o: $(ev6)divide.S
-	$(CC) $(AFLAGS) -DDIV -DINTSIZE -c -o __divlu.o $(ev6)divide.S
+$(obj)/__divlu.o: $(obj)/$(ev6)divide.S
+	$(CC) $(AFLAGS) -DDIV -DINTSIZE \
+		-c -o $(obj)/__divlu.o $(obj)/$(ev6)divide.S
 
-__remlu.o: $(ev6)divide.S
-	$(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o $(ev6)divide.S
+$(obj)/__remlu.o: $(obj)/$(ev6)divide.S
+	$(CC) $(AFLAGS) -DREM -DINTSIZE \
+		-c -o $(obj)/__remlu.o $(obj)/$(ev6)divide.S
diff -Nru a/arch/alpha/lib/dbg_stackcheck.S b/arch/alpha/lib/dbg_stackcheck.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/alpha/lib/dbg_stackcheck.S	Fri Oct 11 21:23:05 2002
@@ -0,0 +1,27 @@
+/*
+ * arch/alpha/lib/stackcheck.S
+ * Contributed by Richard Henderson (rth@tamu.edu)
+ *
+ * Verify that we have not overflowed the stack.  Oops if we have.
+ */
+
+#include <asm/asm_offsets.h>
+
+	.text
+	.set noat
+
+	.align 3
+	.globl _mcount
+	.ent _mcount
+_mcount:
+	.frame $30, 0, $28, 0
+	.prologue 0
+
+	lda	$0, TASK_SIZE($8)
+	cmpult	$30, $0, $0
+	bne	$0, 1f
+	ret	($28)
+1:	stq	$31, -8($31)	# oops me, damn it.
+	br	1b
+
+	.end _mcount
diff -Nru a/arch/alpha/lib/dbg_stackkill.S b/arch/alpha/lib/dbg_stackkill.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/alpha/lib/dbg_stackkill.S	Fri Oct 11 21:22:50 2002
@@ -0,0 +1,35 @@
+/*
+ * arch/alpha/lib/killstack.S
+ * Contributed by Richard Henderson (rth@cygnus.com)
+ *
+ * Clobber the balance of the kernel stack, hoping to catch
+ * uninitialized local variables in the act.
+ */
+
+#include <asm/asm_offsets.h>
+
+	.text
+	.set noat
+
+	.align 5
+	.globl _mcount
+	.ent _mcount
+_mcount:
+	.frame $30, 0, $28, 0
+	.prologue 0
+
+	ldi	$0, 0xdeadbeef
+	lda	$2, -STACK_SIZE
+	sll	$0, 32, $1
+	and	$30, $2, $2
+	or	$0, $1, $0
+	lda	$2, TASK_SIZE($2)
+	cmpult	$2, $30, $1
+	beq	$1, 2f
+1:	stq	$0, 0($2)
+	addq	$2, 8, $2
+	cmpult	$2, $30, $1
+	bne	$1, 1b
+2:	ret	($28)
+
+	.end _mcount
diff -Nru a/arch/alpha/lib/stackcheck.S b/arch/alpha/lib/stackcheck.S
--- a/arch/alpha/lib/stackcheck.S	Fri Oct 11 21:23:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,27 +0,0 @@
-/*
- * arch/alpha/lib/stackcheck.S
- * Contributed by Richard Henderson (rth@tamu.edu)
- *
- * Verify that we have not overflowed the stack.  Oops if we have.
- */
-
-#include <asm/asm_offsets.h>
-
-	.text
-	.set noat
-
-	.align 3
-	.globl _mcount
-	.ent _mcount
-_mcount:
-	.frame $30, 0, $28, 0
-	.prologue 0
-
-	lda	$0, TASK_SIZE($8)
-	cmpult	$30, $0, $0
-	bne	$0, 1f
-	ret	($28)
-1:	stq	$31, -8($31)	# oops me, damn it.
-	br	1b
-
-	.end _mcount
diff -Nru a/arch/alpha/lib/stackkill.S b/arch/alpha/lib/stackkill.S
--- a/arch/alpha/lib/stackkill.S	Fri Oct 11 21:22:50 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*
- * arch/alpha/lib/killstack.S
- * Contributed by Richard Henderson (rth@cygnus.com)
- *
- * Clobber the balance of the kernel stack, hoping to catch
- * uninitialized local variables in the act.
- */
-
-#include <asm/asm_offsets.h>
-
-	.text
-	.set noat
-
-	.align 5
-	.globl _mcount
-	.ent _mcount
-_mcount:
-	.frame $30, 0, $28, 0
-	.prologue 0
-
-	ldi	$0, 0xdeadbeef
-	lda	$2, -STACK_SIZE
-	sll	$0, 32, $1
-	and	$30, $2, $2
-	or	$0, $1, $0
-	lda	$2, TASK_SIZE($2)
-	cmpult	$2, $30, $1
-	beq	$1, 2f
-1:	stq	$0, 0($2)
-	addq	$2, 8, $2
-	cmpult	$2, $30, $1
-	bne	$1, 1b
-2:	ret	($28)
-
-	.end _mcount
diff -Nru a/arch/alpha/lib/stxncpy.S b/arch/alpha/lib/stxncpy.S
--- a/arch/alpha/lib/stxncpy.S	Fri Oct 11 21:23:04 2002
+++ b/arch/alpha/lib/stxncpy.S	Fri Oct 11 21:23:04 2002
@@ -278,7 +278,7 @@
 	extqh	t2, a1, t0	# e0    : extract low bits for last word
 	or	t1, t0, t1	# e1    :
 
-1:	cmpbge	zero, t1, t7
+1:	cmpbge	zero, t1, t8
 	mov	t1, t0
 
 $u_eocfin:			# end-of-count, final word
diff -Nru a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
--- a/arch/alpha/mm/fault.c	Fri Oct 11 21:22:55 2002
+++ b/arch/alpha/mm/fault.c	Fri Oct 11 21:22:55 2002
@@ -125,11 +125,10 @@
 		goto bad_area;
 	if (expand_stack(vma, address))
 		goto bad_area;
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
+
+	/* Ok, we have a good vm_area for this memory access, so
+	   we can handle it.  */
+ good_area:
 	if (cause < 0) {
 		if (!(vma->vm_flags & VM_EXEC))
 			goto bad_area;
@@ -143,11 +142,9 @@
 	}
 
  survive:
-	/*
-	 * If for any reason at all we couldn't handle the fault,
-	 * make sure we exit gracefully rather than endlessly redo
-	 * the fault.
-	 */
+	/* If for any reason at all we couldn't handle the fault,
+	   make sure we exit gracefully rather than endlessly redo
+	   the fault.  */
 	fault = handle_mm_fault(mm, vma, address, cause > 0);
 	up_read(&mm->mmap_sem);
 
@@ -155,14 +152,11 @@
 		goto out_of_memory;
 	if (fault == 0)
 		goto do_sigbus;
-
 	return;
 
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
+	/* Something tried to access memory that isn't in our memory map.
+	   Fix it, but check if it's kernel or user first.  */
+ bad_area:
 	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
@@ -170,7 +164,7 @@
 		return;
 	}
 
-no_context:
+ no_context:
 	/* Are we prepared to handle this fault as an exception?  */
 	if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) {
 		unsigned long newpc;
@@ -183,20 +177,16 @@
 		return;
 	}
 
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
+	/* Oops. The kernel tried to access some bad page. We'll have to
+	   terminate things with extreme prejudice.  */
 	printk(KERN_ALERT "Unable to handle kernel paging request at "
 	       "virtual address %016lx\n", address);
 	die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16);
 	do_exit(SIGKILL);
 
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
+	/* We ran out of memory, or some other thing happened to us that
+	   made us unable to handle the page fault gracefully.  */
+ out_of_memory:
 	if (current->pid == 1) {
 		yield();
 		down_read(&mm->mmap_sem);
@@ -208,18 +198,16 @@
 		goto no_context;
 	do_exit(SIGKILL);
 
-do_sigbus:
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel
-	 * or user mode.
-	 */
+ do_sigbus:
+	/* Send a sigbus, regardless of whether we were in kernel
+	   or user mode.  */
 	force_sig(SIGBUS, current);
 	if (!user_mode(regs))
 		goto no_context;
 	return;
 
 #ifdef CONFIG_ALPHA_LARGE_VMALLOC
-vmalloc_fault:
+ vmalloc_fault:
 	if (user_mode(regs)) {
 		force_sig(SIGSEGV, current);
 		return;
diff -Nru a/arch/alpha/vmlinux.lds.S b/arch/alpha/vmlinux.lds.S
--- a/arch/alpha/vmlinux.lds.S	Fri Oct 11 21:22:59 2002
+++ b/arch/alpha/vmlinux.lds.S	Fri Oct 11 21:22:59 2002
@@ -58,10 +58,11 @@
 	__initcall_end = .;
   }
 
-  . = ALIGN(64);
-  __per_cpu_start = .;
-  .data.percpu  : { *(.data.percpu) }
-  __per_cpu_end = .;
+  .data.percpu ALIGN(64): {
+	__per_cpu_start = .;
+	*(.data.percpu)
+	__per_cpu_end = .;
+  }
 
   /* The initial task and kernel stack */
   .data.init_thread ALIGN(2*8192) : {
diff -Nru a/arch/arm/mach-footbridge/mm.c b/arch/arm/mach-footbridge/mm.c
--- a/arch/arm/mach-footbridge/mm.c	Fri Oct 11 21:23:02 2002
+++ b/arch/arm/mach-footbridge/mm.c	Fri Oct 11 21:23:02 2002
@@ -80,7 +80,7 @@
 /*
  * These two functions convert virtual addresses to PCI addresses and PCI
  * addresses to virtual addresses.  Note that it is only legal to use these
- * on memory obtained via get_free_page or kmalloc.
+ * on memory obtained via get_zeroed_page or kmalloc.
  */
 unsigned long __virt_to_bus(unsigned long res)
 {
diff -Nru a/arch/cris/mm/init.c b/arch/cris/mm/init.c
--- a/arch/cris/mm/init.c	Fri Oct 11 21:22:58 2002
+++ b/arch/cris/mm/init.c	Fri Oct 11 21:22:58 2002
@@ -345,8 +345,8 @@
 	 * mem_map page array.
 	 */
 
-	free_area_init_node(0, 0, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
-
+	free_area_init_node(0, &contig_page_data, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0);
+	mem_map = contig_page_data.node_mem_map;
 }
 
 extern unsigned long loops_per_jiffy; /* init/main.c */
diff -Nru a/arch/i386/Config.help b/arch/i386/Config.help
--- a/arch/i386/Config.help	Fri Oct 11 21:22:53 2002
+++ b/arch/i386/Config.help	Fri Oct 11 21:22:53 2002
@@ -34,6 +34,14 @@
 
   Otherwise, say N.
 
+CONFIG_NR_CPUS
+  This allows you to specify the maximum number of CPUs which this
+  kernel will support.  The maximum supported value is 32 and the
+  minimum value which makes sense is 2.
+
+  This is purely to save memory - each supported CPU adds
+  approximately eight kilobytes to the kernel image.
+
 CONFIG_PREEMPT
   This option reduces the latency of the kernel when reacting to
   real-time or interactive events by allowing a low priority process to
@@ -57,6 +65,14 @@
   You will need a new lynxer.elf file to flash your firmware with - send
   email to Martin.Bligh@us.ibm.com
 
+CONFIG_X86_CYCLONE
+  This patch used the Cyclone performance counter on IBM x440, x360,
+  and other Summit based systems for calculating gettimeofday. This 
+  fixes problems resulting from TSC skew found in multi-CEC system. 
+
+  If you are suffering from time skew using a multi-CEC system, say YES.
+  Otherwise it is safe to say NO.
+
 CONFIG_X86_UP_IOAPIC
   An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
   SMP-capable replacement for PC-style interrupt controllers. Most
@@ -425,7 +441,7 @@
    - "Winchip-C6" for original IDT Winchip.
    - "Winchip-2" for IDT Winchip 2.
    - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
-   - "CyrixIII" for VIA Cyrix III or VIA C3.
+   - "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
 
   If you don't know what to do, choose "386".
 
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/Makefile	Fri Oct 11 21:22:55 2002
@@ -52,7 +52,8 @@
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
-core-y					+= arch/i386/kernel/ arch/i386/mm/ \
+core-y					+= arch/i386/kernel/ \
+					   arch/i386/mm/ \
 					   arch/i386/$(MACHINE)/
 drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
 drivers-$(CONFIG_PCI)			+= arch/i386/pci/
diff -Nru a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
--- a/arch/i386/boot/compressed/misc.c	Fri Oct 11 21:23:00 2002
+++ b/arch/i386/boot/compressed/misc.c	Fri Oct 11 21:23:00 2002
@@ -120,7 +120,7 @@
 static int vidport;
 static int lines, cols;
 
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_X86_NUMAQ
 static void * xquad_portio = NULL;
 #endif
 
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/config.in	Fri Oct 11 21:22:55 2002
@@ -5,7 +5,6 @@
 mainmenu_name "Linux Kernel Configuration"
 
 define_bool CONFIG_X86 y
-define_bool CONFIG_ISA y
 define_bool CONFIG_SBUS n
 
 define_bool CONFIG_UID16 y
@@ -31,7 +30,7 @@
 	 Winchip-C6				CONFIG_MWINCHIPC6 \
 	 Winchip-2				CONFIG_MWINCHIP2 \
 	 Winchip-2A/Winchip-3			CONFIG_MWINCHIP3D \
-	 CyrixIII/C3				CONFIG_MCYRIXIII" Pentium-Pro
+	 CyrixIII/VIA-C3			CONFIG_MCYRIXIII" Pentium-Pro
 #
 # Define implied options from the CPU selection here
 #
@@ -168,12 +167,13 @@
       define_bool CONFIG_X86_IO_APIC y
    fi
 else
+  int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
   bool 'Multi-node NUMA system support' CONFIG_X86_NUMA
   if [ "$CONFIG_X86_NUMA" = "y" ]; then
      #Platform Choices
      bool 'Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ
      if [ "$CONFIG_X86_NUMAQ" = "y" ]; then
-        define_bool CONFIG_MULTIQUAD y
+        define_bool CONFIG_CLUSTERED_APIC y
      fi
      # Common NUMA Features
      if [ "$CONFIG_X86_NUMAQ" = "y" ]; then
@@ -297,7 +297,8 @@
 
 source drivers/pci/Config.in
 
-bool 'EISA support' CONFIG_EISA
+bool 'ISA support' CONFIG_ISA
+dep_bool 'EISA support' CONFIG_EISA $CONFIG_ISA
 
 if [ "$CONFIG_VISWS" != "y" ]; then
    bool 'MCA support' CONFIG_MCA
@@ -361,14 +362,16 @@
 fi
 endmenu
 
-mainmenu_option next_comment
-comment 'Old non-SCSI/ATAPI CD-ROM drives'
-
-bool 'Support non-SCSI/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
-if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-   source drivers/cdrom/Config.in
+if [ "$CONFIG_ISA" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+
+   bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+   if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+      source drivers/cdrom/Config.in
+   fi
+   endmenu
 fi
-endmenu
 
 source drivers/md/Config.in
 
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Fri Oct 11 21:23:01 2002
+++ b/arch/i386/defconfig	Fri Oct 11 21:23:01 2002
@@ -76,6 +76,7 @@
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 CONFIG_HAVE_DEC_LOCK=y
+CONFIG_NR_CPUS=32
 
 #
 # Power management options (ACPI, APM)
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Fri Oct 11 21:22:54 2002
+++ b/arch/i386/kernel/Makefile	Fri Oct 11 21:22:54 2002
@@ -12,6 +12,7 @@
 		bootflag.o
 
 obj-y				+= cpu/
+obj-y				+= timers/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
--- a/arch/i386/kernel/apic.c	Fri Oct 11 21:23:05 2002
+++ b/arch/i386/kernel/apic.c	Fri Oct 11 21:23:05 2002
@@ -273,7 +273,10 @@
 	value = apic_read(APIC_SPIV);
 	value &= ~APIC_VECTOR_MASK;
 	value |= APIC_SPIV_APIC_ENABLED;
-	value |= APIC_SPIV_FOCUS_DISABLED;
+	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 15))
+		value &= ~APIC_SPIV_FOCUS_DISABLED;
+	else
+		value |= APIC_SPIV_FOCUS_DISABLED;
 	value |= SPURIOUS_APIC_VECTOR;
 	apic_write_around(APIC_SPIV, value);
 
@@ -713,7 +716,15 @@
 		for (i = 0; i < nr_ioapics; i++) {
 			if (smp_found_config) {
 				ioapic_phys = mp_ioapics[i].mpc_apicaddr;
+				if (!ioapic_phys) {
+					printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO/APIC support!\n");
+
+					smp_found_config = 0;
+					skip_ioapic_setup = 1;
+					goto fake_ioapic_page;
+				}
 			} else {
+fake_ioapic_page:
 				ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
 				ioapic_phys = __pa(ioapic_phys);
 			}
@@ -1049,7 +1060,6 @@
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
  */
-unsigned int apic_timer_irqs [NR_CPUS];
 
 void smp_apic_timer_interrupt(struct pt_regs regs)
 {
@@ -1058,7 +1068,7 @@
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
-	apic_timer_irqs[cpu]++;
+	irq_stat[cpu].apic_timer_irqs++;
 
 	/*
 	 * NOTE! We'd better ACK the irq immediately,
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c	Fri Oct 11 21:22:52 2002
+++ b/arch/i386/kernel/apm.c	Fri Oct 11 21:22:52 2002
@@ -571,9 +571,10 @@
 {
 	APM_DECL_SEGS
 	unsigned long		flags;
-	int			cpu = smp_processor_id();
+	int			cpu;
 	struct desc_struct	save_desc_40;
 
+	cpu = get_cpu();
 	save_desc_40 = cpu_gdt_table[cpu][0x40 / 8];
 	cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc;
 
@@ -599,6 +600,7 @@
 	APM_DO_RESTORE_SEGS;
 	local_irq_restore(flags);
 	cpu_gdt_table[cpu][0x40 / 8] = save_desc_40;
+	put_cpu();
 	return *eax & 0xff;
 }
 
@@ -618,12 +620,13 @@
 
 static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
 {
-	u8		error;
+	u8			error;
 	APM_DECL_SEGS
-	unsigned long	flags;
-	int			cpu = smp_processor_id();
+	unsigned long		flags;
+	int			cpu;
 	struct desc_struct	save_desc_40;
 
+	cpu = get_cpu();
 	save_desc_40 = cpu_gdt_table[cpu][0x40 / 8];
 	cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc;
 
@@ -653,6 +656,7 @@
 	APM_DO_RESTORE_SEGS;
 	local_irq_restore(flags);
 	cpu_gdt_table[smp_processor_id()][0x40 / 8] = save_desc_40;
+	put_cpu();
 	return error;
 }
 
@@ -864,7 +868,7 @@
 			case 1: apm_idle_done = 1;
 				break;
 			default: /* BIOS refused */
-				;
+				break;
 			}
 		}
 		if (original_pm_idle)
@@ -880,14 +884,6 @@
 		apm_do_busy();
 }
 
-#ifdef CONFIG_SMP
-static int apm_magic(void * unused)
-{
-	while (1)
-		schedule();
-}
-#endif
-
 /**
  *	apm_power_off	-	ask the BIOS to power off
  *
@@ -915,10 +911,11 @@
 	 */
 #ifdef CONFIG_SMP
 	/* Some bioses don't like being called from CPU != 0 */
-	while (smp_processor_id() != 0) {
-		kernel_thread(apm_magic, NULL,
-			CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+	if (smp_processor_id() != 0) {
+		current->cpus_allowed = 1;
 		schedule();
+		if (unlikely(smp_processor_id() != 0))
+			BUG();
 	}
 #endif
 	if (apm_info.realmode_power_off)
@@ -1688,6 +1685,21 @@
 	current->flags |= PF_IOTHREAD;
 	sigfillset(&current->blocked);
 
+#ifdef CONFIG_SMP
+	/* 2002/08/01 - WT
+	 * This is to avoid random crashes at boot time during initialization
+	 * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D.
+	 * Some bioses don't like being called from CPU != 0.
+	 * Method suggested by Ingo Molnar.
+	 */
+	if (smp_processor_id() != 0) {
+		current->cpus_allowed = 1;
+		schedule();
+		if (unlikely(smp_processor_id() != 0))
+			BUG();
+	}
+#endif
+
 	if (apm_info.connection_version == 0) {
 		apm_info.connection_version = apm_info.bios.version;
 		if (apm_info.connection_version > 0x100) {
@@ -1734,7 +1746,7 @@
 		}
 	}
 
-	if (debug && (num_online_cpus() == 1)) {
+	if (debug) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
@@ -1937,9 +1949,6 @@
 	 * that extends up to the end of page zero (that we have reserved).
 	 * This is for buggy BIOS's that refer to (real mode) segment 0x40
 	 * even though they are called in protected mode.
-	 *
-	 * NOTE: on SMP we call into the APM BIOS only on CPU#0, so it's
-	 * enough to modify CPU#0's GDT.
 	 */
 	set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
 	_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
diff -Nru a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
--- a/arch/i386/kernel/bluesmoke.c	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/kernel/bluesmoke.c	Fri Oct 11 21:22:55 2002
@@ -280,6 +280,7 @@
 	u32 low, high;
 	int i;
 
+	preempt_disable(); 
 	for (i=0; i<banks; i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
 
@@ -294,16 +295,13 @@
 			wmb();
 		}
 	}
+	preempt_enable();
 }
 
 static void do_mce_timer(void *data)
 { 
-	preempt_disable(); 
 	mce_checkregs(NULL);
 	smp_call_function (mce_checkregs, NULL, 1, 1);
-	preempt_enable();
-	mce_timer.expires = jiffies + MCE_RATE;
-	add_timer (&mce_timer);
 } 
 
 static DECLARE_WORK(mce_work, do_mce_timer, NULL);
@@ -311,12 +309,11 @@
 static void mce_timerfunc (unsigned long data)
 {
 #ifdef CONFIG_SMP
-	if (num_online_cpus() > 1) { 
+	if (num_online_cpus() > 1) 
 		schedule_work(&mce_work); 
-		return;
-	}
-#endif
+#else
 	mce_checkregs(NULL);
+#endif
 	mce_timer.expires = jiffies + MCE_RATE;
 	add_timer (&mce_timer);
 }	
diff -Nru a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
--- a/arch/i386/kernel/cpu/amd.c	Fri Oct 11 21:23:04 2002
+++ b/arch/i386/kernel/cpu/amd.c	Fri Oct 11 21:23:04 2002
@@ -141,7 +141,7 @@
 			 * here.
 			 */
 			if (c->x86_model == 6 || c->x86_model == 7) {
-				if (!test_bit(X86_FEATURE_XMM, c->x86_capability)) {
+				if (!cpu_has(c, X86_FEATURE_XMM)) {
 					printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
 					rdmsr(MSR_K7_HWCR, l, h);
 					l &= ~0x00008000;
diff -Nru a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
--- a/arch/i386/kernel/cpu/cyrix.c	Fri Oct 11 21:22:54 2002
+++ b/arch/i386/kernel/cpu/cyrix.c	Fri Oct 11 21:22:54 2002
@@ -2,8 +2,6 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/pci_ids.h>
-
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/processor.h>
diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- a/arch/i386/kernel/cpu/intel.c	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/kernel/cpu/intel.c	Fri Oct 11 21:22:55 2002
@@ -62,8 +62,7 @@
 	
 static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
 {
-	if( test_bit(X86_FEATURE_PN, c->x86_capability) &&
-	    disable_x86_serial_nr ) {
+	if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) {
 		/* Disable processor serial number */
 		unsigned long lo,hi;
 		rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
@@ -95,6 +94,7 @@
 #define LVL_1_DATA	2
 #define LVL_2		3
 #define LVL_3		4
+#define LVL_TRACE	5
 
 struct _cache_table
 {
@@ -114,6 +114,8 @@
 	{ 0x23, LVL_3,      1024 },
 	{ 0x25, LVL_3,      2048 },
 	{ 0x29, LVL_3,      4096 },
+	{ 0x39, LVL_2,      128 },
+	{ 0x3C, LVL_2,      256 },
 	{ 0x41, LVL_2,      128 },
 	{ 0x42, LVL_2,      256 },
 	{ 0x43, LVL_2,      512 },
@@ -122,20 +124,44 @@
 	{ 0x66, LVL_1_DATA, 8 },
 	{ 0x67, LVL_1_DATA, 16 },
 	{ 0x68, LVL_1_DATA, 32 },
+	{ 0x70, LVL_TRACE,  12 },
+	{ 0x71, LVL_TRACE,  16 },
+	{ 0x72, LVL_TRACE,  32 },
 	{ 0x79, LVL_2,      128 },
 	{ 0x7A, LVL_2,      256 },
 	{ 0x7B, LVL_2,      512 },
 	{ 0x7C, LVL_2,      1024 },
 	{ 0x82, LVL_2,      256 },
+	{ 0x83, LVL_2,      512 },
 	{ 0x84, LVL_2,      1024 },
 	{ 0x85, LVL_2,      2048 },
 	{ 0x00, 0, 0}
 };
 
+/*
+ * P4 Xeon errata 037 workaround.
+ * Hardware prefetcher may cause stale data to be loaded into the cache.
+ */
+static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c)
+{
+	unsigned long lo, hi;
+
+	if ((c->x86 == 15) && (c->x86_model == 1) && (c->x86_mask == 1)) {
+		rdmsr (MSR_IA32_MISC_ENABLE, lo, hi);
+		if ((lo & (1<<9)) == 0) {
+			printk (KERN_INFO "CPU: C0 stepping P4 Xeon detected.\n");
+			printk (KERN_INFO "CPU: Disabling hardware prefetching (Errata 037)\n");
+			lo |= (1<<9);	/* Disable hw prefetching */
+			wrmsr (MSR_IA32_MISC_ENABLE, lo, hi);
+		}
+	}
+}
+
+
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
 	char *p = NULL;
-	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+	unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
 
 #ifdef CONFIG_X86_F00F_BUG
 	/*
@@ -196,6 +222,9 @@
 						case LVL_3:
 							l3 += cache_table[k].size;
 							break;
+						case LVL_TRACE:
+							trace += cache_table[k].size;
+							break;
 						}
 
 						break;
@@ -205,9 +234,13 @@
 				}
 			}
 		}
-		if ( l1i || l1d )
-			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
-			      l1i, l1d);
+
+		if ( trace )
+			printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
+		else if ( l1i )
+			printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
+		if ( l1d )
+			printk(", L1 D cache: %dK\n", l1d);
 		if ( l2 )
 			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
 		if ( l3 )
@@ -258,7 +291,7 @@
 		strcpy(c->x86_model_id, p);
 	
 #ifdef CONFIG_X86_HT
-	if (test_bit(X86_FEATURE_HT, c->x86_capability) && !disable_P4_HT) {
+	if (cpu_has(c, X86_FEATURE_HT) && !disable_P4_HT) {
 		extern	int phys_proc_id[NR_CPUS];
 		
 		u32 	eax, ebx, ecx, edx;
@@ -312,8 +345,12 @@
 
 	/* Disable the PN if appropriate */
 	squash_the_stupid_serial_number(c);
+
+	/* Work around errata */
+	Intel_errata_workarounds(c);
 }
 
+
 static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size)
 {
 	/* Intel PIII Tualatin. This comes in two flavours.
@@ -370,7 +407,10 @@
 		},
 		{ X86_VENDOR_INTEL,     15,
 		  {
-			  [1] "Pentium 4 (Unknown)",
+			  [0] "Pentium 4 (Unknown)",
+			  [1] "Pentium 4 (Willamette)",
+			  [2] "Pentium 4 (Northwood)",
+			  [4] "Pentium 4 (Foster)",
 			  [5] "Pentium 4 (Foster)",
 		  }
 		},
diff -Nru a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
--- a/arch/i386/kernel/cpu/proc.c	Fri Oct 11 21:23:03 2002
+++ b/arch/i386/kernel/cpu/proc.c	Fri Oct 11 21:23:03 2002
@@ -66,7 +66,7 @@
 	else
 		seq_printf(m, "stepping\t: unknown\n");
 
-	if ( test_bit(X86_FEATURE_TSC, c->x86_capability) ) {
+	if ( cpu_has(c, X86_FEATURE_TSC) ) {
 		seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n",
 			cpu_khz / 1000, (cpu_khz % 1000));
 	}
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/kernel/dmi_scan.c	Fri Oct 11 21:22:55 2002
@@ -274,6 +274,76 @@
 }
 
 /*
+ * Some machines, usually laptops, can't handle an enabled local APIC.
+ * The symptoms include hangs or reboots when suspending or resuming,
+ * attaching or detaching the power cord, or entering BIOS setup screens
+ * through magic key sequences.
+ */
+static int __init local_apic_kills_bios(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	extern int dont_enable_local_apic;
+	if (!dont_enable_local_apic) {
+		dont_enable_local_apic = 1;
+		printk(KERN_WARNING "%s with broken BIOS detected. "
+		       "Refusing to enable the local APIC.\n",
+		       d->ident);
+	}
+#endif
+	return 0;
+}
+
+/*
+ * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after
+ * resumes, and also at what appears to be asynchronous APM events,
+ * if the local APIC is enabled.
+ */
+static int __init apm_kills_local_apic(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	extern int dont_enable_local_apic;
+	if (apm_info.bios.version && !dont_enable_local_apic) {
+		dont_enable_local_apic = 1;
+		printk(KERN_WARNING "%s with broken BIOS detected. "
+		       "Refusing to enable the local APIC.\n",
+		       d->ident);
+	}
+#endif
+	return 0;
+}
+
+/*
+ * The Intel AL440LX mainboard will hang randomly if the local APIC
+ * timer is running and the APM BIOS hasn't been disabled.
+ */
+static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	extern int dont_use_local_apic_timer;
+	if (apm_info.bios.version && !dont_use_local_apic_timer) {
+		dont_use_local_apic_timer = 1;
+		printk(KERN_WARNING "%s with broken BIOS detected. "
+		       "The local APIC timer will not be used.\n",
+		       d->ident);
+	}
+#endif
+	return 0;
+}
+
+/* 
+ * Don't access SMBus on IBM systems which get corrupted eeproms 
+ */
+
+static __init int disable_smbus(struct dmi_blacklist *d)
+{   
+	if (is_unsafe_smbus == 0) {
+		is_unsafe_smbus = 1;
+		printk(KERN_INFO "%s machine detected. Disabling SMBus accesses.\n", d->ident);
+	}
+	return 0;
+}
+
+/*
  * Work around broken HP Pavilion Notebooks which assign USB to
  * IRQ 9 even though it is actually wired to IRQ 11
  */
@@ -350,6 +420,7 @@
  * The MP1.4 table is right however and so SMP kernels tend to work. 
  */
  
+extern int skip_ioapic_setup;
 static __init int broken_pirq(struct dmi_blacklist *d)
 {
 	printk(KERN_INFO " *** Possibly defective BIOS detected (irqtable)\n");
@@ -357,6 +428,9 @@
 	printk(KERN_INFO " *** If you see IRQ problems, in paticular SCSI resets and hangs at boot\n");
 	printk(KERN_INFO " *** contact your hardware vendor and ask about updates.\n");
 	printk(KERN_INFO " *** Building an SMP kernel may evade the bug some of the time.\n");
+#ifdef CONFIG_X86_IO_APIC
+	skip_ioapic_setup = 0;
+#endif
 	return 0;
 }
 
@@ -403,75 +477,6 @@
 	return 0;
 }
 
-/*
- * Some machines, usually laptops, can't handle an enabled local APIC.
- * The symptoms include hangs or reboots when suspending or resuming,
- * attaching or detaching the power cord, or entering BIOS setup screens
- * through magic key sequences.
- */
-static int __init local_apic_kills_bios(struct dmi_blacklist *d)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	extern int dont_enable_local_apic;
-	if (!dont_enable_local_apic) {
-		dont_enable_local_apic = 1;
-		printk(KERN_WARNING "%s with broken BIOS detected. "
-		       "Refusing to enable the local APIC.\n",
-		       d->ident);
-	}
-#endif
-	return 0;
-}
-
-/*
- * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after
- * resumes, and also at what appears to be asynchronous APM events,
- * if the local APIC is enabled.
- */
-static int __init apm_kills_local_apic(struct dmi_blacklist *d)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	extern int dont_enable_local_apic;
-	if (apm_info.bios.version && !dont_enable_local_apic) {
-		dont_enable_local_apic = 1;
-		printk(KERN_WARNING "%s with broken BIOS detected. "
-		       "Refusing to enable the local APIC.\n",
-		       d->ident);
-	}
-#endif
-	return 0;
-}
-
-/*
- * The Intel AL440LX mainboard will hang randomly if the local APIC
- * timer is running and the APM BIOS hasn't been disabled.
- */
-static int __init apm_kills_local_apic_timer(struct dmi_blacklist *d)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	extern int dont_use_local_apic_timer;
-	if (apm_info.bios.version && !dont_use_local_apic_timer) {
-		dont_use_local_apic_timer = 1;
-		printk(KERN_WARNING "%s with broken BIOS detected. "
-		       "The local APIC timer will not be used.\n",
-		       d->ident);
-	}
-#endif
-	return 0;
-}
-
-/* 
- * Don't access SMBus on IBM systems which get corrupted eeproms 
- */
-
-static __init int disable_smbus(struct dmi_blacklist *d)
-{
-	if (is_unsafe_smbus == 0) {
-		is_unsafe_smbus = 1;
-		printk(KERN_INFO "%s machine detected. Disabling SMBus accesses.\n", d->ident);
-	}
-	return 0;
-}
 
 /*
  *	Simple "print if true" callback
@@ -555,6 +560,17 @@
 			MATCH(DMI_BIOS_VERSION, "Version1.01"),
 			NO_MATCH, NO_MATCH,
 			} },
+	{ apm_is_horked, "Intel D850MD", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+			MATCH(DMI_BIOS_VERSION, "MV85010A.86A.0016.P07.0201251536"),
+			NO_MATCH, NO_MATCH,
+			} },
+	{ apm_is_horked, "Dell XPS-Z", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+			MATCH(DMI_BIOS_VERSION, "A11"),
+			MATCH(DMI_PRODUCT_NAME, "XPS-Z"),
+			NO_MATCH,
+			} },
 	{ apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
 			MATCH(DMI_SYS_VENDOR, "SHARP"),
 			MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
@@ -625,22 +641,29 @@
 			MATCH(DMI_BIOS_VERSION, "R0209Z3"),
 			MATCH(DMI_BIOS_DATE, "05/12/01"), NO_MATCH
 			} },
-	
+
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-F104K */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0204K2"),
 			MATCH(DMI_BIOS_DATE, "08/28/00"), NO_MATCH
 			} },
-	
+
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-C1VN/C1VE */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0208P1"),
 			MATCH(DMI_BIOS_DATE, "11/09/00"), NO_MATCH
 			} },
+
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-C1VE */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0204P1"),
 			MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH
+			} },
+
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-C1VE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "WXPO1Z3"),
+			MATCH(DMI_BIOS_DATE, "10/26/01"), NO_MATCH
 			} },
 
 	/* Machines which have problems handling enabled local APICs */
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S	Fri Oct 11 21:22:53 2002
+++ b/arch/i386/kernel/head.S	Fri Oct 11 21:22:53 2002
@@ -82,7 +82,7 @@
  * Initialize page tables
  */
 	movl $pg0-__PAGE_OFFSET,%edi /* initialize page tables */
-	movl $007,%eax		/* "007" doesn't mean with right to kill, but
+	movl $007,%eax		/* "007" doesn't mean with license to kill, but
 				   PRESENT+RW+USER */
 2:	stosl
 	add $0x1000,%eax
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c	Fri Oct 11 21:22:52 2002
+++ b/arch/i386/kernel/irq.c	Fri Oct 11 21:22:52 2002
@@ -171,7 +171,7 @@
 	seq_printf(p, "LOC: ");
 	for (j = 0; j < NR_CPUS; j++)
 		if (cpu_online(j))
-			p += seq_printf(p, "%10u ", apic_timer_irqs[j]);
+			p += seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs);
 	seq_putc(p, '\n');
 #endif
 	seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/kernel/mpparse.c	Fri Oct 11 21:22:55 2002
@@ -1017,6 +1017,8 @@
 	}
 }
 
+#ifndef CONFIG_ACPI_HT_ONLY
+
 /* Ensure the ACPI SCI interrupt level is active low, edge-triggered */
 
 extern FADT_DESCRIPTOR acpi_fadt;
@@ -1038,7 +1040,7 @@
 	status = acpi_get_firmware_table("APIC", 1, ACPI_LOGICAL_ADDRESSING,
 		(acpi_table_header **) &madt);
 	if (ACPI_SUCCESS(status)) {
-		madt_end = (unsigned long)madt + madt->header.length;
+		madt_end = (void *) (unsigned long)madt + madt->header.length;
 
 		entry = (struct acpi_table_int_src_ovr *)
                 ((unsigned long) madt + sizeof(struct acpi_table_madt));
@@ -1059,6 +1061,8 @@
 
 	io_apic_set_pci_routing(ioapic, ioapic_pin, irq);
 }
+
+#endif /*CONFIG_ACPI_HT_ONLY*/
 
 #ifdef CONFIG_ACPI_PCI
 
diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
--- a/arch/i386/kernel/nmi.c	Fri Oct 11 21:22:59 2002
+++ b/arch/i386/kernel/nmi.c	Fri Oct 11 21:22:59 2002
@@ -348,7 +348,7 @@
 	 */
 	int sum, cpu = smp_processor_id();
 
-	sum = apic_timer_irqs[cpu];
+	sum = irq_stat[cpu].apic_timer_irqs;
 
 	if (last_irq_sums[cpu] == sum) {
 		/*
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Fri Oct 11 21:22:50 2002
+++ b/arch/i386/kernel/process.c	Fri Oct 11 21:22:50 2002
@@ -162,7 +162,7 @@
 
 	printk("\n");
 	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
-	printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
+	printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id());
 	print_symbol("EIP is at %s\n", regs->eip);
 
 	if (regs->xcs & 3)
diff -Nru a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
--- a/arch/i386/kernel/reboot.c	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/kernel/reboot.c	Fri Oct 11 21:22:55 2002
@@ -2,44 +2,12 @@
  *  linux/arch/i386/kernel/reboot.c
  */
 
-#define __KERNEL_SYSCALLS__
-#include <stdarg.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/interrupt.h>
-#include <linux/config.h>
 #include <linux/delay.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
-
 #include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/ldt.h>
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/desc.h>
-#ifdef CONFIG_MATH_EMULATION
-#include <asm/math_emu.h>
-#endif
-
-#include <linux/irq.h>
-#include <linux/err.h>
 
 /*
  * Power off function, if any
@@ -148,7 +116,7 @@
 	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
 	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
 	0x74, 0x02,				/*    jz    f                */
-	0x0f, 0x08,				/*    invd                   */
+	0x0f, 0x09,				/*    wbinvd                 */
 	0x24, 0x10,				/* f: andb  $0x10,al         */
 	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
 };
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c	Fri Oct 11 21:22:58 2002
+++ b/arch/i386/kernel/time.c	Fri Oct 11 21:22:58 2002
@@ -53,6 +53,7 @@
 #include <asm/mpspec.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
+#include <asm/timer.h>
 
 #include <linux/mc146818rtc.h>
 #include <linux/timex.h>
@@ -73,161 +74,15 @@
 
 unsigned long cpu_khz;	/* Detected as we calibrate the TSC */
 
-/* Number of usecs that the last interrupt was delayed */
-static int delay_at_last_interrupt;
-
-static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
-
-/* Cached *multiplier* to convert TSC counts to microseconds.
- * (see the equation below).
- * Equal to 2^32 * (1 / (clocks per usec) ).
- * Initialized in time_init.
- */
-unsigned long fast_gettimeoffset_quotient;
-
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
 
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
-static inline unsigned long do_fast_gettimeoffset(void)
-{
-	register unsigned long eax, edx;
-
-	/* Read the Time Stamp Counter */
-
-	rdtsc(eax,edx);
-
-	/* .. relative to previous jiffy (32 bits is enough) */
-	eax -= last_tsc_low;	/* tsc_low delta */
-
-	/*
-         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
-         *             = (tsc_low delta) * (usecs_per_clock)
-         *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
-	 *
-	 * Using a mull instead of a divl saves up to 31 clock cycles
-	 * in the critical path.
-         */
-
-	__asm__("mull %2"
-		:"=a" (eax), "=d" (edx)
-		:"rm" (fast_gettimeoffset_quotient),
-		 "0" (eax));
-
-	/* our adjusted time offset in microseconds */
-	return delay_at_last_interrupt + edx;
-}
-
-#define TICK_SIZE (tick_nsec / 1000)
-
 spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 EXPORT_SYMBOL(i8253_lock);
 
-#ifndef CONFIG_X86_TSC
-
-/* This function must be called with interrupts disabled 
- * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
- * 
- * However, the pc-audio speaker driver changes the divisor so that
- * it gets interrupted rather more often - it loads 64 into the
- * counter rather than 11932! This has an adverse impact on
- * do_gettimeoffset() -- it stops working! What is also not
- * good is that the interval that our timer function gets called
- * is no longer 10.0002 ms, but 9.9767 ms. To get around this
- * would require using a different timing source. Maybe someone
- * could use the RTC - I know that this can interrupt at frequencies
- * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
- * it so that at startup, the timer code in sched.c would select
- * using either the RTC or the 8253 timer. The decision would be
- * based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that 
- * advanced the clock by 1/1024 s. Every time that reached over 1/100
- * of a second, then do all the old code. If the time was kept correct
- * then do_gettimeoffset could just return 0 - there is no low order
- * divider that can be accessed.
- *
- * Ideally, you would be able to use the RTC for the speaker driver,
- * but it appears that the speaker driver really needs interrupt more
- * often than every 120 us or so.
- *
- * Anyway, this needs more thought....		pjsg (1993-08-28)
- * 
- * If you are really that interested, you should be reading
- * comp.protocols.time.ntp!
- */
-
-static unsigned long do_slow_gettimeoffset(void)
-{
-	int count;
-
-	static int count_p = LATCH;    /* for the first call after boot */
-	static unsigned long jiffies_p = 0;
-
-	/*
-	 * cache volatile jiffies temporarily; we have IRQs turned off. 
-	 */
-	unsigned long jiffies_t;
-
-	/* gets recalled with irq locally disabled */
-	spin_lock(&i8253_lock);
-	/* timer count may underflow right here */
-	outb_p(0x00, 0x43);	/* latch the count ASAP */
-
-	count = inb_p(0x40);	/* read the latched count */
-
-	/*
-	 * We do this guaranteed double memory access instead of a _p 
-	 * postfix in the previous port access. Wheee, hackady hack
-	 */
- 	jiffies_t = jiffies;
-
-	count |= inb_p(0x40) << 8;
-	
-        /* VIA686a test code... reset the latch if count > max + 1 */
-        if (count > LATCH) {
-                outb_p(0x34, 0x43);
-                outb_p(LATCH & 0xff, 0x40);
-                outb(LATCH >> 8, 0x40);
-                count = LATCH - 1;
-        }
-	
-	spin_unlock(&i8253_lock);
-
-	/*
-	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there are two kinds of problems that must be avoided here:
-	 *  1. the timer counter underflows
-	 *  2. hardware problem with the timer, not giving us continuous time,
-	 *     the counter does small "jumps" upwards on some Pentium systems,
-	 *     (see c't 95/10 page 335 for Neptun bug.)
-	 */
-
-
-	if( jiffies_t == jiffies_p ) {
-		if( count > count_p ) {
-			/* the nutcase */
-			count = do_timer_overflow(count);
-		}
-	} else
-		jiffies_p = jiffies_t;
-
-	count_p = count;
-
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	count = (count + LATCH/2) / LATCH;
-
-	return count;
-}
-
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
-
-#else
-
-#define do_gettimeoffset()	do_fast_gettimeoffset()
-
-#endif
+struct timer_opts* timer;
 
 /*
  * This version of gettimeofday has microsecond resolution
@@ -239,7 +94,7 @@
 	unsigned long usec, sec;
 
 	read_lock_irqsave(&xtime_lock, flags);
-	usec = do_gettimeoffset();
+	usec = timer->get_offset();
 	{
 		unsigned long lost = jiffies - wall_jiffies;
 		if (lost)
@@ -267,7 +122,7 @@
 	 * wall time.  Discover what correction gettimeofday() would have
 	 * made, and then undo it!
 	 */
-	tv->tv_usec -= do_gettimeoffset();
+	tv->tv_usec -= timer->get_offset();
 	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
 
 	while (tv->tv_usec < 0) {
@@ -413,8 +268,6 @@
 #endif
 }
 
-static int use_tsc;
-
 /*
  * This is the same as the above, except we _also_ save the current
  * Time Stamp Counter value at the time of the timer interrupt, so that
@@ -422,8 +275,6 @@
  */
 void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int count;
-
 	/*
 	 * Here we are in the timer irq handler. We just have irqs locally
 	 * disabled but we don't know if the timer_bh is running on the other
@@ -433,34 +284,7 @@
 	 */
 	write_lock(&xtime_lock);
 
-	if (use_tsc)
-	{
-		/*
-		 * It is important that these two operations happen almost at
-		 * the same time. We do the RDTSC stuff first, since it's
-		 * faster. To avoid any inconsistencies, we need interrupts
-		 * disabled locally.
-		 */
-
-		/*
-		 * Interrupts are just disabled locally since the timer irq
-		 * has the SA_INTERRUPT flag set. -arca
-		 */
-	
-		/* read Pentium cycle counter */
-
-		rdtscl(last_tsc_low);
-
-		spin_lock(&i8253_lock);
-		outb_p(0x00, 0x43);     /* latch the count ASAP */
-
-		count = inb_p(0x40);    /* read the latched count */
-		count |= inb(0x40) << 8;
-		spin_unlock(&i8253_lock);
-
-		count = ((LATCH-1) - count) * TICK_SIZE;
-		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
-	}
+	timer->mark_offset();
  
 	do_timer_interrupt(irq, NULL, regs);
 
@@ -510,85 +334,7 @@
 	return mktime(year, mon, day, hour, min, sec);
 }
 
-/* ------ Calibrate the TSC ------- 
- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
- * Too much 64-bit arithmetic here to do this cleanly in C, and for
- * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
- * output busy loop as low as possible. We avoid reading the CTC registers
- * directly because of the awkward 8-bit access mechanism of the 82C54
- * device.
- */
-
-#define CALIBRATE_LATCH	(5 * LATCH)
-#define CALIBRATE_TIME	(5 * 1000020/HZ)
-
-#ifdef CONFIG_X86_TSC
-static unsigned long __init calibrate_tsc(void)
-{
-       /* Set the Gate high, disable speaker */
-	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
-	/*
-	 * Now let's take care of CTC channel 2
-	 *
-	 * Set the Gate high, program CTC channel 2 for mode 0,
-	 * (interrupt on terminal count mode), binary count,
-	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
-	 */
-	outb(0xb0, 0x43);			/* binary, mode 0, LSB/MSB, Ch 2 */
-	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
-	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
-
-	{
-		unsigned long startlow, starthigh;
-		unsigned long endlow, endhigh;
-		unsigned long count;
-
-		rdtsc(startlow,starthigh);
-		count = 0;
-		do {
-			count++;
-		} while ((inb(0x61) & 0x20) == 0);
-		rdtsc(endlow,endhigh);
-
-		last_tsc_low = endlow;
-
-		/* Error: ECTCNEVERSET */
-		if (count <= 1)
-			goto bad_ctc;
-
-		/* 64-bit subtract - gcc just messes up with long longs */
-		__asm__("subl %2,%0\n\t"
-			"sbbl %3,%1"
-			:"=a" (endlow), "=d" (endhigh)
-			:"g" (startlow), "g" (starthigh),
-			 "0" (endlow), "1" (endhigh));
-
-		/* Error: ECPUTOOFAST */
-		if (endhigh)
-			goto bad_ctc;
-
-		/* Error: ECPUTOOSLOW */
-		if (endlow <= CALIBRATE_TIME)
-			goto bad_ctc;
-
-		__asm__("divl %2"
-			:"=a" (endlow), "=d" (endhigh)
-			:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
-
-		return endlow;
-	}
-
-	/*
-	 * The CTC wasn't reliable: we got a hit on the very first read,
-	 * or the CPU was so fast/slow that the quotient wouldn't fit in
-	 * 32 bits..
-	 */
-bad_ctc:
-	return 0;
-}
-#endif /* CONFIG_X86_TSC */
-
+/* XXX this driverfs stuff should probably go elsewhere later -john */
 static struct sys_device device_i8253 = {
 	.name		= "rtc",
 	.id		= 0,
@@ -605,119 +351,13 @@
 device_initcall(time_init_device);
 
 
-#ifdef CONFIG_CPU_FREQ
-
-static int
-time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-		       void *data)
-{
-	struct cpufreq_freqs *freq = data;
-	unsigned int i;
-
-	if (!cpu_has_tsc)
-		return 0;
-
-	switch (val) {
-	case CPUFREQ_PRECHANGE:
-		if ((freq->old < freq->new) &&
-		((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
-			cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
-		        fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
-		}
-		for (i=0; i<NR_CPUS; i++)
-			if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
-				cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
-		break;
-
-	case CPUFREQ_POSTCHANGE:
-		if ((freq->new < freq->old) &&
-		((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
-			cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
-		        fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
-		}
-		for (i=0; i<NR_CPUS; i++)
-			if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
-				cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
-		break;
-	}
-
-	return 0;
-}
-
-static struct notifier_block time_cpufreq_notifier_block = {
-	notifier_call:	time_cpufreq_notifier
-};
-#endif
-
-
 void __init time_init(void)
 {
-#ifdef CONFIG_X86_TSC
-	extern int x86_udelay_tsc;
-#endif
 	
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_nsec = 0;
 
-/*
- * If we have APM enabled or the CPU clock speed is variable
- * (CPU stops clock on HLT or slows clock to save power)
- * then the TSC timestamps may diverge by up to 1 jiffy from
- * 'real time' but nothing will break.
- * The most frequent case is that the CPU is "woken" from a halt
- * state by the timer interrupt itself, so we get 0 error. In the
- * rare cases where a driver would "wake" the CPU and request a
- * timestamp, the maximum error is < 1 jiffy. But timestamps are
- * still perfectly ordered.
- * Note that the TSC counter will be reset if APM suspends
- * to disk; this won't break the kernel, though, 'cuz we're
- * smart.  See arch/i386/kernel/apm.c.
- */
-#ifdef CONFIG_X86_TSC
- 	/*
- 	 *	Firstly we have to do a CPU check for chips with
- 	 * 	a potentially buggy TSC. At this point we haven't run
- 	 *	the ident/bugs checks so we must run this hook as it
- 	 *	may turn off the TSC flag.
- 	 *
- 	 *	NOTE: this doesnt yet handle SMP 486 machines where only
- 	 *	some CPU's have a TSC. Thats never worked and nobody has
- 	 *	moaned if you have the only one in the world - you fix it!
- 	 */
- 
- 	dodgy_tsc();
- 	
-	if (cpu_has_tsc) {
-		unsigned long tsc_quotient = calibrate_tsc();
-		if (tsc_quotient) {
-			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
-			 */
-			x86_udelay_tsc = 1;
-#ifndef do_gettimeoffset
-			do_gettimeoffset = do_fast_gettimeoffset;
-#endif
-
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
-			 */
-			{	unsigned long eax=0, edx=1000;
-				__asm__("divl %2"
-		       		:"=a" (cpu_khz), "=d" (edx)
-        	       		:"r" (tsc_quotient),
-	                	"0" (eax), "1" (edx));
-				printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
-			}
-#ifdef CONFIG_CPU_FREQ
-			cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
-		}
-	}
-#endif /* CONFIG_X86_TSC */
 
+	timer = select_timer();
 	time_init_hook();
 }
diff -Nru a/arch/i386/kernel/timers/Makefile b/arch/i386/kernel/timers/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/timers/Makefile	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,11 @@
+#
+# Makefile for x86 timers
+#
+
+obj-y := timer.o
+
+obj-y += timer_tsc.o
+obj-y += timer_pit.o
+obj-$(CONFIG_X86_CYCLONE)   += timer_cyclone.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/timers/timer.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,35 @@
+#include <linux/kernel.h>
+#include <asm/timer.h>
+
+/* list of externed timers */
+extern struct timer_opts timer_pit;
+extern struct timer_opts timer_tsc;
+
+/* list of timers, ordered by preference, NULL terminated */
+static struct timer_opts* timers[] = {
+	&timer_tsc,
+#ifndef CONFIG_X86_TSC
+	&timer_pit,
+#endif
+	NULL,
+};
+
+
+/* iterates through the list of timers, returning the first 
+ * one that initializes successfully.
+ */
+struct timer_opts* select_timer(void)
+{
+	int i = 0;
+	
+	/* find most preferred working timer */
+	while (timers[i]) {
+		if (timers[i]->init)
+			if (timers[i]->init() == 0)
+				return timers[i];
+		++i;
+	}
+		
+	panic("select_timer: Cannot find a suitable timer\n");
+	return NULL;
+}
diff -Nru a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/timers/timer_cyclone.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,173 @@
+/*	Cyclone-timer: 
+ *		This code implements timer_ops for the cyclone counter found
+ *		on IBM x440, x360, and other Summit based systems.
+ *
+ *	Copyright (C) 2002 IBM, John Stultz (johnstul@us.ibm.com)
+ */
+
+
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+#include <linux/errno.h>
+
+#include <asm/timer.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+
+extern spinlock_t i8253_lock;
+
+/* Number of usecs that the last interrupt was delayed */
+static int delay_at_last_interrupt;
+
+#define CYCLONE_CBAR_ADDR 0xFEB00CD0
+#define CYCLONE_PMCC_OFFSET 0x51A0
+#define CYCLONE_MPMC_OFFSET 0x51D0
+#define CYCLONE_MPCS_OFFSET 0x51A8
+#define CYCLONE_TIMER_FREQ 100000000
+
+int use_cyclone = 0;
+
+static u32* volatile cyclone_timer;	/* Cyclone MPMC0 register */
+static u32 last_cyclone_timer;
+
+static void mark_offset_cyclone(void)
+{
+	int count;
+	spin_lock(&i8253_lock);
+	/* quickly read the cyclone timer */
+	if(cyclone_timer)
+		last_cyclone_timer = cyclone_timer[0];
+
+	/* calculate delay_at_last_interrupt */
+	outb_p(0x00, 0x43);     /* latch the count ASAP */
+
+	count = inb_p(0x40);    /* read the latched count */
+	count |= inb(0x40) << 8;
+	spin_unlock(&i8253_lock);
+
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+}
+
+static unsigned long get_offset_cyclone(void)
+{
+	u32 offset;
+
+	if(!cyclone_timer)
+		return delay_at_last_interrupt;
+
+	/* Read the cyclone timer */
+	offset = cyclone_timer[0];
+
+	/* .. relative to previous jiffy */
+	offset = offset - last_cyclone_timer;
+
+	/* convert cyclone ticks to microseconds */	
+	/* XXX slow, can we speed this up? */
+	offset = offset/(CYCLONE_TIMER_FREQ/1000000);
+
+	/* our adjusted time offset in microseconds */
+	return delay_at_last_interrupt + offset;
+}
+
+static int init_cyclone(void)
+{
+	u32* reg;	
+	u32 base;		/* saved cyclone base address */
+	u32 pageaddr;	/* page that contains cyclone_timer register */
+	u32 offset;		/* offset from pageaddr to cyclone_timer register */
+	int i;
+	
+	/*make sure we're on a summit box*/
+	/*XXX need to use proper summit hooks! such as xapic -john*/
+	if(!use_cyclone) return -ENODEV; 
+	
+	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
+
+	/* find base address */
+	pageaddr = (CYCLONE_CBAR_ADDR)&PAGE_MASK;
+	offset = (CYCLONE_CBAR_ADDR)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+		return -ENODEV;
+	}
+	base = *reg;	
+	if(!base){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+		return -ENODEV;
+	}
+	
+	/* setup PMCC */
+	pageaddr = (base + CYCLONE_PMCC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_PMCC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+		return -ENODEV;
+	}
+	reg[0] = 0x00000001;
+
+	/* setup MPCS */
+	pageaddr = (base + CYCLONE_MPCS_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPCS_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+		return -ENODEV;
+	}
+	reg[0] = 0x00000001;
+
+	/* map in cyclone_timer */
+	pageaddr = (base + CYCLONE_MPMC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPMC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	cyclone_timer = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!cyclone_timer){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+		return -ENODEV;
+	}
+
+	/*quick test to make sure its ticking*/
+	for(i=0; i<3; i++){
+		u32 old = cyclone_timer[0];
+		int stall = 100;
+		while(stall--) barrier();
+		if(cyclone_timer[0] == old){
+			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+			cyclone_timer = 0;
+			return -ENODEV;
+		}
+	}
+
+	/* Everything looks good! */
+	return 0;
+}
+
+
+#if 0 /* XXX future work */
+static void delay_cyclone(unsigned long loops)
+{
+	unsigned long bclock, now;
+	if(!cyclone_timer)
+		return;
+	bclock = cyclone_timer[0];
+	do {
+		rep_nop();
+		now = cyclone_timer[0];
+	} while ((now-bclock) < loops);
+}
+#endif
+/************************************************************/
+
+/* cyclone timer_opts struct */
+struct timer_opts timer_cyclone = {
+	.init = init_cyclone, 
+	.mark_offset = mark_offset_cyclone, 
+	.get_offset = get_offset_cyclone
+};
diff -Nru a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/timers/timer_pit.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,129 @@
+/*
+ * This code largely moved from arch/i386/kernel/time.c.
+ * See comments there for proper credits.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <asm/mpspec.h>
+#include <asm/timer.h>
+#include <asm/io.h>
+
+extern spinlock_t i8259A_lock;
+extern spinlock_t i8253_lock;
+#include "do_timer.h"
+
+static int init_pit(void)
+{
+	return 0;
+}
+
+static void mark_offset_pit(void)
+{
+	/* nothing needed */
+}
+
+
+/* This function must be called with interrupts disabled 
+ * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
+ * 
+ * However, the pc-audio speaker driver changes the divisor so that
+ * it gets interrupted rather more often - it loads 64 into the
+ * counter rather than 11932! This has an adverse impact on
+ * do_gettimeoffset() -- it stops working! What is also not
+ * good is that the interval that our timer function gets called
+ * is no longer 10.0002 ms, but 9.9767 ms. To get around this
+ * would require using a different timing source. Maybe someone
+ * could use the RTC - I know that this can interrupt at frequencies
+ * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
+ * it so that at startup, the timer code in sched.c would select
+ * using either the RTC or the 8253 timer. The decision would be
+ * based on whether there was any other device around that needed
+ * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
+ * and then do some jiggery to have a version of do_timer that 
+ * advanced the clock by 1/1024 s. Every time that reached over 1/100
+ * of a second, then do all the old code. If the time was kept correct
+ * then do_gettimeoffset could just return 0 - there is no low order
+ * divider that can be accessed.
+ *
+ * Ideally, you would be able to use the RTC for the speaker driver,
+ * but it appears that the speaker driver really needs interrupt more
+ * often than every 120 us or so.
+ *
+ * Anyway, this needs more thought....		pjsg (1993-08-28)
+ * 
+ * If you are really that interested, you should be reading
+ * comp.protocols.time.ntp!
+ */
+
+static unsigned long get_offset_pit(void)
+{
+	int count;
+
+	static int count_p = LATCH;    /* for the first call after boot */
+	static unsigned long jiffies_p = 0;
+
+	/*
+	 * cache volatile jiffies temporarily; we have IRQs turned off. 
+	 */
+	unsigned long jiffies_t;
+
+	/* gets recalled with irq locally disabled */
+	spin_lock(&i8253_lock);
+	/* timer count may underflow right here */
+	outb_p(0x00, 0x43);	/* latch the count ASAP */
+
+	count = inb_p(0x40);	/* read the latched count */
+
+	/*
+	 * We do this guaranteed double memory access instead of a _p 
+	 * postfix in the previous port access. Wheee, hackady hack
+	 */
+ 	jiffies_t = jiffies;
+
+	count |= inb_p(0x40) << 8;
+	
+        /* VIA686a test code... reset the latch if count > max + 1 */
+        if (count > LATCH) {
+                outb_p(0x34, 0x43);
+                outb_p(LATCH & 0xff, 0x40);
+                outb(LATCH >> 8, 0x40);
+                count = LATCH - 1;
+        }
+	
+	spin_unlock(&i8253_lock);
+
+	/*
+	 * avoiding timer inconsistencies (they are rare, but they happen)...
+	 * there are two kinds of problems that must be avoided here:
+	 *  1. the timer counter underflows
+	 *  2. hardware problem with the timer, not giving us continuous time,
+	 *     the counter does small "jumps" upwards on some Pentium systems,
+	 *     (see c't 95/10 page 335 for Neptun bug.)
+	 */
+
+
+	if( jiffies_t == jiffies_p ) {
+		if( count > count_p ) {
+			/* the nutcase */
+			count = do_timer_overflow(count);
+		}
+	} else
+		jiffies_p = jiffies_t;
+
+	count_p = count;
+
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	count = (count + LATCH/2) / LATCH;
+
+	return count;
+}
+
+
+/* tsc timer_opts struct */
+struct timer_opts timer_pit = {
+	.init =		init_pit, 
+	.mark_offset =	mark_offset_pit, 
+	.get_offset =	get_offset_pit,
+};
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/timers/timer_tsc.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,280 @@
+/*
+ * This code largely moved from arch/i386/kernel/time.c.
+ * See comments there for proper credits.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+#include <linux/errno.h>
+
+#include <asm/timer.h>
+#include <asm/io.h>
+
+extern int x86_udelay_tsc;
+extern spinlock_t i8253_lock;
+
+static int use_tsc;
+/* Number of usecs that the last interrupt was delayed */
+static int delay_at_last_interrupt;
+
+static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
+
+/* Cached *multiplier* to convert TSC counts to microseconds.
+ * (see the equation below).
+ * Equal to 2^32 * (1 / (clocks per usec) ).
+ * Initialized in time_init.
+ */
+unsigned long fast_gettimeoffset_quotient;
+
+static unsigned long get_offset_tsc(void)
+{
+	register unsigned long eax, edx;
+
+	/* Read the Time Stamp Counter */
+
+	rdtsc(eax,edx);
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	eax -= last_tsc_low;	/* tsc_low delta */
+
+	/*
+         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
+         *             = (tsc_low delta) * (usecs_per_clock)
+         *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
+	 *
+	 * Using a mull instead of a divl saves up to 31 clock cycles
+	 * in the critical path.
+         */
+
+	__asm__("mull %2"
+		:"=a" (eax), "=d" (edx)
+		:"rm" (fast_gettimeoffset_quotient),
+		 "0" (eax));
+
+	/* our adjusted time offset in microseconds */
+	return delay_at_last_interrupt + edx;
+}
+
+static void mark_offset_tsc(void)
+{
+	int count;
+	/*
+	 * It is important that these two operations happen almost at
+	 * the same time. We do the RDTSC stuff first, since it's
+	 * faster. To avoid any inconsistencies, we need interrupts
+	 * disabled locally.
+	 */
+
+	/*
+	 * Interrupts are just disabled locally since the timer irq
+	 * has the SA_INTERRUPT flag set. -arca
+	 */
+	
+	/* read Pentium cycle counter */
+
+	rdtscl(last_tsc_low);
+
+	spin_lock(&i8253_lock);
+	outb_p(0x00, 0x43);     /* latch the count ASAP */
+
+	count = inb_p(0x40);    /* read the latched count */
+	count |= inb(0x40) << 8;
+	spin_unlock(&i8253_lock);
+
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+}
+
+
+/* ------ Calibrate the TSC ------- 
+ * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
+ * Too much 64-bit arithmetic here to do this cleanly in C, and for
+ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
+ * output busy loop as low as possible. We avoid reading the CTC registers
+ * directly because of the awkward 8-bit access mechanism of the 82C54
+ * device.
+ */
+
+#define CALIBRATE_LATCH	(5 * LATCH)
+#define CALIBRATE_TIME	(5 * 1000020/HZ)
+
+static unsigned long __init calibrate_tsc(void)
+{
+       /* Set the Gate high, disable speaker */
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+	/*
+	 * Now let's take care of CTC channel 2
+	 *
+	 * Set the Gate high, program CTC channel 2 for mode 0,
+	 * (interrupt on terminal count mode), binary count,
+	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+	 */
+	outb(0xb0, 0x43);			/* binary, mode 0, LSB/MSB, Ch 2 */
+	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
+	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
+
+	{
+		unsigned long startlow, starthigh;
+		unsigned long endlow, endhigh;
+		unsigned long count;
+
+		rdtsc(startlow,starthigh);
+		count = 0;
+		do {
+			count++;
+		} while ((inb(0x61) & 0x20) == 0);
+		rdtsc(endlow,endhigh);
+
+		last_tsc_low = endlow;
+
+		/* Error: ECTCNEVERSET */
+		if (count <= 1)
+			goto bad_ctc;
+
+		/* 64-bit subtract - gcc just messes up with long longs */
+		__asm__("subl %2,%0\n\t"
+			"sbbl %3,%1"
+			:"=a" (endlow), "=d" (endhigh)
+			:"g" (startlow), "g" (starthigh),
+			 "0" (endlow), "1" (endhigh));
+
+		/* Error: ECPUTOOFAST */
+		if (endhigh)
+			goto bad_ctc;
+
+		/* Error: ECPUTOOSLOW */
+		if (endlow <= CALIBRATE_TIME)
+			goto bad_ctc;
+
+		__asm__("divl %2"
+			:"=a" (endlow), "=d" (endhigh)
+			:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+
+		return endlow;
+	}
+
+	/*
+	 * The CTC wasn't reliable: we got a hit on the very first read,
+	 * or the CPU was so fast/slow that the quotient wouldn't fit in
+	 * 32 bits..
+	 */
+bad_ctc:
+	return 0;
+}
+
+
+#ifdef CONFIG_CPU_FREQ
+
+static int
+time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+		       void *data)
+{
+	struct cpufreq_freqs *freq = data;
+	unsigned int i;
+
+	if (!cpu_has_tsc)
+		return 0;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		if ((freq->old < freq->new) &&
+		((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
+			cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
+		        fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
+		}
+		for (i=0; i<NR_CPUS; i++)
+			if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
+				cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		if ((freq->new < freq->old) &&
+		((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
+			cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
+		        fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
+		}
+		for (i=0; i<NR_CPUS; i++)
+			if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
+				cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
+		break;
+	}
+
+	return 0;
+}
+
+static struct notifier_block time_cpufreq_notifier_block = {
+	notifier_call:	time_cpufreq_notifier
+};
+#endif
+
+
+static int init_tsc(void)
+{
+	/*
+	 * If we have APM enabled or the CPU clock speed is variable
+	 * (CPU stops clock on HLT or slows clock to save power)
+	 * then the TSC timestamps may diverge by up to 1 jiffy from
+	 * 'real time' but nothing will break.
+	 * The most frequent case is that the CPU is "woken" from a halt
+	 * state by the timer interrupt itself, so we get 0 error. In the
+	 * rare cases where a driver would "wake" the CPU and request a
+	 * timestamp, the maximum error is < 1 jiffy. But timestamps are
+	 * still perfectly ordered.
+	 * Note that the TSC counter will be reset if APM suspends
+	 * to disk; this won't break the kernel, though, 'cuz we're
+	 * smart.  See arch/i386/kernel/apm.c.
+	 */
+ 	/*
+ 	 *	Firstly we have to do a CPU check for chips with
+ 	 * 	a potentially buggy TSC. At this point we haven't run
+ 	 *	the ident/bugs checks so we must run this hook as it
+ 	 *	may turn off the TSC flag.
+ 	 *
+ 	 *	NOTE: this doesnt yet handle SMP 486 machines where only
+ 	 *	some CPU's have a TSC. Thats never worked and nobody has
+ 	 *	moaned if you have the only one in the world - you fix it!
+ 	 */
+ 
+ 	dodgy_tsc();
+ 	
+	if (cpu_has_tsc) {
+		unsigned long tsc_quotient = calibrate_tsc();
+		if (tsc_quotient) {
+			fast_gettimeoffset_quotient = tsc_quotient;
+			use_tsc = 1;
+			/*
+			 *	We could be more selective here I suspect
+			 *	and just enable this for the next intel chips ?
+			 */
+			x86_udelay_tsc = 1;
+
+			/* report CPU clock rate in Hz.
+			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
+			 * clock/second. Our precision is about 100 ppm.
+			 */
+			{	unsigned long eax=0, edx=1000;
+				__asm__("divl %2"
+		       		:"=a" (cpu_khz), "=d" (edx)
+        	       		:"r" (tsc_quotient),
+	                	"0" (eax), "1" (edx));
+				printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
+			}
+#ifdef CONFIG_CPU_FREQ
+			cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+			return 0;
+		}
+	}
+	return -ENODEV;
+}
+
+/************************************************************/
+
+/* tsc timer_opts struct */
+struct timer_opts timer_tsc = {
+	.init =		init_tsc,
+	.mark_offset =	mark_offset_tsc, 
+	.get_offset =	get_offset_tsc,
+};
diff -Nru a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
--- a/arch/i386/kernel/trampoline.S	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/kernel/trampoline.S	Fri Oct 11 21:22:55 2002
@@ -36,9 +36,7 @@
 
 ENTRY(trampoline_data)
 r_base = .
-#ifdef CONFIG_MULTIQUAD
-	wbinvd
-#endif /* CONFIG_MULTIQUAD */
+	wbinvd			# Needed for NUMA-Q should be harmless for others
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
 
diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
--- a/arch/i386/kernel/vm86.c	Fri Oct 11 21:22:53 2002
+++ b/arch/i386/kernel/vm86.c	Fri Oct 11 21:22:53 2002
@@ -2,7 +2,34 @@
  *  linux/kernel/vm86.c
  *
  *  Copyright (C) 1994  Linus Torvalds
+ *
+ *  29 dec 2001 - Fixed oopses caused by unchecked access to the vm86
+ *                stack - Manfred Spraul <manfreds@colorfullife.com>
+ *
+ *  22 mar 2002 - Manfred detected the stackfaults, but didn't handle
+ *                them correctly. Now the emulation will be in a
+ *                consistent state after stackfaults - Kasper Dupont
+ *                <kasperd@daimi.au.dk>
+ *
+ *  22 mar 2002 - Added missing clear_IF in set_vflags_* Kasper Dupont
+ *                <kasperd@daimi.au.dk>
+ *
+ *  ?? ??? 2002 - Fixed premature returns from handle_vm86_fault
+ *                caused by Kasper Dupont's changes - Stas Sergeev
+ *
+ *   4 apr 2002 - Fixed CHECK_IF_IN_TRAP broken by Stas' changes.
+ *                Kasper Dupont <kasperd@daimi.au.dk>
+ *
+ *   9 apr 2002 - Changed syntax of macros in handle_vm86_fault.
+ *                Kasper Dupont <kasperd@daimi.au.dk>
+ *
+ *   9 apr 2002 - Changed stack access macros to jump to a label
+ *                instead of returning to userspace. This simplifies
+ *                do_int, and is needed by handle_vm6_fault. Kasper
+ *                Dupont <kasperd@daimi.au.dk>
+ *
  */
+
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -17,6 +44,7 @@
 #include <asm/pgalloc.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
+#include <asm/irq.h>
 
 /*
  * Known problems:
@@ -97,23 +125,24 @@
 	pte_t *pte, *mapped;
 	int i;
 
+	preempt_disable();
+	spin_lock(&tsk->mm->page_table_lock);
 	pgd = pgd_offset(tsk->mm, 0xA0000);
 	if (pgd_none(*pgd))
-		return;
+		goto out;
 	if (pgd_bad(*pgd)) {
 		pgd_ERROR(*pgd);
 		pgd_clear(pgd);
-		return;
+		goto out;
 	}
 	pmd = pmd_offset(pgd, 0xA0000);
 	if (pmd_none(*pmd))
-		return;
+		goto out;
 	if (pmd_bad(*pmd)) {
 		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
-		return;
+		goto out;
 	}
-	preempt_disable();
 	pte = mapped = pte_offset_map(pmd, 0xA0000);
 	for (i = 0; i < 32; i++) {
 		if (pte_present(*pte))
@@ -121,6 +150,8 @@
 		pte++;
 	}
 	pte_unmap(mapped);
+out:
+	spin_unlock(&tsk->mm->page_table_lock);
 	preempt_enable();
 	flush_tlb();
 }
@@ -293,12 +324,30 @@
 	regs->eflags &= ~TF_MASK;
 }
 
+static inline void clear_AC(struct kernel_vm86_regs * regs)
+{
+	regs->eflags &= ~AC_MASK;
+}
+
+/* It is correct to call set_IF(regs) from the set_vflags_*
+ * functions. However someone forgot to call clear_IF(regs)
+ * in the opposite case.
+ * After the command sequence CLI PUSHF STI POPF you should
+ * end up with interrups disabled, but you ended up with
+ * interrupts enabled.
+ *  ( I was testing my own changes, but the only bug I
+ *    could find was in a function I had not changed. )
+ * [KD]
+ */
+
 static inline void set_vflags_long(unsigned long eflags, struct kernel_vm86_regs * regs)
 {
 	set_flags(VEFLAGS, eflags, current->thread.v86mask);
 	set_flags(regs->eflags, eflags, SAFE_MASK);
 	if (eflags & IF_MASK)
 		set_IF(regs);
+	else
+		clear_IF(regs);
 }
 
 static inline void set_vflags_short(unsigned short flags, struct kernel_vm86_regs * regs)
@@ -307,6 +356,8 @@
 	set_flags(regs->eflags, flags, SAFE_MASK);
 	if (flags & IF_MASK)
 		set_IF(regs);
+	else
+		clear_IF(regs);
 }
 
 static inline unsigned long get_vflags(struct kernel_vm86_regs * regs)
@@ -326,80 +377,90 @@
 	return nr;
 }
 
-/*
- * Boy are these ugly, but we need to do the correct 16-bit arithmetic.
- * Gcc makes a mess of it, so we do it inline and use non-obvious calling
- * conventions..
- */
-#define pushb(base, ptr, val) \
-__asm__ __volatile__( \
-	"decw %w0\n\t" \
-	"movb %2,0(%1,%0)" \
-	: "=r" (ptr) \
-	: "r" (base), "q" (val), "0" (ptr))
-
-#define pushw(base, ptr, val) \
-__asm__ __volatile__( \
-	"decw %w0\n\t" \
-	"movb %h2,0(%1,%0)\n\t" \
-	"decw %w0\n\t" \
-	"movb %b2,0(%1,%0)" \
-	: "=r" (ptr) \
-	: "r" (base), "q" (val), "0" (ptr))
-
-#define pushl(base, ptr, val) \
-__asm__ __volatile__( \
-	"decw %w0\n\t" \
-	"rorl $16,%2\n\t" \
-	"movb %h2,0(%1,%0)\n\t" \
-	"decw %w0\n\t" \
-	"movb %b2,0(%1,%0)\n\t" \
-	"decw %w0\n\t" \
-	"rorl $16,%2\n\t" \
-	"movb %h2,0(%1,%0)\n\t" \
-	"decw %w0\n\t" \
-	"movb %b2,0(%1,%0)" \
-	: "=r" (ptr) \
-	: "r" (base), "q" (val), "0" (ptr))
-
-#define popb(base, ptr) \
-({ unsigned long __res; \
-__asm__ __volatile__( \
-	"movb 0(%1,%0),%b2\n\t" \
-	"incw %w0" \
-	: "=r" (ptr), "=r" (base), "=q" (__res) \
-	: "0" (ptr), "1" (base), "2" (0)); \
-__res; })
-
-#define popw(base, ptr) \
-({ unsigned long __res; \
-__asm__ __volatile__( \
-	"movb 0(%1,%0),%b2\n\t" \
-	"incw %w0\n\t" \
-	"movb 0(%1,%0),%h2\n\t" \
-	"incw %w0" \
-	: "=r" (ptr), "=r" (base), "=q" (__res) \
-	: "0" (ptr), "1" (base), "2" (0)); \
-__res; })
-
-#define popl(base, ptr) \
-({ unsigned long __res; \
-__asm__ __volatile__( \
-	"movb 0(%1,%0),%b2\n\t" \
-	"incw %w0\n\t" \
-	"movb 0(%1,%0),%h2\n\t" \
-	"incw %w0\n\t" \
-	"rorl $16,%2\n\t" \
-	"movb 0(%1,%0),%b2\n\t" \
-	"incw %w0\n\t" \
-	"movb 0(%1,%0),%h2\n\t" \
-	"incw %w0\n\t" \
-	"rorl $16,%2" \
-	: "=r" (ptr), "=r" (base), "=q" (__res) \
-	: "0" (ptr), "1" (base)); \
-__res; })
+#define val_byte(val, n) (((__u8 *)&val)[n])
 
-static void do_int(struct kernel_vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp)
+#define pushb(base, ptr, val, err_label) \
+	do { \
+		__u8 __val = val; \
+		ptr--; \
+		if (put_user(__val, base + ptr) < 0) \
+			goto err_label; \
+	} while(0)
+
+#define pushw(base, ptr, val, err_label) \
+	do { \
+		__u16 __val = val; \
+		ptr--; \
+		if (put_user(val_byte(__val, 1), base + ptr) < 0) \
+			goto err_label; \
+		ptr--; \
+		if (put_user(val_byte(__val, 0), base + ptr) < 0) \
+			goto err_label; \
+	} while(0)
+
+#define pushl(base, ptr, val, err_label) \
+	do { \
+		__u32 __val = val; \
+		ptr--; \
+		if (put_user(val_byte(__val, 3), base + ptr) < 0) \
+			goto err_label; \
+		ptr--; \
+		if (put_user(val_byte(__val, 2), base + ptr) < 0) \
+			goto err_label; \
+		ptr--; \
+		if (put_user(val_byte(__val, 1), base + ptr) < 0) \
+			goto err_label; \
+		ptr--; \
+		if (put_user(val_byte(__val, 0), base + ptr) < 0) \
+			goto err_label; \
+	} while(0)
+
+#define popb(base, ptr, err_label) \
+	({ \
+		__u8 __res; \
+		if (get_user(__res, base + ptr) < 0) \
+			goto err_label; \
+		ptr++; \
+		__res; \
+	})
+
+#define popw(base, ptr, err_label) \
+	({ \
+		__u16 __res; \
+		if (get_user(val_byte(__res, 0), base + ptr) < 0) \
+			goto err_label; \
+		ptr++; \
+		if (get_user(val_byte(__res, 1), base + ptr) < 0) \
+			goto err_label; \
+		ptr++; \
+		__res; \
+	})
+
+#define popl(base, ptr, err_label) \
+	({ \
+		__u32 __res; \
+		if (get_user(val_byte(__res, 0), base + ptr) < 0) \
+			goto err_label; \
+		ptr++; \
+		if (get_user(val_byte(__res, 1), base + ptr) < 0) \
+			goto err_label; \
+		ptr++; \
+		if (get_user(val_byte(__res, 2), base + ptr) < 0) \
+			goto err_label; \
+		ptr++; \
+		if (get_user(val_byte(__res, 3), base + ptr) < 0) \
+			goto err_label; \
+		ptr++; \
+		__res; \
+	})
+
+/* There are so many possible reasons for this function to return
+ * VM86_INTx, so adding another doesn't bother me. We can expect
+ * userspace programs to be able to handle it. (Getting a problem
+ * in userspace is always better than an Oops anyway.) [KD]
+ */
+static void do_int(struct kernel_vm86_regs *regs, int i,
+    unsigned char * ssp, unsigned short sp)
 {
 	unsigned long *intr_ptr, segoffs;
 
@@ -414,14 +475,15 @@
 		goto cannot_handle;
 	if ((segoffs >> 16) == BIOSSEG)
 		goto cannot_handle;
-	pushw(ssp, sp, get_vflags(regs));
-	pushw(ssp, sp, regs->cs);
-	pushw(ssp, sp, IP(regs));
+	pushw(ssp, sp, get_vflags(regs), cannot_handle);
+	pushw(ssp, sp, regs->cs, cannot_handle);
+	pushw(ssp, sp, IP(regs), cannot_handle);
 	regs->cs = segoffs >> 16;
 	SP(regs) -= 6;
 	IP(regs) = segoffs & 0xffff;
 	clear_TF(regs);
 	clear_IF(regs);
+	clear_AC(regs);
 	return;
 
 cannot_handle:
@@ -453,75 +515,80 @@
 
 void handle_vm86_fault(struct kernel_vm86_regs * regs, long error_code)
 {
-	unsigned char *csp, *ssp;
-	unsigned long ip, sp;
+	unsigned char *csp, *ssp, opcode;
+	unsigned short ip, sp;
+	int data32, pref_done;
 
 #define CHECK_IF_IN_TRAP \
 	if (VMPI.vm86dbg_active && VMPI.vm86dbg_TFpendig) \
-		pushw(ssp,sp,popw(ssp,sp) | TF_MASK);
-#define VM86_FAULT_RETURN \
+		newflags |= TF_MASK
+#define VM86_FAULT_RETURN do { \
 	if (VMPI.force_return_for_pic  && (VEFLAGS & (IF_MASK | VIF_MASK))) \
 		return_to_32bit(regs, VM86_PICRETURN); \
-	return;
-	                                   
+	return; } while (0)
+
 	csp = (unsigned char *) (regs->cs << 4);
 	ssp = (unsigned char *) (regs->ss << 4);
 	sp = SP(regs);
 	ip = IP(regs);
 
-	switch (popb(csp, ip)) {
-
-	/* operand size override */
-	case 0x66:
-		switch (popb(csp, ip)) {
-
-		/* pushfd */
-		case 0x9c:
-			SP(regs) -= 4;
-			IP(regs) += 2;
-			pushl(ssp, sp, get_vflags(regs));
-			VM86_FAULT_RETURN;
-
-		/* popfd */
-		case 0x9d:
-			SP(regs) += 4;
-			IP(regs) += 2;
-			CHECK_IF_IN_TRAP
-			set_vflags_long(popl(ssp, sp), regs);
-			VM86_FAULT_RETURN;
-
-		/* iretd */
-		case 0xcf:
-			SP(regs) += 12;
-			IP(regs) = (unsigned short)popl(ssp, sp);
-			regs->cs = (unsigned short)popl(ssp, sp);
-			CHECK_IF_IN_TRAP
-			set_vflags_long(popl(ssp, sp), regs);
-			VM86_FAULT_RETURN;
-		/* need this to avoid a fallthrough */
-		default:
-			return_to_32bit(regs, VM86_UNKNOWN);
+	data32 = 0;
+	pref_done = 0;
+	do {
+		switch (opcode = popb(csp, ip, simulate_sigsegv)) {
+			case 0x66:      /* 32-bit data */     data32=1; break;
+			case 0x67:      /* 32-bit address */  break;
+			case 0x2e:      /* CS */              break;
+			case 0x3e:      /* DS */              break;
+			case 0x26:      /* ES */              break;
+			case 0x36:      /* SS */              break;
+			case 0x65:      /* GS */              break;
+			case 0x64:      /* FS */              break;
+			case 0xf2:      /* repnz */       break;
+			case 0xf3:      /* rep */             break;
+			default: pref_done = 1;
 		}
+	} while (!pref_done);
+
+	switch (opcode) {
 
 	/* pushf */
 	case 0x9c:
-		SP(regs) -= 2;
-		IP(regs)++;
-		pushw(ssp, sp, get_vflags(regs));
+		if (data32) {
+			pushl(ssp, sp, get_vflags(regs), simulate_sigsegv);
+			SP(regs) -= 4;
+		} else {
+			pushw(ssp, sp, get_vflags(regs), simulate_sigsegv);
+			SP(regs) -= 2;
+		}
+		IP(regs) = ip;
 		VM86_FAULT_RETURN;
 
 	/* popf */
 	case 0x9d:
-		SP(regs) += 2;
-		IP(regs)++;
-		CHECK_IF_IN_TRAP
-		set_vflags_short(popw(ssp, sp), regs);
+		{
+		unsigned long newflags;
+		if (data32) {
+			newflags=popl(ssp, sp, simulate_sigsegv);
+			SP(regs) += 4;
+		} else {
+			newflags = popw(ssp, sp, simulate_sigsegv);
+			SP(regs) += 2;
+		}
+		IP(regs) = ip;
+		CHECK_IF_IN_TRAP;
+		if (data32) {
+			set_vflags_long(newflags, regs);
+		} else {
+			set_vflags_short(newflags, regs);
+		}
 		VM86_FAULT_RETURN;
+		}
 
 	/* int xx */
 	case 0xcd: {
-	        int intno=popb(csp, ip);
-		IP(regs) += 2;
+		int intno=popb(csp, ip, simulate_sigsegv);
+		IP(regs) = ip;
 		if (VMPI.vm86dbg_active) {
 			if ( (1 << (intno &7)) & VMPI.vm86dbg_intxxtab[intno >> 3] )
 				return_to_32bit(regs, VM86_INTx + (intno << 8));
@@ -532,16 +599,35 @@
 
 	/* iret */
 	case 0xcf:
-		SP(regs) += 6;
-		IP(regs) = popw(ssp, sp);
-		regs->cs = popw(ssp, sp);
-		CHECK_IF_IN_TRAP
-		set_vflags_short(popw(ssp, sp), regs);
+		{
+		unsigned long newip;
+		unsigned long newcs;
+		unsigned long newflags;
+		if (data32) {
+			newip=popl(ssp, sp, simulate_sigsegv);
+			newcs=popl(ssp, sp, simulate_sigsegv);
+			newflags=popl(ssp, sp, simulate_sigsegv);
+			SP(regs) += 12;
+		} else {
+			newip = popw(ssp, sp, simulate_sigsegv);
+			newcs = popw(ssp, sp, simulate_sigsegv);
+			newflags = popw(ssp, sp, simulate_sigsegv);
+			SP(regs) += 6;
+		}
+		IP(regs) = newip;
+		regs->cs = newcs;
+		CHECK_IF_IN_TRAP;
+		if (data32) {
+			set_vflags_long(newflags, regs);
+		} else {
+			set_vflags_short(newflags, regs);
+		}
 		VM86_FAULT_RETURN;
+		}
 
 	/* cli */
 	case 0xfa:
-		IP(regs)++;
+		IP(regs) = ip;
 		clear_IF(regs);
 		VM86_FAULT_RETURN;
 
@@ -553,13 +639,28 @@
 	 * Probably needs some horsing around with the TF flag. Aiee..
 	 */
 	case 0xfb:
-		IP(regs)++;
+		IP(regs) = ip;
 		set_IF(regs);
 		VM86_FAULT_RETURN;
 
 	default:
 		return_to_32bit(regs, VM86_UNKNOWN);
 	}
+
+	return;
+
+simulate_sigsegv:
+	/* FIXME: After a long discussion with Stas we finally
+	 *        agreed, that this is wrong. Here we should
+	 *        really send a SIGSEGV to the user program.
+	 *        But how do we create the correct context? We
+	 *        are inside a general protection fault handler
+	 *        and has just returned from a page fault handler.
+	 *        The correct context for the signal handler
+	 *        should be a mixture of the two, but how do we
+	 *        get the information? [KD]
+	 */
+	return_to_32bit(regs, VM86_UNKNOWN);
 }
 
 /* ---------------- vm86 special IRQ passing stuff ----------------- */
@@ -621,6 +722,14 @@
 out:
 	read_unlock(&tasklist_lock);
 	return ret;
+}
+
+void release_x86_irqs(struct task_struct *task)
+{
+	int i;
+	for (i=3; i<16; i++)
+	    if (vm86_irqs[i].tsk == task)
+		free_vm86_irq(i);
 }
 
 static inline void handle_irq_zombies(void)
diff -Nru a/arch/i386/math-emu/fpu_system.h b/arch/i386/math-emu/fpu_system.h
--- a/arch/i386/math-emu/fpu_system.h	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/math-emu/fpu_system.h	Fri Oct 11 21:22:55 2002
@@ -20,6 +20,8 @@
    of the stack frame of math_emulate() */
 #define SETUP_DATA_AREA(arg)	FPU_info = (struct info *) &arg
 
+/* s is always from a cpu register, and the cpu does bounds checking
+ * during register load --> no further bounds checks needed */
 #define LDT_DESCRIPTOR(s)	(((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
 #define SEG_D_SIZE(x)		((x).b & (3 << 21))
 #define SEG_G_BIT(x)		((x).b & (1 << 23))
diff -Nru a/arch/i386/math-emu/poly.h b/arch/i386/math-emu/poly.h
--- a/arch/i386/math-emu/poly.h	Fri Oct 11 21:22:51 2002
+++ b/arch/i386/math-emu/poly.h	Fri Oct 11 21:22:51 2002
@@ -75,10 +75,10 @@
 /* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
 static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
 {
-  asm volatile ("movl %1,%%edi; movl %2,%%esi;
-                 movl (%%esi),%%eax; addl %%eax,(%%edi);
-                 movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);
-                 movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);"
+  asm volatile ("movl %1,%%edi; movl %2,%%esi;\n"
+                "movl (%%esi),%%eax; addl %%eax,(%%edi);\n"
+                "movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);\n"
+                "movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);\n"
                  :"=g" (*dest):"g" (dest), "g" (x2)
                  :"ax","si","di");
 }
@@ -90,16 +90,16 @@
    problem, but keep fingers crossed! */
 static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
 {
-  asm volatile ("movl %2,%%ecx; movl %3,%%esi;
-                 movl (%%esi),%%eax; addl %%eax,(%%ecx);
-                 movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);
-                 movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);
-                 jnc 0f;
-		 rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)
-                 movl %4,%%ecx; incl (%%ecx)
-                 movl $1,%%eax; jmp 1f;
-                 0: xorl %%eax,%%eax;
-                 1:"
+  asm volatile ("movl %2,%%ecx; movl %3,%%esi;\n"
+                "movl (%%esi),%%eax; addl %%eax,(%%ecx);\n"
+                "movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);\n"
+                "movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);\n"
+                "jnc 0f;\n"
+		"rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)\n"
+                "movl %4,%%ecx; incl (%%ecx)\n"
+                "movl $1,%%eax; jmp 1f;\n"
+                "0: xorl %%eax,%%eax;\n"
+                "1:\n"
 		:"=g" (*exp), "=g" (*dest)
 		:"g" (dest), "g" (x2), "g" (exp)
 		:"cx","si","ax");
@@ -110,11 +110,11 @@
 /* This is faster in a loop on my 386 than using the "neg" instruction. */
 static inline void negate_Xsig(Xsig *x)
 {
-  asm volatile("movl %1,%%esi; "
-               "xorl %%ecx,%%ecx; "
-               "movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi); "
-               "movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi); "
-               "movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi); "
+  asm volatile("movl %1,%%esi;\n"
+               "xorl %%ecx,%%ecx;\n"
+               "movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi);\n"
+               "movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi);\n"
+               "movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi);\n"
                :"=g" (*x):"g" (x):"si","ax","cx");
 }
 
diff -Nru a/arch/i386/math-emu/reg_add_sub.c b/arch/i386/math-emu/reg_add_sub.c
--- a/arch/i386/math-emu/reg_add_sub.c	Fri Oct 11 21:22:58 2002
+++ b/arch/i386/math-emu/reg_add_sub.c	Fri Oct 11 21:22:58 2002
@@ -140,7 +140,7 @@
   FPU_REG const *a, *b;
   FPU_REG *dest;
   u_char taga, tagb, signa, signb, saved_sign, sign;
-  int diff, tag, expa, expb, deststnr;
+  int diff, tag = 0, expa, expb, deststnr;
 
   a = &st(0);
   taga = FPU_gettag0();
diff -Nru a/arch/i386/math-emu/reg_compare.c b/arch/i386/math-emu/reg_compare.c
--- a/arch/i386/math-emu/reg_compare.c	Fri Oct 11 21:23:03 2002
+++ b/arch/i386/math-emu/reg_compare.c	Fri Oct 11 21:23:03 2002
@@ -174,7 +174,7 @@
 /* This function requires that st(0) is not empty */
 int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
 {
-  int f, c;
+  int f = 0, c;
 
   c = compare(loaded_data, loaded_tag);
 
@@ -216,7 +216,7 @@
 
 static int compare_st_st(int nr)
 {
-  int f, c;
+  int f = 0, c;
   FPU_REG *st_ptr;
 
   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
@@ -268,7 +268,7 @@
 
 static int compare_u_st_st(int nr)
 {
-  int f, c;
+  int f = 0, c;
   FPU_REG *st_ptr;
 
   if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
diff -Nru a/arch/i386/math-emu/reg_divide.c b/arch/i386/math-emu/reg_divide.c
--- a/arch/i386/math-emu/reg_divide.c	Fri Oct 11 21:22:59 2002
+++ b/arch/i386/math-emu/reg_divide.c	Fri Oct 11 21:22:59 2002
@@ -203,4 +203,5 @@
     }
 #endif /* PARANOID */ 
 
+	return 0;
 }
diff -Nru a/arch/i386/math-emu/reg_ld_str.c b/arch/i386/math-emu/reg_ld_str.c
--- a/arch/i386/math-emu/reg_ld_str.c	Fri Oct 11 21:23:01 2002
+++ b/arch/i386/math-emu/reg_ld_str.c	Fri Oct 11 21:23:01 2002
@@ -632,7 +632,7 @@
 /* Put a float into user memory */
 int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single)
 {
-  long templ;
+  long templ = 0;
   unsigned long increment = 0;     	/* avoid gcc warnings */
   int precision_loss;
   int exp;
diff -Nru a/arch/i386/math-emu/reg_mul.c b/arch/i386/math-emu/reg_mul.c
--- a/arch/i386/math-emu/reg_mul.c	Fri Oct 11 21:22:55 2002
+++ b/arch/i386/math-emu/reg_mul.c	Fri Oct 11 21:22:55 2002
@@ -128,4 +128,5 @@
     }
 #endif /* PARANOID */ 
 
+	return 0;
 }
diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
--- a/arch/i386/mm/discontig.c	Fri Oct 11 21:22:59 2002
+++ b/arch/i386/mm/discontig.c	Fri Oct 11 21:22:59 2002
@@ -1,5 +1,6 @@
 /*
- * Written by: Patricia Gaughen, IBM Corporation
+ * Written by: Patricia Gaughen <gone@us.ibm.com>, IBM Corporation
+ * August 2002: added remote node KVA remap - Martin J. Bligh 
  *
  * Copyright (C) 2002, IBM Corp.
  *
@@ -19,8 +20,6 @@
  * 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.
- *
- * Send feedback to <gone@us.ibm.com>
  */
 
 #include <linux/config.h>
@@ -113,35 +112,98 @@
 	}
 }
 
+#define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)
+
+unsigned long node_remap_start_pfn[MAX_NUMNODES];
+unsigned long node_remap_size[MAX_NUMNODES];
+unsigned long node_remap_offset[MAX_NUMNODES];
+void *node_remap_start_vaddr[MAX_NUMNODES];
+extern void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
+
+void __init remap_numa_kva(void)
+{
+	void *vaddr;
+	unsigned long pfn;
+	int node;
+
+	for (node = 1; node < numnodes; ++node) {
+		for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) {
+			vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT);
+			set_pmd_pfn((ulong) vaddr, 
+				node_remap_start_pfn[node] + pfn, 
+				PAGE_KERNEL_LARGE);
+		}
+	}
+}
+
+static unsigned long calculate_numa_remap_pages(void)
+{
+	int nid;
+	unsigned long size, reserve_pages = 0;
+
+	for (nid = 1; nid < numnodes; nid++) {
+		/* calculate the size of the mem_map needed in bytes */
+		size = (node_end_pfn[nid] - node_start_pfn[nid] + 1) 
+			* sizeof(struct page);
+		/* convert size to large (pmd size) pages, rounding up */
+		size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES;
+		/* now the roundup is correct, convert to PAGE_SIZE pages */
+		size = size * PTRS_PER_PTE;
+		printk("Reserving %ld pages of KVA for lmem_map of node %d\n",
+				size, nid);
+		node_remap_size[nid] = size;
+		reserve_pages += size;
+		node_remap_offset[nid] = reserve_pages;
+		printk("Shrinking node %d from %ld pages to %ld pages\n",
+			nid, node_end_pfn[nid], node_end_pfn[nid] - size);
+		node_end_pfn[nid] -= size;
+		node_remap_start_pfn[nid] = node_end_pfn[nid];
+	}
+	printk("Reserving total of %ld pages for numa KVA remap\n",
+			reserve_pages);
+	return reserve_pages;
+}
+
 unsigned long __init setup_memory(void)
 {
 	int nid;
 	unsigned long bootmap_size, system_start_pfn, system_max_low_pfn;
+	unsigned long reserve_pages;
 
 	get_memcfg_numa();
+	reserve_pages = calculate_numa_remap_pages();
 
-	/*
-	 * partially used pages are not usable - thus
-	 * we are rounding upwards:
-	 */
+	/* partially used pages are not usable - thus round upwards */
 	system_start_pfn = min_low_pfn = PFN_UP(__pa(&_end));
 
 	find_max_pfn();
 	system_max_low_pfn = max_low_pfn = find_max_low_pfn();
-
 #ifdef CONFIG_HIGHMEM
-		highstart_pfn = highend_pfn = max_pfn;
-		if (max_pfn > system_max_low_pfn) {
-			highstart_pfn = system_max_low_pfn;
-		}
-		printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
-		       pages_to_mb(highend_pfn - highstart_pfn));
+	highstart_pfn = highend_pfn = max_pfn;
+	if (max_pfn > system_max_low_pfn)
+		highstart_pfn = system_max_low_pfn;
+	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+	       pages_to_mb(highend_pfn - highstart_pfn));
 #endif
+	system_max_low_pfn = max_low_pfn = max_low_pfn - reserve_pages;
 	printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
 			pages_to_mb(system_max_low_pfn));
-	
-	for (nid = 0; nid < numnodes; nid++)
+	printk("min_low_pfn = %ld, max_low_pfn = %ld, highstart_pfn = %ld\n", 
+			min_low_pfn, max_low_pfn, highstart_pfn);
+
+	printk("Low memory ends at vaddr %08lx\n",
+			(ulong) pfn_to_kaddr(max_low_pfn));
+	for (nid = 0; nid < numnodes; nid++) {
 		allocate_pgdat(nid);
+		node_remap_start_vaddr[nid] = pfn_to_kaddr(
+			highstart_pfn - node_remap_offset[nid]);
+		printk ("node %d will remap to vaddr %08lx - %08lx\n", nid,
+			(ulong) node_remap_start_vaddr[nid],
+			(ulong) pfn_to_kaddr(highstart_pfn
+			    - node_remap_offset[nid] + node_remap_size[nid]));
+	}
+	printk("High memory starts at vaddr %08lx\n",
+			(ulong) pfn_to_kaddr(highstart_pfn));
 	for (nid = 0; nid < numnodes; nid++)
 		find_max_pfn_node(nid);
 
@@ -244,7 +306,18 @@
 #endif
 			}
 		}
-		free_area_init_node(nid, NODE_DATA(nid), 0, zones_size, start, 0);
+		/*
+		 * We let the lmem_map for node 0 be allocated from the
+		 * normal bootmem allocator, but other nodes come from the
+		 * remapped KVA area - mbligh
+		 */
+		if (nid)
+			free_area_init_node(nid, NODE_DATA(nid), 
+				node_remap_start_vaddr[nid], zones_size, 
+				start, 0);
+		else
+			free_area_init_node(nid, NODE_DATA(nid), 0, 
+				zones_size, start, 0);
 	}
 	return;
 }
@@ -258,7 +331,7 @@
 		unsigned long node_pfn, node_high_size, zone_start_pfn;
 		struct page * zone_mem_map;
 		
-		node_high_size = NODE_DATA(nid)->node_zones[ZONE_HIGHMEM].size;
+		node_high_size = NODE_DATA(nid)->node_zones[ZONE_HIGHMEM].spanned_pages;
 		zone_mem_map = NODE_DATA(nid)->node_zones[ZONE_HIGHMEM].zone_mem_map;
 		zone_start_pfn = NODE_DATA(nid)->node_zones[ZONE_HIGHMEM].zone_start_pfn;
 
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Fri Oct 11 21:22:54 2002
+++ b/arch/i386/mm/init.c	Fri Oct 11 21:22:54 2002
@@ -245,6 +245,12 @@
 
 unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
 
+#ifndef CONFIG_DISCONTIGMEM
+#define remap_numa_kva() do {} while (0)
+#else
+extern void __init remap_numa_kva(void);
+#endif
+
 static void __init pagetable_init (void)
 {
 	unsigned long vaddr;
@@ -269,6 +275,7 @@
 	}
 
 	kernel_physical_mapping_init(pgd_base);
+	remap_numa_kva();
 
 	/*
 	 * Fixed mappings, only the page table structure has to be
@@ -449,7 +456,11 @@
 
 	set_max_mapnr_init();
 
+#ifdef CONFIG_HIGHMEM
+	high_memory = (void *) __va(highstart_pfn * PAGE_SIZE);
+#else
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+#endif
 
 	/* clear the zero-page */
 	memset(empty_zero_page, 0, PAGE_SIZE);
diff -Nru a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
--- a/arch/i386/mm/pgtable.c	Fri Oct 11 21:23:05 2002
+++ b/arch/i386/mm/pgtable.c	Fri Oct 11 21:23:05 2002
@@ -84,6 +84,39 @@
 	__flush_tlb_one(vaddr);
 }
 
+/*
+ * Associate a large virtual page frame with a given physical page frame 
+ * and protection flags for that frame. pfn is for the base of the page,
+ * vaddr is what the page gets mapped to - both must be properly aligned. 
+ * The pmd must already be instantiated. Assumes PAE mode.
+ */ 
+void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+
+	if (vaddr & (PMD_SIZE-1)) {		/* vaddr is misaligned */
+		printk ("set_pmd_pfn: vaddr misaligned\n");
+		return; /* BUG(); */
+	}
+	if (pfn & (PTRS_PER_PTE-1)) {		/* pfn is misaligned */
+		printk ("set_pmd_pfn: pfn misaligned\n");
+		return; /* BUG(); */
+	}
+	pgd = swapper_pg_dir + __pgd_offset(vaddr);
+	if (pgd_none(*pgd)) {
+		printk ("set_pmd_pfn: pgd_none\n");
+		return; /* BUG(); */
+	}
+	pmd = pmd_offset(pgd, vaddr);
+	set_pmd(pmd, pfn_pmd(pfn, flags));
+	/*
+	 * It's enough to flush this one mapping.
+	 * (PGE mappings get flushed as well)
+	 */
+	__flush_tlb_one(vaddr);
+}
+
 void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 {
 	unsigned long address = __fix_to_virt(idx);
diff -Nru a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
--- a/arch/i386/pci/fixup.c	Fri Oct 11 21:22:54 2002
+++ b/arch/i386/pci/fixup.c	Fri Oct 11 21:22:54 2002
@@ -148,7 +148,12 @@
 	pci_read_config_byte(d, PCI_REVISION_ID, &revision);
 
 	if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
-  	        where = 0x95; /* the memory write queue timer register is 
+		/* fix pci bus latency issues resulted by NB bios error
+		   it appears on bug free^Wreduced kt266x's bios forces
+		   NB latency to zero */
+		pci_write_config_byte(d, PCI_LATENCY_TIMER, 0);
+
+		where = 0x95; /* the memory write queue timer register is 
 				different for the KT266x's: 0x95 not 0x55 */
 	} else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
 			(revision == VIA_8363_KL133_REVISION_ID || 
@@ -157,7 +162,7 @@
 					causes screen corruption on the KL133/KM133 */
 	}
 
-        pci_read_config_byte(d, where, &v);
+	pci_read_config_byte(d, where, &v);
 	if (v & ~mask) {
 		printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
 			d->device, revision, where, v, mask, v & mask);
diff -Nru a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
--- a/arch/i386/pci/irq.c	Fri Oct 11 21:23:05 2002
+++ b/arch/i386/pci/irq.c	Fri Oct 11 21:23:05 2002
@@ -472,6 +472,8 @@
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, pirq_piix_get, pirq_piix_set },
 
 	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
 
@@ -492,6 +494,10 @@
 	  pirq_serverworks_get, pirq_serverworks_set },
 	{ "AMD756 VIPER", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B,
 		pirq_amd756_get, pirq_amd756_set },
+	{ "AMD766", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413,
+		pirq_amd756_get, pirq_amd756_set },
+	{ "AMD768", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443,
+		pirq_amd756_get, pirq_amd756_set },
 
 	{ "default", 0, 0, NULL, NULL }
 };
@@ -684,42 +690,7 @@
 	return 1;
 }
 
-static int __init pcibios_irq_init(void)
-{
-	DBG("PCI: IRQ init\n");
-
-	if (pcibios_enable_irq)
-		return 0;
-
-	pirq_table = pirq_find_routing_table();
-
-#ifdef CONFIG_PCI_BIOS
-	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
-		pirq_table = pcibios_get_irq_routing_table();
-#endif
-	if (pirq_table) {
-		pirq_peer_trick();
-		pirq_find_router();
-		if (pirq_table->exclusive_irqs) {
-			int i;
-			for (i=0; i<16; i++)
-				if (!(pirq_table->exclusive_irqs & (1 << i)))
-					pirq_penalty[i] += 100;
-		}
-		/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
-		if (io_apic_assign_pci_irqs)
-			pirq_table = NULL;
-	}
-
-	pcibios_enable_irq = pirq_enable_irq;
-
-	pcibios_fixup_irqs();
-	return 0;
-}
-
-subsys_initcall(pcibios_irq_init);
-
-void __init pcibios_fixup_irqs(void)
+static void __init pcibios_fixup_irqs(void)
 {
 	struct pci_dev *dev;
 	u8 pin;
@@ -784,6 +755,42 @@
 			pcibios_lookup_irq(dev, 0);
 	}
 }
+
+static int __init pcibios_irq_init(void)
+{
+	DBG("PCI: IRQ init\n");
+
+	if (pcibios_enable_irq)
+		return 0;
+
+	pirq_table = pirq_find_routing_table();
+
+#ifdef CONFIG_PCI_BIOS
+	if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
+		pirq_table = pcibios_get_irq_routing_table();
+#endif
+	if (pirq_table) {
+		pirq_peer_trick();
+		pirq_find_router();
+		if (pirq_table->exclusive_irqs) {
+			int i;
+			for (i=0; i<16; i++)
+				if (!(pirq_table->exclusive_irqs & (1 << i)))
+					pirq_penalty[i] += 100;
+		}
+		/* If we're using the I/O APIC, avoid using the PCI IRQ routing table */
+		if (io_apic_assign_pci_irqs)
+			pirq_table = NULL;
+	}
+
+	pcibios_enable_irq = pirq_enable_irq;
+
+	pcibios_fixup_irqs();
+	return 0;
+}
+
+subsys_initcall(pcibios_irq_init);
+
 
 void pcibios_penalize_isa_irq(int irq)
 {
diff -Nru a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
--- a/arch/i386/pci/pci.h	Fri Oct 11 21:22:59 2002
+++ b/arch/i386/pci/pci.h	Fri Oct 11 21:22:59 2002
@@ -69,7 +69,6 @@
 extern int pcibios_scanned;
 extern spinlock_t pci_config_lock;
 
-void pcibios_fixup_irqs(void);
 int pirq_enable_irq(struct pci_dev *dev);
 
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
diff -Nru a/arch/ia64/config.in b/arch/ia64/config.in
--- a/arch/ia64/config.in	Fri Oct 11 21:23:05 2002
+++ b/arch/ia64/config.in	Fri Oct 11 21:23:05 2002
@@ -118,6 +118,10 @@
 tristate '/proc/pal support' CONFIG_IA64_PALINFO
 tristate '/proc/efi/vars support' CONFIG_EFI_VARS
 
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-64)' CONFIG_NR_CPUS 64
+fi
+
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig
--- a/arch/ia64/defconfig	Fri Oct 11 21:22:53 2002
+++ b/arch/ia64/defconfig	Fri Oct 11 21:22:53 2002
@@ -61,6 +61,7 @@
 CONFIG_EFI_VARS=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+CONFIG_NR_CPUS=64
 
 #
 # ACPI Support
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c	Fri Oct 11 21:22:58 2002
+++ b/arch/ia64/hp/sim/simserial.c	Fri Oct 11 21:22:58 2002
@@ -773,7 +773,7 @@
 	struct serial_state *state= info->state;
 	unsigned long page;
 
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
@@ -900,7 +900,7 @@
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
 			/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 			return -ENOMEM;
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Fri Oct 11 21:23:00 2002
+++ b/arch/ia64/ia32/sys_ia32.c	Fri Oct 11 21:23:00 2002
@@ -4049,7 +4049,7 @@
 	memset(karg, 0, sizeof(*karg));
 	if(__get_user(karg->ca_version, &arg32->ca32_version))
 		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+	karg->ca_umap.ug_ident = (char *)get_zeroed_page(GFP_USER);
 	if(!karg->ca_umap.ug_ident)
 		return -ENOMEM;
 	err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident);
diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c	Fri Oct 11 21:22:54 2002
+++ b/arch/ia64/kernel/setup.c	Fri Oct 11 21:22:54 2002
@@ -560,7 +560,7 @@
 	if (cpu == 0)
 		my_cpu_data = alloc_bootmem_pages(__per_cpu_end - __per_cpu_start);
 	else
-		my_cpu_data = (void *) get_free_page(GFP_KERNEL);
+		my_cpu_data = (void *) get_zeroed_page(GFP_KERNEL);
 	memcpy(my_cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start);
 	__per_cpu_offset[cpu] = (char *) my_cpu_data - __per_cpu_start;
 	my_cpu_info = my_cpu_data + ((char *) &__get_cpu_var(cpu_info) - __per_cpu_start);
diff -Nru a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
--- a/arch/m68k/amiga/config.c	Fri Oct 11 21:22:51 2002
+++ b/arch/m68k/amiga/config.c	Fri Oct 11 21:22:51 2002
@@ -33,7 +33,6 @@
 #include <asm/amigaints.h>
 #include <asm/irq.h>
 #include <asm/rtc.h>
-#include <asm/keyboard.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 
@@ -71,11 +70,6 @@
 extern char m68k_debug_device[];
 
 static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *));
-/* amiga specific keyboard functions */
-extern int amiga_keyb_init(void);
-extern int amiga_kbdrate (struct kbd_repeat *);
-extern int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep,
-			       char raw_mode);
 /* amiga specific irq functions */
 extern void amiga_init_IRQ (void);
 extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *);
@@ -94,7 +88,6 @@
 static int a3000_hwclk (int, struct rtc_time *);
 static int a2000_hwclk (int, struct rtc_time *);
 static int amiga_set_clock_mmss (unsigned long);
-extern void amiga_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_AMIGA_FLOPPY
 extern void amiga_floppy_setup(char *, int *);
 #endif
@@ -116,18 +109,6 @@
 	.index =	-1,
 };
 
-#ifdef CONFIG_MAGIC_SYSRQ
-static char amiga_sysrq_xlate[128] =
-	"\0001234567890-=\\\000\000"					/* 0x00 - 0x0f */
-	"qwertyuiop[]\000123"							/* 0x10 - 0x1f */
-	"asdfghjkl;'\000\000456"						/* 0x20 - 0x2f */
-	"\000zxcvbnm,./\000+789"						/* 0x30 - 0x3f */
-	" \177\t\r\r\000\177\000\000\000-\000\000\000\000\000"	/* 0x40 - 0x4f */
-	"\000\201\202\203\204\205\206\207\210\211()/*+\000"	/* 0x50 - 0x5f */
-	"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"	/* 0x60 - 0x6f */
-	"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
-#endif
-
 
     /*
      *  Motherboard Resources present in all Amiga models
@@ -388,11 +369,6 @@
     request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
 
   mach_sched_init      = amiga_sched_init;
-#ifdef CONFIG_VT
-  mach_keyb_init       = amiga_keyb_init;
-  mach_kbdrate         = amiga_kbdrate;
-  mach_kbd_translate   = amiga_kbd_translate;
-#endif
   mach_init_IRQ        = amiga_init_IRQ;
   mach_default_handler = &amiga_default_handler;
   mach_request_irq     = amiga_request_irq;
@@ -432,16 +408,10 @@
 #ifdef CONFIG_DUMMY_CONSOLE
   conswitchp           = &dummy_con;
 #endif
-#ifdef CONFIG_VT
-  kd_mksound           = amiga_mksound;
-#endif
-#ifdef CONFIG_MAGIC_SYSRQ
-  SYSRQ_KEY            = 0xff;
-  mach_sysrq_key = 0x5f;	     /* HELP */
-  mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */
-  mach_sysrq_shift_mask = 0xff;  /* all modifiers except CapsLock */
-  mach_sysrq_xlate = amiga_sysrq_xlate;
+#ifdef CONFIG_INPUT_M68K_BEEP
+  mach_beep            = amiga_mksound;
 #endif
+
 #ifdef CONFIG_HEARTBEAT
   mach_heartbeat = amiga_heartbeat;
 #endif
@@ -709,7 +679,7 @@
   unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
   unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label);
 
-  cli();
+  local_irq_disable();
   if (CPU_IS_040_OR_060)
     /* Setup transparent translation registers for mapping
      * of 16 MB kernel segment before disabling translation
diff -Nru a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
--- a/arch/m68k/atari/atakeyb.c	Fri Oct 11 21:22:59 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,877 +0,0 @@
-/*
- * linux/atari/atakeyb.c
- *
- * Atari Keyboard driver for 680x0 Linux
- *
- * 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.
- */
-
-/*
- * Atari support by Robert de Vries
- * enhanced by Bjoern Brauel and Roman Hodek
- */
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/keyboard.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/kd.h>
-#include <linux/random.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/kbd_kern.h>
-
-#include <asm/atariints.h>
-#include <asm/atarihw.h>
-#include <asm/atarikb.h>
-#include <asm/atari_joystick.h>
-#include <asm/irq.h>
-
-static void atakeyb_rep( unsigned long ignore );
-extern unsigned int keymap_count;
-
-/* Hook for MIDI serial driver */
-void (*atari_MIDI_interrupt_hook) (void);
-/* Hook for mouse driver */
-void (*atari_mouse_interrupt_hook) (char *);
-
-/* variables for IKBD self test: */
-
-/* state: 0: off; >0: in progress; >1: 0xf1 received */
-static volatile int ikbd_self_test;
-/* timestamp when last received a char */
-static volatile unsigned long self_test_last_rcv;
-/* bitmap of keys reported as broken */
-static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
-
-#define BREAK_MASK	(0x80)
-
-/*
- * ++roman: The following changes were applied manually:
- *
- *  - The Alt (= Meta) key works in combination with Shift and
- *    Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
- *    Meta-Ctrl-A (0x81) ...
- *
- *  - The parentheses on the keypad send '(' and ')' with all
- *    modifiers (as would do e.g. keypad '+'), but they cannot be used as
- *    application keys (i.e. sending Esc O c).
- *
- *  - HELP and UNDO are mapped to be F21 and F24, resp, that send the
- *    codes "\E[M" and "\E[P". (This is better than the old mapping to
- *    F11 and F12, because these codes are on Shift+F1/2 anyway.) This
- *    way, applications that allow their own keyboard mappings
- *    (e.g. tcsh, X Windows) can be configured to use them in the way
- *    the label suggests (providing help or undoing).
- *
- *  - Console switching is done with Alt+Fx (consoles 1..10) and
- *    Shift+Alt+Fx (consoles 11..20).
- *
- *  - The misc. special function implemented in the kernel are mapped
- *    to the following key combinations:
- *
- *      ClrHome          -> Home/Find
- *      Shift + ClrHome  -> End/Select
- *      Shift + Up       -> Page Up
- *      Shift + Down     -> Page Down
- *      Alt + Help       -> show system status
- *      Shift + Help     -> show memory info
- *      Ctrl + Help      -> show registers
- *      Ctrl + Alt + Del -> Reboot
- *      Alt + Undo       -> switch to last console
- *      Shift + Undo     -> send interrupt
- *      Alt + Insert     -> stop/start output (same as ^S/^Q)
- *      Alt + Up         -> Scroll back console (if implemented)
- *      Alt + Down       -> Scroll forward console (if implemented)
- *      Alt + CapsLock   -> NumLock
- *
- * ++Andreas:
- *
- *  - Help mapped to K_HELP
- *  - Undo mapped to K_UNDO (= K_F246)
- *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
- */
-
-static u_short ataplain_map[NR_KEYS] __initdata = {
-	0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
-	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
-	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-	0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
-	0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
-	0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
-	0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
-	0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
-	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short atashift_map[NR_KEYS] __initdata = {
-	0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
-	0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf008, 0xf009,
-	0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
-	0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
-	0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
-	0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
-	0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf200,
-	0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
-	0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf200, 0xf200, 0xf117,
-	0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf119, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf205, 0xf203, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short atactrl_map[NR_KEYS] __initdata = {
-	0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
-	0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
-	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-	0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
-	0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-	0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
-	0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
-	0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
-	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short atashift_ctrl_map[NR_KEYS] __initdata = {
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
-	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-	0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
-	0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-	0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
-	0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
-	0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117,
-	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short ataalt_map[NR_KEYS] __initdata = {
-	0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
-	0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf808, 0xf809,
-	0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
-	0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
-	0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
-	0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
-	0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf200,
-	0xf703, 0xf820, 0xf208, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
-	0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf200, 0xf200, 0xf114,
-	0xf20b, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf20a, 0xf200, 0xf209, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf206, 0xf204, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf907,
-	0xf908, 0xf909, 0xf904, 0xf905, 0xf906, 0xf901, 0xf902, 0xf903,
-	0xf900, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short atashift_alt_map[NR_KEYS] __initdata = {
-	0xf200, 0xf81b, 0xf821, 0xf840, 0xf823, 0xf824, 0xf825, 0xf85e,
-	0xf826, 0xf82a, 0xf828, 0xf829, 0xf85f, 0xf82b, 0xf808, 0xf809,
-	0xf851, 0xf857, 0xf845, 0xf852, 0xf854, 0xf859, 0xf855, 0xf849,
-	0xf84f, 0xf850, 0xf87b, 0xf87d, 0xf201, 0xf702, 0xf841, 0xf853,
-	0xf844, 0xf846, 0xf847, 0xf848, 0xf84a, 0xf84b, 0xf84c, 0xf83a,
-	0xf822, 0xf87e, 0xf700, 0xf87c, 0xf85a, 0xf858, 0xf843, 0xf856,
-	0xf842, 0xf84e, 0xf84d, 0xf83c, 0xf83e, 0xf83f, 0xf700, 0xf200,
-	0xf703, 0xf820, 0xf207, 0xf50a, 0xf50b, 0xf50c, 0xf50d, 0xf50e,
-	0xf50f, 0xf510, 0xf511, 0xf512, 0xf513, 0xf200, 0xf200, 0xf117,
-	0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf119, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short atactrl_alt_map[NR_KEYS] __initdata = {
-	0xf200, 0xf200, 0xf200, 0xf800, 0xf81b, 0xf81c, 0xf81d, 0xf81e,
-	0xf81f, 0xf87f, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200,
-	0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
-	0xf80f, 0xf810, 0xf81b, 0xf81d, 0xf201, 0xf702, 0xf801, 0xf813,
-	0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
-	0xf807, 0xf800, 0xf700, 0xf81c, 0xf81a, 0xf818, 0xf803, 0xf816,
-	0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf87f, 0xf700, 0xf200,
-	0xf703, 0xf800, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
-	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short atashift_ctrl_alt_map[NR_KEYS] = {
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200,
-	0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
-	0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
-	0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
-	0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
-	0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf87f, 0xf700, 0xf200,
-	0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117,
-	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
-	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
-	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-typedef enum kb_state_t
-{
-    KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
-} KB_STATE_T;
-
-#define	IS_SYNC_CODE(sc)	((sc) >= 0x04 && (sc) <= 0xfb)
-
-typedef struct keyboard_state
-{
-    unsigned char  buf[6];
-    int 	   len;
-    KB_STATE_T	   state;
-} KEYBOARD_STATE;
-
-KEYBOARD_STATE kb_state;
-
-#define	DEFAULT_KEYB_REP_DELAY	(HZ/4)
-#define	DEFAULT_KEYB_REP_RATE	(HZ/25)
-
-/* These could be settable by some ioctl() in future... */
-static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
-static unsigned int key_repeat_rate  = DEFAULT_KEYB_REP_RATE;
-
-static unsigned char rep_scancode;
-static struct timer_list atakeyb_rep_timer = { function: atakeyb_rep };
-
-static void atakeyb_rep( unsigned long ignore )
-
-{
-	kbd_pt_regs = NULL;
-
-	/* Disable keyboard for the time we call handle_scancode(), else a race
-	 * in the keyboard tty queue may happen */
-	atari_disable_irq( IRQ_MFP_ACIA );
-	del_timer( &atakeyb_rep_timer );
-
-	/* A keyboard int may have come in before we disabled the irq, so
-	 * double-check whether rep_scancode is still != 0 */
-	if (rep_scancode) {
-		init_timer(&atakeyb_rep_timer);
-		atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
-		add_timer( &atakeyb_rep_timer );
-
-		handle_scancode(rep_scancode, 1);
-	}
-
-	atari_enable_irq( IRQ_MFP_ACIA );
-}
-
-
-/* ++roman: If a keyboard overrun happened, we can't tell in general how much
- * bytes have been lost and in which state of the packet structure we are now.
- * This usually causes keyboards bytes to be interpreted as mouse movements
- * and vice versa, which is very annoying. It seems better to throw away some
- * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I
- * introduced the RESYNC state for IKBD data. In this state, the bytes up to
- * one that really looks like a key event (0x04..0xf2) or the start of a mouse
- * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
- * speeds up the resynchronization of the event structure, even if maybe a
- * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
- * it's really hard to decide whether they're mouse or keyboard bytes. Since
- * overruns usually occur when moving the Atari mouse rapidly, they're seen as
- * mouse bytes here. If this is wrong, only a make code of the keyboard gets
- * lost, which isn't too bad. Loosing a break code would be disastrous,
- * because then the keyboard repeat strikes...
- */
-
-static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-  u_char acia_stat;
-  int scancode;
-  int break_flag;
-
-  /* save frame for register dump */
-  kbd_pt_regs = fp;
-
- repeat:
-  if (acia.mid_ctrl & ACIA_IRQ)
-	if (atari_MIDI_interrupt_hook)
-		atari_MIDI_interrupt_hook();
-  acia_stat = acia.key_ctrl;
-  /* check out if the interrupt came from this ACIA */
-  if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
-	return;
-
-    if (acia_stat & ACIA_OVRN)
-    {
-	/* a very fast typist or a slow system, give a warning */
-	/* ...happens often if interrupts were disabled for too long */
-	printk( KERN_DEBUG "Keyboard overrun\n" );
-	scancode = acia.key_data;
-	/* Turn off autorepeating in case a break code has been lost */
-	del_timer( &atakeyb_rep_timer );
-	rep_scancode = 0;
-	if (ikbd_self_test)
-	    /* During self test, don't do resyncing, just process the code */
-	    goto interpret_scancode;
-	else if (IS_SYNC_CODE(scancode)) {
-	    /* This code seem already to be the start of a new packet or a
-	     * single scancode */
-	    kb_state.state = KEYBOARD;
-	    goto interpret_scancode;
-	}
-	else {
-	    /* Go to RESYNC state and skip this byte */
-	    kb_state.state = RESYNC;
-	    kb_state.len = 1; /* skip max. 1 another byte */
-	    goto repeat;
-	}
-    }
-
-    if (acia_stat & ACIA_RDRF)	/* received a character */
-    {
-	scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
-	tasklet_schedule(&keyboard_tasklet);
-      interpret_scancode:
-	switch (kb_state.state)
-	{
-	  case KEYBOARD:
-	    switch (scancode)
-	    {
-	      case 0xF7:
-		kb_state.state = AMOUSE;
-		kb_state.len = 0;
-		break;
-
-	      case 0xF8:
-	      case 0xF9:
-     	      case 0xFA:
-	      case 0xFB:
-		kb_state.state = RMOUSE;
-	    	kb_state.len = 1;
-		kb_state.buf[0] = scancode;
-		break;
-
-	      case 0xFC:
-		kb_state.state = CLOCK;
-		kb_state.len = 0;
-		break;
-
-	      case 0xFE:
-	      case 0xFF:
-		kb_state.state = JOYSTICK;
-		kb_state.len = 1;
-		kb_state.buf[0] = scancode;
-		break;
-
-	      case 0xF1:
-		/* during self-test, note that 0xf1 received */
-		if (ikbd_self_test) {
-		    ++ikbd_self_test;
-		    self_test_last_rcv = jiffies;
-		    break;
-		}
-		/* FALL THROUGH */
-		
-	      default:
-		break_flag = scancode & BREAK_MASK;
-		scancode &= ~BREAK_MASK;
-
-		if (ikbd_self_test) {
-		    /* Scancodes sent during the self-test stand for broken
-		     * keys (keys being down). The code *should* be a break
-		     * code, but nevertheless some AT keyboard interfaces send
-		     * make codes instead. Therefore, simply ignore
-		     * break_flag...
-		     * */
-		    int keyval = plain_map[scancode], keytyp;
-		    
-		    set_bit( scancode, broken_keys );
-		    self_test_last_rcv = jiffies;
-		    keyval = plain_map[scancode];
-		    keytyp = KTYP(keyval) - 0xf0;
-		    keyval = KVAL(keyval);
-
-		    printk( KERN_WARNING "Key with scancode %d ", scancode );
-		    if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
-			if (keyval < ' ')
-			    printk( "('^%c') ", keyval + '@' );
-			else
-			    printk( "('%c') ", keyval );
-		    }
-		    printk( "is broken -- will be ignored.\n" );
-		    break;
-		}
-		else if (test_bit( scancode, broken_keys ))
-		    break;
-
-		if (break_flag) {
-		    del_timer( &atakeyb_rep_timer );
-		    rep_scancode = 0;
-		}
-		else {
-		    del_timer( &atakeyb_rep_timer );
-		    rep_scancode = scancode;
-		    atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
-		    add_timer( &atakeyb_rep_timer );
-		}
-
-		handle_scancode(scancode, !break_flag);
-		break;
-	    }
-	    break;
-
-	  case AMOUSE:
-	    kb_state.buf[kb_state.len++] = scancode;
-	    if (kb_state.len == 5)
-	    {
-		kb_state.state = KEYBOARD;
-		/* not yet used */
-		/* wake up someone waiting for this */
-	    }
-	    break;	
-
-	  case RMOUSE:
-	    kb_state.buf[kb_state.len++] = scancode;
-	    if (kb_state.len == 3)
-	    {
-		kb_state.state = KEYBOARD;
-		if (atari_mouse_interrupt_hook)
-			atari_mouse_interrupt_hook(kb_state.buf);
-	    }
-	    break;
-
-	  case JOYSTICK:
-	    kb_state.buf[1] = scancode;
-	    kb_state.state = KEYBOARD;
-	    atari_joystick_interrupt(kb_state.buf);
-	    break;
-
-	  case CLOCK:
-	    kb_state.buf[kb_state.len++] = scancode;
-	    if (kb_state.len == 6)
-	    {
-		kb_state.state = KEYBOARD;
-		/* wake up someone waiting for this.
-		   But will this ever be used, as Linux keeps its own time.
-		   Perhaps for synchronization purposes? */
-		/* wake_up_interruptible(&clock_wait); */
-	    }
-	    break;
-
-	  case RESYNC:
-	    if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
-		kb_state.state = KEYBOARD;
-		goto interpret_scancode;
-	    }
-	    kb_state.len--;
-	    break;
-	}
-    }
-
-#if 0
-    if (acia_stat & ACIA_CTS)
-	/* cannot happen */;
-#endif
-
-    if (acia_stat & (ACIA_FE | ACIA_PE))
-    {
-	printk("Error in keyboard communication\n");
-    }
-
-    /* handle_scancode() can take a lot of time, so check again if
-	 * some character arrived
-	 */
-    goto repeat;
-}
-
-/*
- * I write to the keyboard without using interrupts, I poll instead.
- * This takes for the maximum length string allowed (7) at 7812.5 baud
- * 8 data 1 start 1 stop bit: 9.0 ms
- * If this takes too long for normal operation, interrupt driven writing
- * is the solution. (I made a feeble attempt in that direction but I
- * kept it simple for now.)
- */
-void ikbd_write(const char *str, int len)
-{
-    u_char acia_stat;
-
-    if ((len < 1) || (len > 7))
-	panic("ikbd: maximum string length exceeded");
-    while (len)
-    {
-	acia_stat = acia.key_ctrl;
-	if (acia_stat & ACIA_TDRE)
-	{
-	    acia.key_data = *str++;
-	    len--;
-	}
-    }
-}
-
-/* Reset (without touching the clock) */
-void ikbd_reset(void)
-{
-    static const char cmd[2] = { 0x80, 0x01 };
-    
-    ikbd_write(cmd, 2);
-
-    /* if all's well code 0xF1 is returned, else the break codes of
-       all keys making contact */
-}
-
-/* Set mouse button action */
-void ikbd_mouse_button_action(int mode)
-{
-    char cmd[2] = { 0x07, mode };
-
-    ikbd_write(cmd, 2);
-}
-
-/* Set relative mouse position reporting */
-void ikbd_mouse_rel_pos(void)
-{
-    static const char cmd[1] = { 0x08 };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Set absolute mouse position reporting */
-void ikbd_mouse_abs_pos(int xmax, int ymax)
-{
-    char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
-
-    ikbd_write(cmd, 5);
-}
-
-/* Set mouse keycode mode */
-void ikbd_mouse_kbd_mode(int dx, int dy)
-{
-    char cmd[3] = { 0x0A, dx, dy };
-
-    ikbd_write(cmd, 3);
-}
-
-/* Set mouse threshold */
-void ikbd_mouse_thresh(int x, int y)
-{
-    char cmd[3] = { 0x0B, x, y };
-
-    ikbd_write(cmd, 3);
-}
-
-/* Set mouse scale */
-void ikbd_mouse_scale(int x, int y)
-{
-    char cmd[3] = { 0x0C, x, y };
-
-    ikbd_write(cmd, 3);
-}
-
-/* Interrogate mouse position */
-void ikbd_mouse_pos_get(int *x, int *y)
-{
-    static const char cmd[1] = { 0x0D };
-
-    ikbd_write(cmd, 1);
-
-    /* wait for returning bytes */
-}
-
-/* Load mouse position */
-void ikbd_mouse_pos_set(int x, int y)
-{
-    char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
-
-    ikbd_write(cmd, 6);
-}
-
-/* Set Y=0 at bottom */
-void ikbd_mouse_y0_bot(void)
-{
-    static const char cmd[1] = { 0x0F };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Set Y=0 at top */
-void ikbd_mouse_y0_top(void)
-{
-    static const char cmd[1] = { 0x10 };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Resume */
-void ikbd_resume(void)
-{
-    static const char cmd[1] = { 0x11 };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Disable mouse */
-void ikbd_mouse_disable(void)
-{
-    static const char cmd[1] = { 0x12 };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Pause output */
-void ikbd_pause(void)
-{
-    static const char cmd[1] = { 0x13 };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Set joystick event reporting */
-void ikbd_joystick_event_on(void)
-{
-    static const char cmd[1] = { 0x14 };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Set joystick interrogation mode */
-void ikbd_joystick_event_off(void)
-{
-    static const char cmd[1] = { 0x15 };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Joystick interrogation */
-void ikbd_joystick_get_state(void)
-{
-    static const char cmd[1] = { 0x16 };
-
-    ikbd_write(cmd, 1);
-}
-
-#if 0
-/* This disables all other ikbd activities !!!! */
-/* Set joystick monitoring */
-void ikbd_joystick_monitor(int rate)
-{
-    static const char cmd[2] = { 0x17, rate };
-
-    ikbd_write(cmd, 2);
-
-    kb_state.state = JOYSTICK_MONITOR;
-}
-#endif
-
-/* some joystick routines not in yet (0x18-0x19) */
-
-/* Disable joysticks */
-void ikbd_joystick_disable(void)
-{
-    static const char cmd[1] = { 0x1A };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Time-of-day clock set */
-void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
-{
-    char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
-
-    ikbd_write(cmd, 7);
-}
-
-/* Interrogate time-of-day clock */
-void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
-{
-    static const char cmd[1] = { 0x1C };
-
-    ikbd_write(cmd, 1);
-}
-
-/* Memory load */
-void ikbd_mem_write(int address, int size, char *data)
-{
-    panic("Attempt to write data into keyboard memory");
-}
-
-/* Memory read */
-void ikbd_mem_read(int address, char data[6])
-{
-    char cmd[3] = { 0x21, address>>8, address&0xFF };
-
-    ikbd_write(cmd, 3);
-
-    /* receive data and put it in data */
-}
-
-/* Controller execute */
-void ikbd_exec(int address)
-{
-    char cmd[3] = { 0x22, address>>8, address&0xFF };
-
-    ikbd_write(cmd, 3);
-}
-
-/* Status inquiries (0x87-0x9A) not yet implemented */
-
-/* Set the state of the caps lock led. */
-void atari_kbd_leds (unsigned int leds)
-{
-    char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
-    ikbd_write(cmd, 6);
-}
-
-/*
- * The original code sometimes left the interrupt line of 
- * the ACIAs low forever. I hope, it is fixed now.
- *
- * Martin Rogge, 20 Aug 1995
- */
- 
-int __init atari_keyb_init(void)
-{
-    /* setup key map */
-    memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
-    memcpy(key_maps[1], atashift_map, sizeof(plain_map));
-    memcpy(key_maps[4], atactrl_map, sizeof(plain_map));
-    memcpy(key_maps[5], atashift_ctrl_map, sizeof(plain_map));
-    memcpy(key_maps[8], ataalt_map, sizeof(plain_map));
-    /* Atari doesn't have an altgr_map, so we can reuse its memory for
-       atashift_alt_map */
-    memcpy(key_maps[2], atashift_alt_map, sizeof(plain_map));
-    key_maps[9]  = key_maps[2];
-    key_maps[2]  = 0; /* ataaltgr_map */
-    memcpy(key_maps[12], atactrl_alt_map, sizeof(plain_map));
-    key_maps[13] = atashift_ctrl_alt_map;
-    keymap_count = 8;
-
-    /* say that we don't have an AltGr key */
-    keyboard_type = KB_84;
-
-    kb_state.state = KEYBOARD;
-    kb_state.len = 0;
-
-    request_irq(IRQ_MFP_ACIA, keyboard_interrupt, IRQ_TYPE_SLOW,
-                "keyboard/mouse/MIDI", keyboard_interrupt);
-
-    atari_turnoff_irq(IRQ_MFP_ACIA);
-    do {
-	/* reset IKBD ACIA */
-	acia.key_ctrl = ACIA_RESET |
-			(atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0;
-	(void)acia.key_ctrl;
-	(void)acia.key_data;
-
-	/* reset MIDI ACIA */
-	acia.mid_ctrl = ACIA_RESET |
-			(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
-	(void)acia.mid_ctrl;
-	(void)acia.mid_data;
-
-	/* divide 500kHz by 64 gives 7812.5 baud */
-	/* 8 data no parity 1 start 1 stop bit */
-	/* receive interrupt enabled */
-	/* RTS low (except if switch selected), transmit interrupt disabled */
-	acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
-			((atari_switches & ATARI_SWITCH_IKBD) ?
-			 ACIA_RHTID : ACIA_RLTID);
-	   
-	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
-			(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
-    }
-    /* make sure the interrupt line is up */
-    while ((mfp.par_dt_reg & 0x10) == 0);
-
-    /* enable ACIA Interrupts */ 
-    mfp.active_edge &= ~0x10;
-    atari_turnon_irq(IRQ_MFP_ACIA);
-
-    ikbd_self_test = 1;
-    ikbd_reset();
-    /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
-     * self-test is finished */
-    self_test_last_rcv = jiffies;
-    while (time_before(jiffies, self_test_last_rcv + HZ/4))
-	barrier();
-    /* if not incremented: no 0xf1 received */
-    if (ikbd_self_test == 1)
-	printk( KERN_ERR "WARNING: keyboard self test failed!\n" );
-    ikbd_self_test = 0;
-    
-    ikbd_mouse_disable();
-    ikbd_joystick_disable();
-
-    atari_joystick_init();
-  
-    return 0;
-}
-
-
-int atari_kbdrate( struct kbd_repeat *k )
-
-{
-	if (k->delay > 0) {
-		/* convert from msec to jiffies */
-		key_repeat_delay = (k->delay * HZ + 500) / 1000;
-		if (key_repeat_delay < 1)
-			key_repeat_delay = 1;
-	}
-	if (k->rate > 0) {
-		key_repeat_rate = (k->rate * HZ + 500) / 1000;
-		if (key_repeat_rate < 1)
-			key_repeat_rate = 1;
-	}
-
-	k->delay = key_repeat_delay * 1000 / HZ;
-	k->rate  = key_repeat_rate  * 1000 / HZ;
-	
-	return( 0 );
-}
-
-int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
-{
-#ifdef CONFIG_MAGIC_SYSRQ
-        /* ALT+HELP pressed? */
-        if ((keycode == 98) && ((shift_state & 0xff) == 8))
-                *keycodep = 0xff;
-        else
-#endif
-                *keycodep = keycode;
-        return 1;
-}
-
diff -Nru a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
--- a/arch/m68k/atari/config.c	Fri Oct 11 21:23:00 2002
+++ b/arch/m68k/atari/config.c	Fri Oct 11 21:23:00 2002
@@ -39,7 +39,6 @@
 #include <asm/atariints.h>
 #include <asm/atari_stram.h>
 #include <asm/system.h>
-#include <asm/keyboard.h>
 #include <asm/machdep.h>
 #include <asm/hwtest.h>
 #include <asm/io.h>
@@ -59,12 +58,6 @@
 static void atari_get_model(char *model);
 static int atari_get_hardware_list(char *buffer);
 
-/* atari specific keyboard functions */
-extern int atari_keyb_init(void);
-extern int atari_kbdrate (struct kbd_repeat *);
-extern int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep,
-			       char raw_mode);
-extern void atari_kbd_leds (unsigned int);
 /* atari specific irq functions */
 extern void atari_init_IRQ (void);
 extern int atari_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -73,7 +66,6 @@
 extern void atari_enable_irq (unsigned int);
 extern void atari_disable_irq (unsigned int);
 extern int show_atari_interrupts (struct seq_file *, void *);
-extern void atari_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_HEARTBEAT
 static void atari_heartbeat( int on );
 #endif
@@ -89,18 +81,6 @@
 /* atari specific debug functions (in debug.c) */
 extern void atari_debug_init(void);
 
-#ifdef CONFIG_MAGIC_SYSRQ
-static char atari_sysrq_xlate[128] =
-	"\000\0331234567890-=\177\t"					/* 0x00 - 0x0f */
-	"qwertyuiop[]\r\000as"							/* 0x10 - 0x1f */
-	"dfghjkl;'`\000\\zxcv"							/* 0x20 - 0x2f */
-	"bnm,./\000\000\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
-	"\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */
-	"\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-	"\000\000\000()/*789456123"						/* 0x60 - 0x6f */
-	"0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 0x70 - 0x7f */
-#endif
-
 
 /* I've moved hwreg_present() and hwreg_present_bywrite() out into
  * mm/hwtest.c, to avoid having multiple copies of the same routine
@@ -254,12 +234,6 @@
                                            to 4GB. */
 
     mach_sched_init      = atari_sched_init;
-#ifdef CONFIG_VT
-    mach_keyb_init       = atari_keyb_init;
-    mach_kbdrate         = atari_kbdrate;
-    mach_kbd_translate   = atari_kbd_translate;
-    mach_kbd_leds        = atari_kbd_leds;
-#endif
     mach_init_IRQ        = atari_init_IRQ;
     mach_request_irq     = atari_request_irq;
     mach_free_irq        = atari_free_irq;
@@ -277,15 +251,8 @@
     conswitchp	         = &dummy_con;
 #endif
     mach_max_dma_address = 0xffffff;
-#ifdef CONFIG_VT
-    kd_mksound		 = atari_mksound;
-#endif
-#ifdef CONFIG_MAGIC_SYSRQ
-    SYSRQ_KEY            = 0xff;
-    mach_sysrq_key = 98;          /* HELP */
-    mach_sysrq_shift_state = 8;   /* Alt */
-    mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */
-    mach_sysrq_xlate = atari_sysrq_xlate;
+#ifdef CONFIG_INPUT_M68K_BEEP
+    mach_beep          = atari_mksound;
 #endif
 #ifdef CONFIG_HEARTBEAT
     mach_heartbeat = atari_heartbeat;
diff -Nru a/arch/m68k/atari/joystick.c b/arch/m68k/atari/joystick.c
--- a/arch/m68k/atari/joystick.c	Fri Oct 11 21:22:51 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,144 +0,0 @@
-/*
- * Atari Joystick Driver for Linux
- * by Robert de Vries (robert@and.nl) 19Jul93
- *
- * 16 Nov 1994 Andreas Schwab
- * Support for three button mouse (shamelessly stolen from MiNT)
- * third button wired to one of the joystick directions on joystick 1
- */
-
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/major.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/smp_lock.h>
-
-#include <asm/atarikb.h>
-#include <asm/atari_joystick.h>
-#include <asm/uaccess.h>
-
-#define MAJOR_NR    JOYSTICK_MAJOR
-
-#define	ANALOG_JOY(n)	(!(n & 0x80))
-#define	DIGITAL_JOY(n)	(minor(n) & 0x80)
-#define	DEVICE_NR(n)	(minor(n) & 0x7f)
-
-
-static struct joystick_status joystick[2];
-int atari_mouse_buttons; /* for three-button mouse */
-
-void atari_joystick_interrupt(char *buf)
-{
-    int j;
-/*    ikbd_joystick_disable(); */
-
-    j = buf[0] & 0x1;
-    joystick[j].dir   = buf[1] & 0xF;
-    joystick[j].fire  = (buf[1] & 0x80) >> 7;
-    joystick[j].ready = 1;
-    wake_up_interruptible(&joystick[j].wait);
-
-    /* For three-button mouse emulation fake a mouse packet */
-    if (atari_mouse_interrupt_hook &&
-	j == 1 && (buf[1] & 1) != ((atari_mouse_buttons & 2) >> 1))
-      {
-	char faked_packet[3];
-
-	atari_mouse_buttons = (atari_mouse_buttons & 5) | ((buf[1] & 1) << 1);
-	faked_packet[0] = (atari_mouse_buttons & 1) | 
-			  (atari_mouse_buttons & 4 ? 2 : 0);
-	faked_packet[1] = 0;
-	faked_packet[2] = 0;
-	atari_mouse_interrupt_hook (faked_packet);
-      }
-
-/*    ikbd_joystick_event_on(); */
-}
-
-static int release_joystick(struct inode *inode, struct file *file)
-{
-    int minor = DEVICE_NR(inode->i_rdev);
-
-    joystick[minor].active = 0;
-    joystick[minor].ready = 0;
-
-    if ((joystick[0].active == 0) && (joystick[1].active == 0))
-	ikbd_joystick_disable();
-    return 0;
-}
-
-static int open_joystick(struct inode *inode, struct file *file)
-{
-    int minor = DEVICE_NR(inode->i_rdev);
-
-    if (!DIGITAL_JOY(inode->i_rdev) || minor > 1)
-	return -ENODEV;
-    if (joystick[minor].active)
-	return -EBUSY;
-    joystick[minor].active = 1;
-    joystick[minor].ready = 0;
-    ikbd_joystick_event_on();
-    return 0;
-}
-
-static ssize_t write_joystick(struct file *file, const char *buffer,
-			      size_t count, loff_t *ppos)
-{
-    return -EINVAL;
-}
-
-static ssize_t read_joystick(struct file *file, char *buffer, size_t count,
-			     loff_t *ppos)
-{
-    struct inode *inode = file->f_dentry->d_inode;
-    int minor = DEVICE_NR(inode->i_rdev);
-
-    if (count < 2)
-	return -EINVAL;
-    if (!joystick[minor].ready)
-	return -EAGAIN;
-    joystick[minor].ready = 0;
-    if (put_user(joystick[minor].fire, buffer++) ||
-	put_user(joystick[minor].dir, buffer++))
-	return -EFAULT;
-    if (count > 2)
-	if (clear_user(buffer, count - 2))
-	    return -EFAULT;
-    return count;
-}
-
-static unsigned int joystick_poll(struct file *file, poll_table *wait)
-{
-    int minor = DEVICE_NR(file->f_dentry->d_inode->i_rdev);
-
-    poll_wait(file, &joystick[minor].wait, wait);
-    if (joystick[minor].ready)
-	return POLLIN | POLLRDNORM;
-    return 0;
-}
-
-struct file_operations atari_joystick_fops = {
-	.read =		read_joystick,
-	.write =	write_joystick,
-	.poll =		joystick_poll,
-	.open =		open_joystick,
-	.release =	release_joystick,
-};
-
-int __init atari_joystick_init(void)
-{
-    joystick[0].active = joystick[1].active = 0;
-    joystick[0].ready = joystick[1].ready = 0;
-    init_waitqueue_head(&joystick[0].wait);
-    init_waitqueue_head(&joystick[1].wait);
-
-    if (register_chrdev(MAJOR_NR, "Joystick", &atari_joystick_fops))
-	printk("unable to get major %d for joystick devices\n", MAJOR_NR);
-    devfs_register_series (NULL, "joysticks/digital%u", 2, DEVFS_FL_DEFAULT,
-			   MAJOR_NR, 128, S_IFCHR | S_IRUSR | S_IWUSR,
-			   &atari_joystick_fops, NULL);
-
-    return 0;
-}
diff -Nru a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
--- a/arch/m68k/bvme6000/config.c	Fri Oct 11 21:23:00 2002
+++ b/arch/m68k/bvme6000/config.c	Fri Oct 11 21:23:00 2002
@@ -45,12 +45,9 @@
 static int  bvme6000_get_hardware_list(char *buffer);
 extern int  bvme6000_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void bvme6000_sched_init(void (*handler)(int, void *, struct pt_regs *));
-extern int  bvme6000_keyb_init(void);
-extern int  bvme6000_kbdrate (struct kbd_repeat *);
 extern unsigned long bvme6000_gettimeoffset (void);
 extern int bvme6000_hwclk (int, struct rtc_time *);
 extern int bvme6000_set_clock_mmss (unsigned long);
-extern void bvme6000_mksound( unsigned int count, unsigned int ticks );
 extern void bvme6000_reset (void);
 extern void bvme6000_waitbut(void);
 void bvme6000_set_vectors (void);
@@ -72,15 +69,6 @@
 		return 1;
 }
 
-int bvme6000_kbdrate (struct kbd_repeat *k)
-{
-	return 0;
-}
-
-void bvme6000_mksound( unsigned int count, unsigned int ticks )
-{
-}
-
 void bvme6000_reset()
 {
 	volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
@@ -133,15 +121,10 @@
 
     mach_max_dma_address = 0xffffffff;
     mach_sched_init      = bvme6000_sched_init;
-#ifdef CONFIG_VT
-    mach_keyb_init       = bvme6000_keyb_init;
-    mach_kbdrate         = bvme6000_kbdrate;
-#endif
     mach_init_IRQ        = bvme6000_init_IRQ;
     mach_gettimeoffset   = bvme6000_gettimeoffset;
     mach_hwclk           = bvme6000_hwclk;
     mach_set_clock_mmss	 = bvme6000_set_clock_mmss;
-/*  mach_mksound         = bvme6000_mksound; */
     mach_reset		 = bvme6000_reset;
     mach_free_irq	 = bvme6000_free_irq;
     mach_process_int	 = bvme6000_process_int;
@@ -394,8 +377,3 @@
 	return retval;
 }
 
-
-int bvme6000_keyb_init (void)
-{
-	return 0;
-}
diff -Nru a/arch/m68k/config.in b/arch/m68k/config.in
--- a/arch/m68k/config.in	Fri Oct 11 21:23:02 2002
+++ b/arch/m68k/config.in	Fri Oct 11 21:23:02 2002
@@ -3,6 +3,7 @@
 # see Documentation/kbuild/config-language.txt.
 #
 
+define_bool CONFIG_M68K y
 define_bool CONFIG_UID16 y
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
diff -Nru a/arch/m68k/hp300/config.c b/arch/m68k/hp300/config.c
--- a/arch/m68k/hp300/config.c	Fri Oct 11 21:22:52 2002
+++ b/arch/m68k/hp300/config.c	Fri Oct 11 21:22:52 2002
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <asm/machdep.h>
 #include <asm/blinken.h>
-#include <asm/io.h>                               /* readb() and writeb() */
 #include <asm/hwtest.h>                           /* hwreg_present() */
 
 #include "ints.h"
@@ -27,14 +26,6 @@
 extern void (*hp300_default_handler[])(int, void *, struct pt_regs *);
 extern int show_hp300_interrupts(struct seq_file *, void *);
 
-#ifdef CONFIG_VT
-extern int hp300_keyb_init(void);
-static int hp300_kbdrate(struct kbd_repeat *k)
-{
-  return 0;
-}
-#endif
-
 #ifdef CONFIG_HEARTBEAT
 static void hp300_pulse(int x)
 {
@@ -53,10 +44,6 @@
 void __init config_hp300(void)
 {
   mach_sched_init      = hp300_sched_init;
-#ifdef CONFIG_VT
-  mach_keyb_init       = hp300_keyb_init;
-  mach_kbdrate         = hp300_kbdrate;
-#endif
   mach_init_IRQ        = hp300_init_IRQ;
   mach_request_irq     = hp300_request_irq;
   mach_free_irq        = hp300_free_irq;
diff -Nru a/arch/m68k/hp300/hil.c b/arch/m68k/hp300/hil.c
--- a/arch/m68k/hp300/hil.c	Fri Oct 11 21:23:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,344 +0,0 @@
-/*
- *  linux/arch/m68k/hp300/hil.c
- *
- *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
- *
- *  HP300 Human Interface Loop driver.  This handles the keyboard and mouse.
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/keyboard.h>
-#include <linux/kbd_ll.h>
-#include <asm/io.h>
-#include <asm/hwtest.h>
-#include <asm/ptrace.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#define HILBASE			0xf0428000
-#define HIL_DATA			0x1
-#define HIL_CMD			0x3
-
-#define	HIL_BUSY		0x02
-#define	HIL_DATA_RDY		0x01
-
-#define hil_busy()		(readb(HILBASE + HIL_CMD) & HIL_BUSY)
-#define hil_data_available()	(readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
-#define hil_status()		(readb(HILBASE + HIL_CMD))
-#define hil_command(x)		do { writeb((x), HILBASE + HIL_CMD); } while (0)
-#define hil_read_data()		(readb(HILBASE + HIL_DATA))
-#define hil_write_data(x)	do { writeb((x), HILBASE + HIL_DATA); } while (0)
-
-#define	HIL_SETARD		0xA0		/* set auto-repeat delay */
-#define	HIL_SETARR		0xA2		/* set auto-repeat rate */
-#define	HIL_SETTONE		0xA3		/* set tone generator */
-#define	HIL_CNMT		0xB2		/* clear nmi */
-#define	HIL_INTON		0x5C		/* Turn on interrupts. */
-#define	HIL_INTOFF		0x5D		/* Turn off interrupts. */
-#define	HIL_TRIGGER		0xC5		/* trigger command */
-#define	HIL_STARTCMD		0xE0		/* start loop command */
-#define	HIL_TIMEOUT		0xFE		/* timeout */
-#define	HIL_READTIME		0x13		/* Read real time register */
-
-#define	HIL_READBUSY		0x02		/* internal "busy" register */
-#define	HIL_READKBDLANG		0x12		/* read keyboard language code */
-#define	HIL_READKBDSADR	 	0xF9
-#define	HIL_WRITEKBDSADR 	0xE9
-#define	HIL_READLPSTAT  	0xFA
-#define	HIL_WRITELPSTAT 	0xEA
-#define	HIL_READLPCTRL  	0xFB
-#define	HIL_WRITELPCTRL 	0xEB
-
-#define HIL_IRQ			1
-
-#define plain_map		hp_plain_map
-#define shift_map		hp_shift_map
-#define altgr_map		hp_altgr_map
-#define ctrl_map		hp_ctrl_map
-#define shift_ctrl_map		hp_shift_ctrl_map
-#define alt_map			hp_alt_map
-#define ctrl_alt_map		hp_ctrl_alt_map
-
-u_short plain_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb62,	0xfb76,	0xfb63,	0xfb78,	0xfb7a,	0xf200,	0xf200,	0xf01b,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb68,	0xfb67,	0xfb66,	0xfb64,	0xfb73,	0xfb61,	0xf200,	0xf207,
-	0xfb75,	0xfb79,	0xfb74,	0xfb72,	0xfb65,	0xfb77,	0xfb71,	0xf009,
-	0xf037,	0xf036,	0xf035,	0xf034,	0xf033,	0xf032,	0xf031,	0xf060,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
-	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf008,	0xf200,	0xf200,
-	0xfb69,	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf05c,	0xf200,	0xf200,
-	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,	0xf027,	0xf201,	0xf200,	0xf200,
-	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb6e,	0xf020,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
-};
-
-u_short shift_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb42,	0xfb56,	0xfb43,	0xfb58,	0xfb5a,	0xf200,	0xf200,	0xf07f,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb48,	0xfb47,	0xfb46,	0xfb44,	0xfb53,	0xfb41,	0xf200,	0xf207,
-	0xfb55,	0xfb59,	0xfb54,	0xfb52,	0xfb45,	0xfb57,	0xfb51,	0xf009,
-	0xf026,	0xf05e,	0xf025,	0xf024,	0xf023,	0xf040,	0xf021,	0xf07e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
-	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf200,	0xf200,	0xf200,
-	0xfb49,	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf07c,	0xf200,	0xf200,
-	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,	0xf201,	0xf200,	0xf200,
-	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb4e,	0xf020,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
-};
-
-u_short altgr_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb62,	0xfb76,	0xfb63,	0xfb78,	0xfb7a,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb68,	0xfb67,	0xfb66,	0xfb64,	0xfb73,	0xfb61,	0xf200,	0xf207,
-	0xfb75,	0xfb79,	0xfb74,	0xfb72,	0xfb65,	0xfb77,	0xfb71,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf040,	0xf021,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
-	0xf02a,	0xf05b,	0xf05d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb69,	0xfb6f,	0xfb70,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
-	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xfb6e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
-};
-
-u_short ctrl_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf002,	0xf016,	0xf003,	0xf018,	0xf01a,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf008,	0xf007,	0xf006,	0xf004,	0xf013,	0xf001,	0xf200,	0xf207,
-	0xf015,	0xf019,	0xf014,	0xf012,	0xf005,	0xf017,	0xf011,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf000,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf503,	0xf502,	0xf501,	0xf500,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf504,	0xf505,	0xf506,	0xf507,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf01c,	0xf200,	0xf200,
-	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,	0xf201,	0xf200,	0xf200,
-	0xf00d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf00e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf002,	0xf016,	0xf003,	0xf018,	0xf01a,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf008,	0xf007,	0xf006,	0xf004,	0xf013,	0xf001,	0xf200,	0xf207,
-	0xf015,	0xf019,	0xf014,	0xf012,	0xf005,	0xf017,	0xf011,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
-	0xf00d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf00e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
-};
-
-u_short alt_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf862,	0xf876,	0xf863,	0xf878,	0xf87a,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf868,	0xf867,	0xf866,	0xf864,	0xf873,	0xf861,	0xf200,	0xf207,
-	0xf875,	0xf879,	0xf874,	0xf872,	0xf865,	0xf877,	0xf871,	0xf809,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf860,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf869,	0xf86f,	0xf870,	0xf200,	0xf200,	0xf85c,	0xf200,	0xf200,
-	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,	0xf201,	0xf200,	0xf200,
-	0xf86d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf86e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf802,	0xf816,	0xf803,	0xf818,	0xf81a,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf808,	0xf807,	0xf806,	0xf804,	0xf813,	0xf801,	0xf200,	0xf207,
-	0xf815,	0xf819,	0xf814,	0xf812,	0xf805,	0xf817,	0xf811,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf809,	0xf80f,	0xf810,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
-	0xf80d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf80e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
-};
-
-#undef plain_map
-#undef ctrl_alt_map
-#undef shift_map
-#undef altgr_map
-#undef ctrl_map
-#undef shift_ctrl_map
-#undef alt_map
-
-struct {
-  unsigned char s, c;
-  int valid;
-} hil_last;
-
-#define hil_getlast(s,c)  do { s = hil_last.s; c = hil_last.c; hil_last.valid = 0; } while (0)
-
-struct {
-  unsigned char data[16];
-  unsigned int ptr;
-} poll;
-
-unsigned char curdev = 0;
-
-static void poll_finished(void)
-{
-  switch (poll.data[0])
-  {
-  case 0x40:
-    {
-      int down = (poll.data[1] & 1) == 0;
-      unsigned char scode = poll.data[1] >> 1;
-#if 0
-      if (down)
-	printk("[%02x]", scode);
-#endif
-      handle_scancode(scode, down);
-    }
-    break;
-  }
-  curdev = 0;
-}
-
-static inline void handle_status(unsigned char s, unsigned char c)
-{
-  if (c & 0x8) {
-    /* End of block */
-    if (c & 0x10)
-      poll_finished();
-  } else {
-    if (c & 0x10) {
-      if (curdev)
-	poll_finished();		/* just in case */
-      curdev = c & 7;
-      poll.ptr = 0;
-    }
-  }
-}
-
-static inline void handle_data(unsigned char s, unsigned char c)
-{
-  if (curdev)
-    poll.data[poll.ptr++] = c;
-}
-
-/* 
- * Handle HIL interrupts.
- */
-
-static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
-{
-  unsigned char s, c;
-  s = hil_status(); c = hil_read_data();
-  switch (s >> 4)
-  {
-  case 0x5:
-    handle_status(s, c);
-    break;
-  case 0x6:
-    handle_data(s, c);
-    break;
-  case 0x4:
-    hil_last.s = s;
-    hil_last.c = c;
-    mb();
-    hil_last.valid = 1;
-    break;
-  }
-}
-
-/*
- * Send a command to the HIL
- */
-
-static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
-{
-  unsigned long flags;
-  save_flags(flags); cli();
-  while (hil_busy());
-  hil_command(cmd);
-  while (len--) {
-    while (hil_busy());
-    hil_write_data(*(data++));
-  }
-  restore_flags(flags);
-}
-
-/*
- * Initialise HIL. 
- */
-
-int __init hp300_keyb_init(void)
-{
-  unsigned char s, c, kbid;
-  unsigned int n = 0;
-
-  memcpy(key_maps[0], hp_plain_map, sizeof(plain_map));
-  memcpy(key_maps[1], hp_shift_map, sizeof(plain_map));
-  memcpy(key_maps[4], hp_ctrl_map, sizeof(plain_map));
-
-  if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
-    return 1;		/* maybe this can happen */
-
-  request_irq(HIL_IRQ, hil_interrupt, 0, "HIL", NULL);
-
-  /* Turn on interrupts */
-  hil_do(HIL_INTON, NULL, 0);
-
-  /* Look for keyboards */
-  hil_do(HIL_READKBDSADR, NULL, 0);
-  while (!hil_last.valid) {
-    if (n++ > 100000) {
-      printk("HIL: timed out, assuming no keyboard present.\n");
-      return 1;
-    }
-    mb();
-  }
-  hil_getlast(s, c);
-  if (c == 0) {
-    printk("HIL: no keyboard present.\n");
-    return 1;
-  }
-  for (kbid = 0; (kbid < 8) && ((c & (1<<kbid)) == 0); kbid++);
-  printk("HIL: keyboard found at id %d\n", kbid);
-  /* set it to raw mode */
-  c = 0;
-  hil_do(HIL_WRITEKBDSADR, &c, 1);
-  return 0;
-}
diff -Nru a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
--- a/arch/m68k/kernel/setup.c	Fri Oct 11 21:23:04 2002
+++ b/arch/m68k/kernel/setup.c	Fri Oct 11 21:23:04 2002
@@ -71,13 +71,6 @@
 char m68k_debug_device[6] = "";
 
 void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
-/* machine dependent keyboard functions */
-#ifdef CONFIG_VT
-int (*mach_keyb_init) (void) __initdata = NULL;
-int (*mach_kbdrate) (struct kbd_repeat *) = NULL;
-void (*mach_kbd_leds) (unsigned int) = NULL;
-int (*mach_kbd_translate)(unsigned char scancode, unsigned char *keycode, char raw_mode) = NULL;
-#endif
 /* machine dependent irq functions */
 void (*mach_init_IRQ) (void) __initdata = NULL;
 void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL;
@@ -89,6 +82,8 @@
 unsigned long (*mach_gettimeoffset) (void);
 int (*mach_hwclk) (int, struct rtc_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
+int (*mach_get_rtc_pll)(struct rtc_pll_info *) = NULL;
+int (*mach_set_rtc_pll)(struct rtc_pll_info *) = NULL;
 void (*mach_reset)( void );
 void (*mach_halt)( void ) = NULL;
 void (*mach_power_off)( void ) = NULL;
@@ -103,15 +98,9 @@
 #ifdef CONFIG_M68K_L2_CACHE
 void (*mach_l2_flush) (int) = NULL;
 #endif
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned int SYSRQ_KEY;
-int mach_sysrq_key = -1;
-int mach_sysrq_shift_state = 0;
-int mach_sysrq_shift_mask = 0;
-char *mach_sysrq_xlate = NULL;
+#ifdef CONFIG_INPUT_M68K_BEEP
+void (*mach_beep)(unsigned int, unsigned int) = NULL;
 #endif
-
 #if defined(CONFIG_ISA) && defined(MULTI_ISA)
 int isa_type;
 int isa_sex;
diff -Nru a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
--- a/arch/m68k/mac/config.c	Fri Oct 11 21:22:56 2002
+++ b/arch/m68k/mac/config.c	Fri Oct 11 21:22:56 2002
@@ -78,27 +78,12 @@
 extern void psc_init(void);
 extern void baboon_init(void);
 
-extern void mac_mksound(unsigned int, unsigned int);
-
 extern void nubus_sweep_video(void);
 
 /* Mac specific debug functions (in debug.c) */
 extern void mac_debug_init(void);
 extern void mac_debugging_long(int, long);
 
-extern int mackbd_init_hw(void);
-extern void mackbd_leds(unsigned int leds);
-extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode);
-
-extern void mac_hid_init_hw(void);
-extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode);
-
-#ifdef CONFIG_MAGIC_SYSRQ
-extern unsigned char mac_hid_kbd_sysrq_xlate[128];
-extern unsigned char pckbd_sysrq_xlate[128];
-extern unsigned char mackbd_sysrq_xlate[128];
-#endif /* CONFIG_MAGIC_SYSRQ */
-
 static void mac_get_model(char *str);
 
 void mac_bang(int irq, void *vector, struct pt_regs *p)
@@ -207,33 +192,6 @@
 	  printk("ERROR: no Mac, but config_mac() called!! \n");
 	}
 
-#ifdef CONFIG_VT
-#ifdef CONFIG_INPUT_ADBHID
-	mach_keyb_init       = mac_hid_init_hw;
-	mach_kbd_translate   = mac_hid_kbd_translate;
-#ifdef CONFIG_MAGIC_SYSRQ
-#ifdef CONFIG_MAC_ADBKEYCODES
-	if (!keyboard_sends_linux_keycodes) {
-		mach_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
-		SYSRQ_KEY = 0x69;
-	} else
-#endif /* CONFIG_MAC_ADBKEYCODES */
-	{
-		mach_sysrq_xlate = pckbd_sysrq_xlate;
-		SYSRQ_KEY = 0x54;
-	}
-#endif /* CONFIG_MAGIC_SYSRQ */
-#elif defined(CONFIG_ADB_KEYBOARD)
-	mach_keyb_init       = mackbd_init_hw;
-	mach_kbd_leds        = mackbd_leds;
-	mach_kbd_translate   = mackbd_translate;
-#ifdef CONFIG_MAGIC_SYSRQ
-	mach_sysrq_xlate     = mackbd_sysrq_xlate;
-	SYSRQ_KEY = 0x69;
-#endif /* CONFIG_MAGIC_SYSRQ */
-#endif /* CONFIG_INPUT_ADBHID */
-#endif /* CONFIG_VT */
-
 	mach_sched_init      = mac_sched_init;
 	mach_init_IRQ        = mac_init_IRQ;
 	mach_request_irq     = mac_request_irq;
@@ -249,9 +207,6 @@
 	mach_hwclk           = mac_hwclk;
 #endif
 	mach_set_clock_mmss	 = mac_set_clock_mmss;
-#if 0
-	mach_mksound         = mac_mksound;
-#endif
 	mach_reset           = mac_reset;
 	mach_halt            = mac_poweroff;
 	mach_power_off       = mac_poweroff;
@@ -262,8 +217,8 @@
 #if 0
 	mach_debug_init	 = mac_debug_init;
 #endif
-#ifdef CONFIG_VT
-	kd_mksound		 = mac_mksound;
+#ifdef CONFIG_INPUT_M68K_BEEP
+        mach_beep            = mac_mksound;
 #endif
 #ifdef CONFIG_HEARTBEAT
 #if 0
@@ -287,10 +242,6 @@
 	    || macintosh_config->ident == MAC_MODEL_IIFX) {
 		mach_l2_flush = mac_cache_card_flush;
 	}
-#ifdef MAC_DEBUG_SOUND
-	/* goes on forever if timers broken */
-	mac_mksound(1000,10);
-#endif
 
 	/*
 	 * Check for machine specific fixups.
diff -Nru a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
--- a/arch/m68k/mm/memory.c	Fri Oct 11 21:23:00 2002
+++ b/arch/m68k/mm/memory.c	Fri Oct 11 21:23:00 2002
@@ -80,7 +80,7 @@
 		void *page;
 		ptable_desc *new;
 
-		if (!(page = (void *)get_free_page(GFP_KERNEL)))
+		if (!(page = (void *)get_zeroed_page(GFP_KERNEL)))
 			return 0;
 
 		flush_tlb_kernel_page(page);
diff -Nru a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
--- a/arch/m68k/mvme147/config.c	Fri Oct 11 21:22:55 2002
+++ b/arch/m68k/mvme147/config.c	Fri Oct 11 21:22:55 2002
@@ -45,8 +45,6 @@
 static int  mvme147_get_hardware_list(char *buffer);
 extern int mvme147_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void mvme147_sched_init(void (*handler)(int, void *, struct pt_regs *));
-extern int mvme147_keyb_init(void);
-extern int mvme147_kbdrate (struct kbd_repeat *);
 extern unsigned long mvme147_gettimeoffset (void);
 extern int mvme147_hwclk (int, struct rtc_time *);
 extern int mvme147_set_clock_mmss (unsigned long);
@@ -70,11 +68,6 @@
 		return 1;
 }
 
-int mvme147_kbdrate (struct kbd_repeat *k)
-{
-	return 0;
-}
-
 void mvme147_reset()
 {
 	printk ("\r\n\nCalled mvme147_reset\r\n");
@@ -102,10 +95,6 @@
 {
 	mach_max_dma_address	= 0x01000000;
 	mach_sched_init		= mvme147_sched_init;
-#ifdef CONFIG_VT
-	mach_keyb_init		= mvme147_keyb_init;
-	mach_kbdrate		= mvme147_kbdrate;
-#endif
 	mach_init_IRQ		= mvme147_init_IRQ;
 	mach_gettimeoffset	= mvme147_gettimeoffset;
 	mach_hwclk		= mvme147_hwclk;
diff -Nru a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
--- a/arch/m68k/mvme16x/config.c	Fri Oct 11 21:22:55 2002
+++ b/arch/m68k/mvme16x/config.c	Fri Oct 11 21:22:55 2002
@@ -49,12 +49,9 @@
 static int  mvme16x_get_hardware_list(char *buffer);
 extern int  mvme16x_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
 extern void mvme16x_sched_init(void (*handler)(int, void *, struct pt_regs *));
-extern int  mvme16x_keyb_init(void);
-extern int  mvme16x_kbdrate (struct kbd_repeat *);
 extern unsigned long mvme16x_gettimeoffset (void);
 extern int mvme16x_hwclk (int, struct rtc_time *);
 extern int mvme16x_set_clock_mmss (unsigned long);
-extern void mvme16x_mksound( unsigned int count, unsigned int ticks );
 extern void mvme16x_reset (void);
 extern void mvme16x_waitbut(void);
 
@@ -77,15 +74,6 @@
 		return 1;
 }
 
-int mvme16x_kbdrate (struct kbd_repeat *k)
-{
-	return 0;
-}
-
-void mvme16x_mksound( unsigned int count, unsigned int ticks )
-{
-}
-
 void mvme16x_reset()
 {
 	printk ("\r\n\nCalled mvme16x_reset\r\n"
@@ -144,17 +132,10 @@
 
     mach_max_dma_address = 0xffffffff;
     mach_sched_init      = mvme16x_sched_init;
-#ifdef CONFIG_VT
-    mach_keyb_init       = mvme16x_keyb_init;
-    mach_kbdrate         = mvme16x_kbdrate;
-#endif
     mach_init_IRQ        = mvme16x_init_IRQ;
     mach_gettimeoffset   = mvme16x_gettimeoffset;
     mach_hwclk           = mvme16x_hwclk;
     mach_set_clock_mmss	 = mvme16x_set_clock_mmss;
-#ifdef CONFIG_VT
-/*  kd_mksound           = mvme16x_mksound; */
-#endif
     mach_reset		 = mvme16x_reset;
     mach_free_irq	 = mvme16x_free_irq;
     mach_process_int	 = mvme16x_process_int;
@@ -297,11 +278,6 @@
 }
 
 int mvme16x_set_clock_mmss (unsigned long nowtime)
-{
-	return 0;
-}
-
-int mvme16x_keyb_init (void)
 {
 	return 0;
 }
diff -Nru a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
--- a/arch/m68k/q40/config.c	Fri Oct 11 21:22:58 2002
+++ b/arch/m68k/q40/config.c	Fri Oct 11 21:22:58 2002
@@ -36,12 +36,9 @@
 #include <asm/rtc.h>
 #include <asm/machdep.h>
 #include <asm/q40_master.h>
-#include <asm/keyboard.h>
 
 extern void floppy_setup(char *str, int *ints);
 
-extern int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
-			    char raw_mode);
 extern void q40_process_int (int level, struct pt_regs *regs);
 extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* added just for debugging */
 extern void q40_init_IRQ (void);
@@ -62,8 +59,6 @@
 extern void q40_waitbut(void);
 void q40_set_vectors (void);
 
-void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
-
 extern char *saved_command_line;
 extern char m68k_debug_device[];
 static void q40_mem_console_write(struct console *co, const char *b,
@@ -82,14 +77,6 @@
 extern char *q40_mem_cptr; /*=(char *)0xff020000;*/
 static int _cpleft;
 
-#if 0
-int q40_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
-{
-        *keycodep = keycode;
-        return 1;
-}
-#endif
-
 static void q40_mem_console_write(struct console *co, const char *s,
 				  unsigned int count)
 {
@@ -117,13 +104,6 @@
 }
 #endif
 
-#if 0
-int q40_kbdrate (struct kbd_repeat *k)
-{
-	return 0;
-}
-#endif
-
 static int halted=0;
 
 #ifdef CONFIG_HEARTBEAT
@@ -185,10 +165,6 @@
 {
     mach_sched_init      = q40_sched_init;
 
-#ifdef CONFIG_VT
-    mach_keyb_init       = q40kbd_init_hw;
-    mach_kbd_translate   = q40kbd_translate;
-#endif
     mach_init_IRQ        = q40_init_IRQ;   
     mach_gettimeoffset   = q40_gettimeoffset; 
     mach_hwclk           = q40_hwclk; 
@@ -204,12 +180,9 @@
     mach_default_handler = &q40_sys_default_handler;
     mach_get_model       = q40_get_model;
     mach_get_hardware_list = q40_get_hardware_list;
-#ifdef CONFIG_VT
-    kd_mksound             = q40_mksound;
-#endif
 
-#ifdef CONFIG_MAGIC_SYSRQ
-    mach_sysrq_key       = 0x54;
+#ifdef CONFIG_INPUT_M68K_BEEP
+    mach_beep            = q40_mksound;
 #endif
 #ifdef CONFIG_HEARTBEAT
     mach_heartbeat = q40_heartbeat;
diff -Nru a/arch/mips/baget/vacserial.c b/arch/mips/baget/vacserial.c
--- a/arch/mips/baget/vacserial.c	Fri Oct 11 21:23:00 2002
+++ b/arch/mips/baget/vacserial.c	Fri Oct 11 21:23:00 2002
@@ -650,7 +650,7 @@
 	struct serial_state *state= info->state;
 	unsigned long page;
 
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
@@ -2022,7 +2022,7 @@
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
 			/* MOD_DEC_USE_COUNT; "info->tty" will cause this */
 			return -ENOMEM;
diff -Nru a/arch/mips/config.in b/arch/mips/config.in
--- a/arch/mips/config.in	Fri Oct 11 21:23:00 2002
+++ b/arch/mips/config.in	Fri Oct 11 21:23:00 2002
@@ -491,6 +491,8 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
+else
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
 fi
 endmenu
 
diff -Nru a/arch/mips64/config.in b/arch/mips64/config.in
--- a/arch/mips64/config.in	Fri Oct 11 21:23:01 2002
+++ b/arch/mips64/config.in	Fri Oct 11 21:23:01 2002
@@ -245,6 +245,8 @@
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Run uncached' CONFIG_MIPS_UNCACHED
+else
+   int  'Maximum number of CPUs (2-64)' CONFIG_NR_CPUS 64
 fi
 endmenu
 
diff -Nru a/arch/mips64/defconfig b/arch/mips64/defconfig
--- a/arch/mips64/defconfig	Fri Oct 11 21:22:54 2002
+++ b/arch/mips64/defconfig	Fri Oct 11 21:22:54 2002
@@ -32,6 +32,7 @@
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
 # CONFIG_SBUS is not set
+CONFIG_NR_CPUS=64
 
 #
 # CPU selection
diff -Nru a/arch/parisc/config.in b/arch/parisc/config.in
--- a/arch/parisc/config.in	Fri Oct 11 21:23:05 2002
+++ b/arch/parisc/config.in	Fri Oct 11 21:23:05 2002
@@ -19,6 +19,10 @@
 # bool 'Symmetric multi-processing support' CONFIG_SMP
 define_bool CONFIG_SMP n
 
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
+
 bool 'Kernel Debugger support' CONFIG_KWDB
 # define_bool CONFIG_KWDB n
 
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Fri Oct 11 21:22:52 2002
+++ b/arch/ppc/Makefile	Fri Oct 11 21:22:52 2002
@@ -53,7 +53,9 @@
   endif
 endif
 
-core-y				+= arch/ppc/kernel/ arch/ppc/platforms/ arch/ppc/mm/ arch/ppc/lib/
+core-y				+= arch/ppc/kernel/ arch/ppc/platforms/ \
+				   arch/ppc/mm/ arch/ppc/lib/
+core-$(CONFIG_4xx)		+= arch/ppc/platforms/4xx/
 core-$(CONFIG_MATH_EMULATION)	+= arch/ppc/math-emu/
 core-$(CONFIG_XMON)		+= arch/ppc/xmon/
 core-$(CONFIG_APUS)		+= arch/ppc/amiga/
@@ -79,13 +81,21 @@
 	cp -f arch/ppc/configs/$(@:config=defconfig) .config
 
 archclean:
-	rm -f arch/ppc/kernel/{mk_defs,asm-offsets.h,find_name}
-	rm -f arch/ppc/iSeries/ReleaseData.h
 	@$(MAKEBOOT) clean
 
 archmrproper:
 
-prepare: checkbin
+prepare: include/asm-$(ARCH)/offsets.h checkbin
+
+arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
+				   include/config/MARKER
+
+include/asm-$(ARCH)/offsets.h.tmp: arch/$(ARCH)/kernel/asm-offsets.s
+	@$(generate-asm-offsets.h) < $< > $@
+
+include/asm-$(ARCH)/offsets.h: include/asm-$(ARCH)/offsets.h.tmp
+	@echo -n '  Generating $@'
+	@$(update-if-changed)
 
 ifdef CONFIG_6xx
 # Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later
@@ -105,3 +115,8 @@
 checkbin:
 	@true
 endif
+
+CLEAN_FILES +=	include/asm-$(ARCH)/offsets.h.tmp \
+		include/asm-$(ARCH)/offsets.h \
+		arch/$(ARCH)/kernel/asm-offsets.s \
+		arch/$(ARCH)/iSeries/ReleaseData.h
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Fri Oct 11 21:22:59 2002
+++ b/arch/ppc/config.in	Fri Oct 11 21:22:59 2002
@@ -174,6 +174,7 @@
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_SMP" = "y" ]; then
    bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
 fi
 if [ "$CONFIG_SMP" != "y" ]; then
    bool 'Preemptible Kernel' CONFIG_PREEMPT
diff -Nru a/arch/ppc/configs/cedar_defconfig b/arch/ppc/configs/cedar_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/configs/cedar_defconfig	Fri Oct 11 21:23:02 2002
@@ -0,0 +1,612 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_4xx=y
+# CONFIG_POWER3 is not set
+# CONFIG_8xx is not set
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_PPC_STD_MMU is not set
+CONFIG_CEDER=y
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_OAK is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_NP405=y
+CONFIG_BIOS_FIXUP=y
+CONFIG_TREEBOOT=y
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM_OCP=y
+# CONFIG_405_DMA is not set
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_IBM405_ERR51=y
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+# CONFIG_PCI is not set
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+CONFIG_PPC_RTC=y
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# 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=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_COPS_DAYNA is not set
+# CONFIG_COPS_TANGENT is not set
+# CONFIG_IPDDP is not set
+# CONFIG_IPDDP_ENCAP is not set
+# CONFIG_IPDDP_DECAP is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# 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_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=8
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_PROC is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+CONFIG_PPC405_WDT=y
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# MPC4xx Driver Options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+
+#
+#   Input core support is needed for USB HID
+#
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
diff -Nru a/arch/ppc/configs/ceder_defconfig b/arch/ppc/configs/ceder_defconfig
--- a/arch/ppc/configs/ceder_defconfig	Fri Oct 11 21:23:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,612 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-# CONFIG_UID16 is not set
-# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-CONFIG_HAVE_DEC_LOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
-# Platform support
-#
-CONFIG_PPC=y
-CONFIG_PPC32=y
-# CONFIG_6xx is not set
-CONFIG_4xx=y
-# CONFIG_POWER3 is not set
-# CONFIG_8xx is not set
-# CONFIG_PPC_ISERIES is not set
-# CONFIG_PPC_STD_MMU is not set
-CONFIG_CEDER=y
-# CONFIG_CPCI405 is not set
-# CONFIG_EP405 is not set
-# CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
-# CONFIG_REDWOOD_5 is not set
-# CONFIG_TIVO is not set
-# CONFIG_WALNUT is not set
-# CONFIG_ALL_PPC is not set
-# CONFIG_SMP is not set
-# CONFIG_MATH_EMULATION is not set
-CONFIG_NP405=y
-CONFIG_BIOS_FIXUP=y
-CONFIG_TREEBOOT=y
-CONFIG_IBM405_ERR77=y
-CONFIG_IBM_OCP=y
-# CONFIG_405_DMA is not set
-CONFIG_UART0_TTYS0=y
-# CONFIG_UART0_TTYS1 is not set
-CONFIG_IBM405_ERR51=y
-CONFIG_NOT_COHERENT_CACHE=y
-
-#
-# General setup
-#
-# CONFIG_HIGHMEM is not set
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
-# CONFIG_PCI is not set
-# CONFIG_PC_KEYBOARD is not set
-CONFIG_NET=y
-CONFIG_SYSCTL=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
-# CONFIG_CMDLINE_BOOL is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# 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=y
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_COPS_DAYNA is not set
-# CONFIG_COPS_TANGENT is not set
-# CONFIG_IPDDP is not set
-# CONFIG_IPDDP_ENCAP is not set
-# CONFIG_IPDDP_DECAP is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# 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_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-# CONFIG_FUSION_BOOT is not set
-# CONFIG_FUSION_ISENSE is not set
-# CONFIG_FUSION_CTL is not set
-# CONFIG_FUSION_LAN is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
-# CONFIG_GMAC is not set
-CONFIG_IBM_OCP_ENET=y
-# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
-CONFIG_IBM_OCP_ENET_RX_BUFF=64
-CONFIG_IBM_OCP_ENET_TX_BUFF=8
-CONFIG_IBM_OCP_ENET_GAP=8
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Console drivers
-#
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Macintosh device drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_CHARDEV is not set
-# CONFIG_I2C_PROC is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_WDT is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_PCWATCHDOG is not set
-# CONFIG_ACQUIRE_WDT is not set
-# CONFIG_ADVANTECH_WDT is not set
-# CONFIG_EUROTECH_WDT is not set
-# CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
-# CONFIG_MIXCOMWD is not set
-# CONFIG_60XX_WDT is not set
-# CONFIG_W83877F_WDT is not set
-# CONFIG_MACHZ_WDT is not set
-CONFIG_PPC405_WDT=y
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-CONFIG_ROOT_NFS=y
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-# CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# MPC4xx Driver Options
-#
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-# CONFIG_BDI_SWITCH is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile	Fri Oct 11 21:23:03 2002
+++ b/arch/ppc/kernel/Makefile	Fri Oct 11 21:23:03 2002
@@ -89,23 +89,5 @@
 
 include $(TOPDIR)/Rules.make
 
-entry.o: entry.S asm-offsets.h
-misc.o: misc.S asm-offsets.h
-l2cr.o: l2cr.S asm-offsets.h
-head.o: head.S asm-offsets.h
-head_4xx.o: head_4xx.S asm-offsets.h
-head_8xx.o: head_8xx.S asm-offsets.h
-iSeries_head.o: iSeries_head.S asm-offsets.h
-iSeries_misc.o: iSeries_misc.S asm-offsets.h
-
-asm-offsets.h: mk_defs.c asm-offsets.head \
-		$(TOPDIR)/include/asm/mmu.h \
-		$(TOPDIR)/include/asm/processor.h \
-		$(TOPDIR)/include/asm/pgtable.h \
-		$(TOPDIR)/include/asm/ptrace.h
-	$(CC) $(CFLAGS) -S mk_defs.c
-	(cat asm-offsets.head; grep '^#define' mk_defs.s) >asm-offsets.h
-	rm mk_defs.s
-
 find_name : find_name.c
 	$(HOSTCC) $(HOSTCFLAGS) -o find_name find_name.c
diff -Nru a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/asm-offsets.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,157 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+
+#ifdef CONFIG_PPC_ISERIES
+#include <asm/iSeries/Paca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/HvLpEvent.h>
+#endif /* CONFIG_PPC_ISERIES */
+
+#define DEFINE(sym, val) \
+	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int
+main(void)
+{
+	DEFINE(THREAD, offsetof(struct task_struct, thread));
+	DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
+	DEFINE(MM, offsetof(struct task_struct, mm));
+	DEFINE(KSP, offsetof(struct thread_struct, ksp));
+	DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
+	DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
+	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
+	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
+	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
+#ifdef CONFIG_ALTIVEC
+	DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0]));
+	DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave));
+	DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
+#endif /* CONFIG_ALTIVEC */
+	/* Interrupt register frame */
+	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
+	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+	/* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */
+	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+	DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+	DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+	DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+	DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+	DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+	DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+	DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+	DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
+	DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
+	DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
+	DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
+	DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14]));
+	DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15]));
+	DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16]));
+	DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17]));
+	DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18]));
+	DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19]));
+	DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+	DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24]));
+	DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25]));
+	DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26]));
+	DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27]));
+	DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28]));
+	DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29]));
+	DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30]));
+	DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31]));
+	/* Note: these symbols include _ because they overlap with special
+	 * register names
+	 */
+	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+	DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+	DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+	DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+	DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+	DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq));
+	DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+	DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+	DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+	/* The PowerPC 400-class processors have neither the DAR nor the DSISR
+	 * SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs
+	 * for such processors.  For critical interrupts we use them to
+	 * hold SRR0 and SRR1.
+	 */
+	DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+	DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
+	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
+	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
+	DEFINE(CLONE_VM, CLONE_VM);
+	DEFINE(MM_PGD, offsetof(struct mm_struct, pgd));
+
+	/* About the CPU features table */
+	DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec));
+	DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask));
+	DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value));
+	DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
+	DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
+
+#ifdef CONFIG_PPC_ISERIES
+	DEFINE(PACAPROCENABLED, offsetof(struct Paca, xProcEnabled));
+	DEFINE(PACAPACAINDEX, offsetof(struct Paca, xPacaIndex));
+	DEFINE(PACAPROCSTART, offsetof(struct Paca, xProcStart));
+	DEFINE(PACAKSAVE, offsetof(struct Paca, xKsave));
+	DEFINE(PACASAVEDMSR, offsetof(struct Paca, xSavedMsr));
+	DEFINE(PACASAVEDLR, offsetof(struct Paca, xSavedLr));
+	DEFINE(PACACONTEXTOVERFLOW, offsetof(struct Paca, xContextOverflow));
+	DEFINE(PACAR21, offsetof(struct Paca, xR21));
+	DEFINE(PACAR22, offsetof(struct Paca, xR22));
+	DEFINE(PACALPQUEUE, offsetof(struct Paca, lpQueuePtr));
+	DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca));
+	DEFINE(PACA_STRUCT_SIZE, sizeof(struct Paca));
+	DEFINE(LPREGSAV, offsetof(struct Paca, xRegSav));
+	DEFINE(PACADEFAULTDECR, offsetof(struct Paca, default_decr));
+	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xRsvd));
+	DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
+	DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
+	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xDecrInt));
+	DEFINE(LPPACAIPIINT, offsetof(struct ItLpPaca, xIpiCnt));
+	DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
+	DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
+	DEFINE(LPQINUSEWORD, offsetof(struct ItLpQueue, xInUseWord));
+	DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
+	DEFINE(CONTEXT, offsetof(struct mm_struct, context));
+	DEFINE(_SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq));
+	DEFINE(PACA_EXT_INTS, offsetof(struct Paca, ext_ints));
+#endif /* CONFIG_PPC_ISERIES */
+
+	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
+	return 0;
+}
diff -Nru a/arch/ppc/kernel/asm-offsets.head b/arch/ppc/kernel/asm-offsets.head
--- a/arch/ppc/kernel/asm-offsets.head	Fri Oct 11 21:22:57 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S	Fri Oct 11 21:23:03 2002
+++ b/arch/ppc/kernel/entry.S	Fri Oct 11 21:23:03 2002
@@ -30,7 +30,7 @@
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 #ifdef	CONFIG_PPC_ISERIES
 #include "iSeries_asm.h"
 #endif /* CONFIG_PPC_ISERIES */
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Fri Oct 11 21:22:50 2002
+++ b/arch/ppc/kernel/head.S	Fri Oct 11 21:22:50 2002
@@ -31,7 +31,7 @@
 #include <asm/cache.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 
 #ifdef CONFIG_APUS
 #include <asm/amigappc.h>
diff -Nru a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
--- a/arch/ppc/kernel/head_4xx.S	Fri Oct 11 21:22:57 2002
+++ b/arch/ppc/kernel/head_4xx.S	Fri Oct 11 21:22:57 2002
@@ -40,7 +40,7 @@
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 
 /* As with the other PowerPC ports, it is expected that when code
  * execution begins here, the following registers contain valid, yet
diff -Nru a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
--- a/arch/ppc/kernel/head_8xx.S	Fri Oct 11 21:22:58 2002
+++ b/arch/ppc/kernel/head_8xx.S	Fri Oct 11 21:22:58 2002
@@ -30,7 +30,7 @@
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 
 	.text
 	.globl	_stext
diff -Nru a/arch/ppc/kernel/iSeries_head.S b/arch/ppc/kernel/iSeries_head.S
--- a/arch/ppc/kernel/iSeries_head.S	Fri Oct 11 21:22:55 2002
+++ b/arch/ppc/kernel/iSeries_head.S	Fri Oct 11 21:22:55 2002
@@ -32,7 +32,7 @@
 #include <asm/pgtable.h>
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 #include "iSeries_asm.h"
 
 
diff -Nru a/arch/ppc/kernel/iSeries_misc.S b/arch/ppc/kernel/iSeries_misc.S
--- a/arch/ppc/kernel/iSeries_misc.S	Fri Oct 11 21:22:51 2002
+++ b/arch/ppc/kernel/iSeries_misc.S	Fri Oct 11 21:22:51 2002
@@ -22,7 +22,7 @@
 #include <asm/page.h>
 #include <asm/cache.h>
 #include <asm/ppc_asm.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 #include "iSeries_asm.h"
 
 	.text
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Fri Oct 11 21:22:55 2002
+++ b/arch/ppc/kernel/misc.S	Fri Oct 11 21:22:55 2002
@@ -23,7 +23,7 @@
 #include <asm/mmu.h>
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 
 	.text
 
diff -Nru a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
--- a/arch/ppc/kernel/mk_defs.c	Fri Oct 11 21:22:59 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,156 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#include <stddef.h>
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/cputable.h>
-#include <asm/thread_info.h>
-
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/iSeries/Paca.h>
-#include <asm/iSeries/ItLpPaca.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/iSeries/HvLpEvent.h>
-#endif /* CONFIG_PPC_ISERIES */
-
-#define DEFINE(sym, val) \
-	asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
-
-int
-main(void)
-{
-	DEFINE(THREAD, offsetof(struct task_struct, thread));
-	DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
-	DEFINE(MM, offsetof(struct task_struct, mm));
-	DEFINE(KSP, offsetof(struct thread_struct, ksp));
-	DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
-	DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
-	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
-	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
-	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
-	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
-#ifdef CONFIG_ALTIVEC
-	DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0]));
-	DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave));
-	DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
-#endif /* CONFIG_ALTIVEC */
-	/* Interrupt register frame */
-	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
-	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
-	/* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */
-	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
-	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
-	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
-	DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
-	DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
-	DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
-	DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
-	DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
-	DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
-	DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
-	DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
-	DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
-	DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
-	DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
-	DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14]));
-	DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15]));
-	DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16]));
-	DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17]));
-	DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18]));
-	DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19]));
-	DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
-	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
-	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
-	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
-	DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24]));
-	DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25]));
-	DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26]));
-	DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27]));
-	DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28]));
-	DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29]));
-	DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30]));
-	DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31]));
-	/* Note: these symbols include _ because they overlap with special
-	 * register names
-	 */
-	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
-	DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
-	DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
-	DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
-	DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
-	DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq));
-	DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
-	DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
-	DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
-	/* The PowerPC 400-class processors have neither the DAR nor the DSISR
-	 * SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs
-	 * for such processors.  For critical interrupts we use them to
-	 * hold SRR0 and SRR1.
-	 */
-	DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
-	DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
-	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
-	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
-	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
-	DEFINE(CLONE_VM, CLONE_VM);
-	DEFINE(MM_PGD, offsetof(struct mm_struct, pgd));
-
-	/* About the CPU features table */
-	DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec));
-	DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask));
-	DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value));
-	DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
-	DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
-
-#ifdef CONFIG_PPC_ISERIES
-	DEFINE(PACAPROCENABLED, offsetof(struct Paca, xProcEnabled));
-	DEFINE(PACAPACAINDEX, offsetof(struct Paca, xPacaIndex));
-	DEFINE(PACAPROCSTART, offsetof(struct Paca, xProcStart));
-	DEFINE(PACAKSAVE, offsetof(struct Paca, xKsave));
-	DEFINE(PACASAVEDMSR, offsetof(struct Paca, xSavedMsr));
-	DEFINE(PACASAVEDLR, offsetof(struct Paca, xSavedLr));
-	DEFINE(PACACONTEXTOVERFLOW, offsetof(struct Paca, xContextOverflow));
-	DEFINE(PACAR21, offsetof(struct Paca, xR21));
-	DEFINE(PACAR22, offsetof(struct Paca, xR22));
-	DEFINE(PACALPQUEUE, offsetof(struct Paca, lpQueuePtr));
-	DEFINE(PACALPPACA, offsetof(struct Paca, xLpPaca));
-	DEFINE(PACA_STRUCT_SIZE, sizeof(struct Paca));
-	DEFINE(LPREGSAV, offsetof(struct Paca, xRegSav));
-	DEFINE(PACADEFAULTDECR, offsetof(struct Paca, default_decr));
-	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xRsvd));
-	DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
-	DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
-	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xDecrInt));
-	DEFINE(LPPACAIPIINT, offsetof(struct ItLpPaca, xIpiCnt));
-	DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
-	DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
-	DEFINE(LPQINUSEWORD, offsetof(struct ItLpQueue, xInUseWord));
-	DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
-	DEFINE(CONTEXT, offsetof(struct mm_struct, context));
-	DEFINE(_SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq));
-	DEFINE(PACA_EXT_INTS, offsetof(struct Paca, ext_ints));
-#endif /* CONFIG_PPC_ISERIES */
-
-	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
-	return 0;
-}
diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
--- a/arch/ppc/kernel/open_pic.c	Fri Oct 11 21:23:00 2002
+++ b/arch/ppc/kernel/open_pic.c	Fri Oct 11 21:23:00 2002
@@ -150,11 +150,11 @@
     if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
 	|| ISR[irq - open_pic_irq_offset] == 0) { \
       printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
-      show_stack(NULL); }
+      dump_stack(); }
 #define check_arg_cpu(cpu) \
     if (cpu < 0 || cpu >= NumProcessors){ \
 	printk("open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \
-	show_stack(NULL); }
+	dump_stack(); }
 #else
 #define check_arg_ipi(ipi)	do {} while (0)
 #define check_arg_timer(timer)	do {} while (0)
@@ -317,7 +317,7 @@
 	openpic_reset();
 #endif
 
-	if (ppc_md.progress) ppc_md.progress("openpic enter", 0x122);
+	if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
 
 	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
 	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
@@ -351,7 +351,7 @@
 	open_pic_irq_offset = linux_irq_offset;
 
 	/* Initialize timer interrupts */
-	if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba);
+	if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
 	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
 		/* Disabled, Priority 0 */
 		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+linux_irq_offset);
@@ -361,7 +361,7 @@
 
 #ifdef CONFIG_SMP
 	/* Initialize IPI interrupts */
-	if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb);
+	if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
 	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 		/* Disabled, Priority 10..13 */
 		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+linux_irq_offset);
@@ -374,7 +374,7 @@
 #endif
 
 	/* Initialize external interrupts */
-	if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc);
+	if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc);
 
 	openpic_set_priority(0xf);
 
@@ -389,7 +389,7 @@
 		openpic_disable_irq(i+linux_irq_offset);
 
 		/*
-		 * We find the vale from either the InitSenses table
+		 * We find the value from either the InitSenses table
 		 * or assume a negative polarity level interrupt.
 		 */
 		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
@@ -410,7 +410,7 @@
 		irq_desc[i].handler = &open_pic;
 
 	/* Initialize the spurious interrupt */
-	if (ppc_md.progress) ppc_md.progress("openpic spurious",0x3bd);
+	if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
 	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+linux_irq_offset);
 
 	/* Initialize the cascade */
@@ -426,7 +426,7 @@
 #endif
 	openpic_set_priority(0);
 
-	if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
+	if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222);
 }
 
 #ifdef notused
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Fri Oct 11 21:22:58 2002
+++ b/arch/ppc/kernel/process.c	Fri Oct 11 21:22:58 2002
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/prctl.h>
 #include <linux/init_task.h>
+#include <linux/module.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -69,6 +70,8 @@
 /* only used to get secondary processor up */
 struct task_struct *current_set[NR_CPUS] = {&init_task, };
 
+static void show_tsk_stack(struct task_struct *tsk, unsigned long sp);
+
 #undef SHOW_TASK_SWITCHES
 #undef CHECK_STACK
 
@@ -264,15 +267,15 @@
 	printk("TASK = %p[%d] '%s' ",
 	       current, current->pid, current->comm);
 	printk("Last syscall: %ld ", current->thread.last_syscall);
-	printk("\nlast math %p last altivec %p", last_task_used_math,
-	       last_task_used_altivec);
 
 #if defined(CONFIG_4xx) && defined(DCRN_PLB0_BEAR)
 	printk("\nPLB0: bear= 0x%8.8x acr=   0x%8.8x besr=  0x%8.8x\n",
-	    mfdcr(DCRN_POB0_BEAR), mfdcr(DCRN_PLB0_ACR),
+	    mfdcr(DCRN_PLB0_BEAR), mfdcr(DCRN_PLB0_ACR),
 	    mfdcr(DCRN_PLB0_BESR));
+#endif
+#if defined(CONFIG_4xx) && defined(DCRN_POB0_BEAR)
 	printk("PLB0 to OPB: bear= 0x%8.8x besr0= 0x%8.8x besr1= 0x%8.8x\n",
-	    mfdcr(DCRN_PLB0_BEAR), mfdcr(DCRN_POB0_BESR0),
+	    mfdcr(DCRN_POB0_BEAR), mfdcr(DCRN_POB0_BESR0),
 	    mfdcr(DCRN_POB0_BESR1));
 #endif
 	
@@ -291,7 +294,7 @@
 			break;
 	}
 	printk("\n");
-	show_stack((unsigned long *)regs->gpr[1]);
+	show_tsk_stack(current, regs->gpr[1]);
 }
 
 void exit_thread(void)
@@ -328,6 +331,8 @@
 	unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE;
 	unsigned long childframe;
 
+	p->user_tid = NULL;
+
 	CHECK_FULL_REGS(regs);
 	/* Copy registers */
 	sp -= sizeof(struct pt_regs);
@@ -441,7 +446,10 @@
 	      struct pt_regs *regs)
 {
  	struct task_struct *p;
+
 	CHECK_FULL_REGS(regs);
+	if ((p1 & (CLONE_SETTID | CLONE_CLEARTID)) == 0)
+		p3 = 0;
  	p = do_fork(p1 & ~CLONE_IDLETASK, p2, regs, 0, (int *)p3);
  	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
@@ -489,50 +497,61 @@
 	return error;
 }
 
-void
-show_stack(unsigned long *sp)
+void show_trace_task(struct task_struct *tsk)
 {
-	int cnt = 0;
-	unsigned long i;
+	show_tsk_stack(tsk, tsk->thread.ksp);
+}
 
-	if (sp == NULL)
-		sp = (unsigned long *)_get_SP();
-	printk("Call backtrace: ");
-	for (;;) {
-		if (__get_user(sp, (unsigned long **)sp))
-			break;
-		if (sp == NULL)
-			break;
-		if (__get_user(i, &sp[1]))
-			break;
-		if (cnt++ % 7 == 0)
-			printk("\n");
-		printk("%08lX ", i);
-		if (cnt > 32)
-			break;
-	}
-	printk("\n");
+void dump_stack(void)
+{
+	show_tsk_stack(current, _get_SP());
 }
 
-void show_trace_task(struct task_struct *tsk)
+static void show_tsk_stack(struct task_struct *tsk, unsigned long sp)
 {
-	unsigned long stack_top = (unsigned long) tsk->thread_info + THREAD_SIZE;
-	unsigned long sp, prev_sp;
+	unsigned long stack_top, prev_sp, ret;
 	int count = 0;
+	unsigned long next_exc = 0;
+	struct pt_regs *regs;
+	extern char ret_from_except, ret_from_except_full, ret_from_syscall;
 
 	if (tsk == NULL)
 		return;
-	sp = (unsigned long) &tsk->thread.ksp;
-	do {
-		prev_sp = sp;
+	prev_sp = (unsigned long) (tsk->thread_info + 1);
+	stack_top = (unsigned long) tsk->thread_info + THREAD_SIZE;
+	while (count < 16 && sp > prev_sp && sp < stack_top && (sp & 3) == 0) {
+		if (count == 0) {
+			printk("Call trace:");
+#if CONFIG_KALLSYMS
+			printk("\n");
+#endif
+		} else {
+			if (next_exc) {
+				ret = next_exc;
+				next_exc = 0;
+			} else
+				ret = *(unsigned long *)(sp + 4);
+			printk(" [%08lx] ", ret);
+#if CONFIG_KALLSYMS
+			print_symbol("%s", ret);
+			printk("\n");
+#endif
+			if (ret == (unsigned long) &ret_from_except
+			    || ret == (unsigned long) &ret_from_except_full
+			    || ret == (unsigned long) &ret_from_syscall) {
+				/* sp + 16 points to an exception frame */
+				regs = (struct pt_regs *) (sp + 16);
+				if (sp + 16 + sizeof(*regs) <= stack_top)
+					next_exc = regs->nip;
+			}
+		}
+		++count;
 		sp = *(unsigned long *)sp;
-		if (sp <= prev_sp || sp >= stack_top || (sp & 3) != 0)
-			break;
-		if (count > 0)
-			printk("[%08lx] ", *(unsigned long *)(sp + 4));
-	} while (++count < 16);
-	if (count > 1)
+	}
+#if !CONFIG_KALLSYMS
+	if (count > 0)
 		printk("\n");
+#endif
 }
 
 #if 0
diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c	Fri Oct 11 21:22:57 2002
+++ b/arch/ppc/kernel/signal.c	Fri Oct 11 21:22:57 2002
@@ -65,11 +65,11 @@
 	sigset_t saveset;
 
 	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	regs->result = -EINTR;
 	regs->ccr |= 0x10000000;
@@ -96,11 +96,11 @@
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	current->blocked = newset;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	regs->result = -EINTR;
 	regs->ccr |= 0x10000000;
@@ -157,7 +157,7 @@
  * When we have signals to deliver, we set up on the
  * user stack, going down from the original stack pointer:
  *	a sigregs struct
- *	one or more sigcontext structs with
+ *	a sigcontext struct
  *	a gap of __SIGNAL_FRAMESIZE bytes
  *
  * Each of these things must be a multiple of 16 bytes in size.
@@ -196,7 +196,7 @@
 		     struct pt_regs *regs)
 {
 	struct rt_sigframe *rt_sf;
-	struct sigcontext_struct sigctx;
+	struct sigcontext sigctx;
 	struct sigregs *sr;
 	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
 	sigset_t set;
@@ -208,10 +208,10 @@
 	    || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
 		goto badframe;
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
@@ -297,12 +297,12 @@
 int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
 		  struct pt_regs *regs)
 {
-	struct sigcontext_struct *sc, sigctx;
+	struct sigcontext *sc, sigctx;
 	struct sigregs *sr;
 	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
 	sigset_t set;
 
-	sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+	sc = (struct sigcontext *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
 
@@ -311,10 +311,10 @@
 	set.sig[1] = sigctx._unused[3];
 #endif
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	if (regs->msr & MSR_FP )
 		giveup_fpu(current);
 
@@ -344,7 +344,7 @@
 setup_frame(struct pt_regs *regs, struct sigregs *frame,
 	    unsigned long newsp)
 {
-	struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
+	struct sigcontext *sc = (struct sigcontext *) newsp;
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
@@ -387,7 +387,7 @@
 handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
 	struct pt_regs * regs, unsigned long *newspp, unsigned long frame)
 {
-	struct sigcontext_struct *sc;
+	struct sigcontext *sc;
 	struct rt_sigframe *rt_sf;
 	struct k_sigaction *ka = &current->sig->action[sig-1];
 
@@ -428,7 +428,7 @@
 	} else {
 		/* Put a sigcontext on the stack */
 		*newspp -= sizeof(*sc);
-		sc = (struct sigcontext_struct *) *newspp;
+		sc = (struct sigcontext *) *newspp;
 		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 			goto badframe;
 		
@@ -446,11 +446,11 @@
 		ka->sa.sa_handler = SIG_DFL;
 
 	if (!(ka->sa.sa_flags & SA_NODEFER)) {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 		sigaddset(&current->blocked,sig);
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 	}
 	return;
 
diff -Nru a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
--- a/arch/ppc/mm/hashtable.S	Fri Oct 11 21:23:03 2002
+++ b/arch/ppc/mm/hashtable.S	Fri Oct 11 21:23:03 2002
@@ -30,7 +30,7 @@
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
 #include <asm/thread_info.h>
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 
 #ifdef CONFIG_SMP
 	.comm	mmu_hash_lock,4
@@ -144,9 +144,7 @@
 #endif
 
 	/* Return from the exception */
-	lwz	r4,_LINK(r11)
 	lwz	r5,_CTR(r11)
-	mtlr	r4
 	mtctr	r5
 	lwz	r0,GPR0(r11)
 	lwz	r7,GPR7(r11)
diff -Nru a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
--- a/arch/ppc/mm/ppc_mmu.c	Fri Oct 11 21:22:54 2002
+++ b/arch/ppc/mm/ppc_mmu.c	Fri Oct 11 21:22:54 2002
@@ -109,7 +109,7 @@
 			break;
 	}
 
-	setbat(2, KERNELBASE, PPC_MEMSTART, bl, _PAGE_KERNEL);
+	setbat(2, KERNELBASE, PPC_MEMSTART, bl, _PAGE_RAM);
 	done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
 	if ((done < tot) && !bat_addrs[3].limit) {
 		/* use BAT3 to cover a bit more */
@@ -117,8 +117,7 @@
 		for (bl = 128<<10; bl < max_size; bl <<= 1)
 			if (bl * 2 > tot)
 				break;
-		setbat(3, KERNELBASE+done, PPC_MEMSTART+done, bl,
-		       _PAGE_KERNEL);
+		setbat(3, KERNELBASE+done, PPC_MEMSTART+done, bl, _PAGE_RAM);
 		done = (unsigned long)bat_addrs[3].limit - KERNELBASE + 1;
 	}
 
diff -Nru a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/Makefile	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,19 @@
+#
+# Makefile for the PowerPC 4xx linux kernel.
+
+obj-$(CONFIG_ASH)		+= ash.o
+obj-$(CONFIG_CEDAR)		+= cedar.o
+obj-$(CONFIG_CPCI405)		+= cpci405.o
+obj-$(CONFIG_EP405)		+= ep405.o
+obj-$(CONFIG_OAK)		+= oak.o
+obj-$(CONFIG_REDWOOD_4)		+= redwood.o
+obj-$(CONFIG_REDWOOD_5)		+= redwood5.o
+obj-$(CONFIG_WALNUT)		+= walnut.o
+
+obj-$(CONFIG_NP405L)		+= ibmnp405l.o
+obj-$(CONFIG_405GP)		+= ibm405gp.o
+obj-$(CONFIG_REDWOOD_4)		+= ibmstb3.o
+obj-$(CONFIG_REDWOOD_5)		+= ibmstb4.o
+obj-$(CONFIG_NP405H)		+= ibmnp405h.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/platforms/4xx/ash.c b/arch/ppc/platforms/4xx/ash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ash.c	Fri Oct 11 21:22:54 2002
@@ -0,0 +1,108 @@
+/*
+ *
+ *    Copyright 2001 MontaVista Software Inc.
+ *        <akuster@mvista.com>
+ *	IBM NP405H ash eval board
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_PPC_RTC
+#include <asm/todc.h>
+#endif
+
+void *ash_rtc_base;
+
+/* Some IRQs unique to Walnut.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	/*
+	 *      PCI IDSEL/INTPIN->INTLINE
+	 *      A       B       C       D
+	 */
+	{
+		{28, 28, 28, 28},	/* IDSEL 1 - PCI slot 1 */
+		{29, 29, 29, 29},	/* IDSEL 2 - PCI slot 2 */
+		{30, 30, 30, 30},	/* IDSEL 3 - PCI slot 3 */
+		{31, 31, 31, 31},	/* IDSEL 4 - PCI slot 4 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+board_setup_arch(void)
+{
+
+	bd_t *bip = (bd_t *)__res;
+
+#ifdef CONFIG_PPC_RTC
+        /* RTC step for the walnut */
+        ash_rtc_base = (void *) ASH_RTC_VADDR;
+	TODC_INIT(TODC_TYPE_DS1743, ash_rtc_base, ash_rtc_base,ash_rtc_base, 8);
+#endif /* CONFIG_PPC_RTC */
+#define CONFIG_DEBUG_BRINGUP
+#ifdef CONFIG_DEBUG_BRINGUP
+	printk("\n");
+	printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
+	printk("\n");
+	printk("bi_s_version\t %s\n",      bip->bi_s_version);
+	printk("bi_r_version\t %s\n",      bip->bi_r_version);
+	printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000));
+	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
+	bip->bi_enetaddr[0][0], bip->bi_enetaddr[0][1],
+	bip->bi_enetaddr[0][2], bip->bi_enetaddr[0][3],
+	bip->bi_enetaddr[0][4], bip->bi_enetaddr[0][5]);
+
+	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 1,
+	bip->bi_enetaddr[1][0], bip->bi_enetaddr[1][1],
+	bip->bi_enetaddr[1][2], bip->bi_enetaddr[1][3],
+	bip->bi_enetaddr[1][4], bip->bi_enetaddr[1][5]);
+
+	printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
+	       bip->bi_intfreq, bip->bi_intfreq/ 1000000);
+
+	printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
+		bip->bi_busfreq, bip->bi_busfreq / 1000000 );
+	printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n",
+	       bip->bi_pci_busfreq, bip->bi_pci_busfreq/1000000);
+
+	printk("\n");
+#endif
+}
+
+void __init
+board_io_mapping(void)
+{
+	io_block_mapping(ASH_RTC_VADDR,
+		ASH_RTC_PADDR, ASH_RTC_SIZE, _PAGE_IO);
+}
+void __init
+board_setup_irq(void)
+{
+
+}
+
+void __init
+board_init(void)
+{
+#ifdef CONFIG_PPC_RTC
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+}
diff -Nru a/arch/ppc/platforms/4xx/ash.h b/arch/ppc/platforms/4xx/ash.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ash.h	Fri Oct 11 21:22:53 2002
@@ -0,0 +1,86 @@
+/*
+ *
+ *
+ *    Copyright 2000 MontaVista Software Inc.
+ * 	Author: MontaVista Software, Inc.
+ *         	akuster@mvista.com or source@mvista.com
+ *
+ *    Module name: ash.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to the IBM PowerPC
+ *      Ash eval board.
+ *
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_ASH_H__
+#define __ASM_ASH_H__
+#include <platforms/ibm_ocp.h>
+#include <platforms/ibmnp405h.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Ash" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[EMAC_NUMS][6];	/* Local Ethernet MAC address */
+	unsigned char	 bi_pci_enetaddr[6];
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
+	unsigned int	 bi_pci_busfreq;	/* PCI speed in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+/* Memory map for the IBM "Ash" NP405H evaluation board.
+ */
+
+extern  void *ash_rtc_base;
+#define ASH_RTC_PADDR		((uint)0xf0000000)
+#define ASH_RTC_VADDR		ASH_RTC_PADDR
+#define ASH_RTC_SIZE		((uint)8*1024)
+
+
+/* Early initialization address mapping for block_io.
+ * Standard 405GP map.
+ */
+#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
+
+#define NR_BOARD_IRQS 32
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD		201600
+#else
+#define BASE_BAUD		691200
+#endif
+
+#define PPC4xx_MACHINE_NAME "IBM NP405H Ceder"
+
+extern char pci_irq_table[][4];
+
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_ASH_H__ */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/cedar.c b/arch/ppc/platforms/4xx/cedar.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/cedar.c	Fri Oct 11 21:22:54 2002
@@ -0,0 +1,83 @@
+/*
+ *
+ *    Copyright 2001 MontaVista Software Inc.
+ *        <akuster@mvista.com>
+ *	IBM NP405L ceder eval board
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <asm/machdep.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_PPC_RTC
+#include <asm/todc.h>
+#endif
+
+void *ceder_rtc_base;
+
+void __init
+board_setup_arch(void)
+{
+
+	bd_t *bip = (bd_t *)__res;
+
+#ifdef CONFIG_PPC_RTC
+        /* RTC step for the walnut */
+        ceder_rtc_base = (void *) CEDER_RTC_VADDR;
+	TODC_INIT(TODC_TYPE_DS1743, ceder_rtc_base, ceder_rtc_base,ceder_rtc_base, 8);
+#endif /* CONFIG_PPC_RTC */
+#define CONFIG_DEBUG_BRINGUP
+#ifdef CONFIG_DEBUG_BRINGUP
+	printk("\n");
+	printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
+	printk("\n");
+	printk("bi_s_version\t %s\n",      bip->bi_s_version);
+	printk("bi_r_version\t %s\n",      bip->bi_r_version);
+	printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000));
+	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
+	bip->bi_enetaddr[0][0], bip->bi_enetaddr[0][1],
+	bip->bi_enetaddr[0][2], bip->bi_enetaddr[0][3],
+	bip->bi_enetaddr[0][4], bip->bi_enetaddr[0][5]);
+
+	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 1,
+	bip->bi_enetaddr[1][0], bip->bi_enetaddr[1][1],
+	bip->bi_enetaddr[1][2], bip->bi_enetaddr[1][3],
+	bip->bi_enetaddr[1][4], bip->bi_enetaddr[1][5]);
+
+	printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
+	       bip->bi_intfreq, bip->bi_intfreq/ 1000000);
+
+	printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
+		bip->bi_busfreq, bip->bi_busfreq / 1000000 );
+	printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n",
+	       bip->bi_pci_busfreq, bip->bi_pci_busfreq/1000000);
+
+	printk("\n");
+#endif
+}
+
+void __init
+board_io_mapping(void)
+{
+	io_block_mapping(CEDER_RTC_VADDR,
+		CEDER_RTC_PADDR, CEDER_RTC_SIZE, _PAGE_IO);
+}
+void __init
+board_setup_irq(void)
+{
+}
+
+void __init
+board_init(void)
+{
+#ifdef CONFIG_PPC_RTC
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+}
diff -Nru a/arch/ppc/platforms/4xx/cedar.h b/arch/ppc/platforms/4xx/cedar.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/cedar.h	Fri Oct 11 21:23:01 2002
@@ -0,0 +1,85 @@
+/*
+ *
+ *
+ *    Copyright 2000 MontaVista Software Inc.
+ * 	Author: MontaVista Software, Inc.
+ *         	akuster@mvista.com or source@mvista.com
+ *
+ *    Module name: ceder.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to the IBM PowerPC
+ *      Ceder eval board.
+ *
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_CEDER_H__
+#define __ASM_CEDER_H__
+#include <platforms/ibmnp405l.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Ceder" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[EMAC_NUMS][6];	/* Local Ethernet MAC address */
+	unsigned char	 bi_pci_mac[6];
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
+	unsigned int	 bi_pci_busfreq;	/* PCI speed in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+/* Memory map for the IBM "Ceder" NP405 evaluation board.
+ */
+
+extern  void *ceder_rtc_base;
+#define CEDER_RTC_PADDR		((uint)0xf0000000)
+#define CEDER_RTC_VADDR		CEDER_RTC_PADDR
+#define CEDER_RTC_SIZE		((uint)8*1024)
+
+
+/* Early initialization address mapping for block_io.
+ * Standard 405GP map.
+ */
+#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
+
+#define NR_BOARD_IRQS 32
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD		201600
+#else
+#define BASE_BAUD		691200
+#endif
+
+#define PPC4xx_MACHINE_NAME "IBM NP405L Ceder"
+
+extern char pci_irq_table[][4];
+
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_CEDER_H__ */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/cpci405.c b/arch/ppc/platforms/4xx/cpci405.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/cpci405.c	Fri Oct 11 21:23:02 2002
@@ -0,0 +1,78 @@
+/*
+ * arch/ppc/platforms/cpci405.c
+ *
+ * Board setup routines for the esd CPCI-405 cPCI Board.
+ *
+ * Author: Stefan Roese
+ *         stefan.roese@esd-electronics.com
+ *
+ * Copyright 2001 esd electronic system design - hannover germany
+ *
+ * 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.
+ *
+ *	History: 11/09/2001 - armin
+ *       added board_init to add in additional instuctions needed during platfrom_init
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/todc.h>
+
+/*
+ * Some IRQs unique to CPCI-405.
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	/*
+	 *      PCI IDSEL/INTPIN->INTLINE
+	 *      A       B       C       D
+	 */
+	{
+		{28,	28,	28,	28},	/* IDSEL 15 - cPCI slot 8 */
+		{29,	29,	29,	29},	/* IDSEL 16 - cPCI slot 7 */
+		{30,	30,	30,	30},	/* IDSEL 17 - cPCI slot 6 */
+		{27,	27,	27,	27},	/* IDSEL 18 - cPCI slot 5 */
+		{28,	28,	28,	28},	/* IDSEL 19 - cPCI slot 4 */
+		{29,	29,	29,	29},	/* IDSEL 20 - cPCI slot 3 */
+		{30,	30,	30,	30},	/* IDSEL 21 - cPCI slot 2 */
+        };
+	const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+board_setup_arch(void)
+{
+}
+
+void __init
+board_io_mapping(void)
+{
+}
+
+void __init
+board_setup_irq(void)
+{
+}
+
+void __init
+board_init(void)
+{
+#ifdef CONFIG_PPC_RTC
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+}
diff -Nru a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/cpci405.h	Fri Oct 11 21:23:02 2002
@@ -0,0 +1,45 @@
+/*
+ * CPCI-405 board specific definitions
+ *
+ * Copyright (c) 2001 Stefan Roese (stefan.roese@esd-electronics.com)
+ */
+
+#ifndef __ASM_CPCI405_H__
+#define __ASM_CPCI405_H__
+
+#include <linux/config.h>
+
+/* We have a 405GP core */
+#include <platforms/ibm405gp.h>
+
+#include <asm/ppcboot.h>
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+/* Early initialization address mapping for block_io.
+ * Standard 405GP map.
+ */
+#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD		201600
+#else
+#define BASE_BAUD		691200
+#endif
+
+#define PPC4xx_MACHINE_NAME "esd CPCI-405"
+
+#endif	/* __ASM_CPCI405_H__ */
diff -Nru a/arch/ppc/platforms/4xx/ep405.c b/arch/ppc/platforms/4xx/ep405.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ep405.c	Fri Oct 11 21:22:53 2002
@@ -0,0 +1,184 @@
+/*
+ *    Copyright 2001 MontaVista Software Inc.
+ *        <mlocke@mvista.com>
+ *
+ * 	Not much is needed for the Embedded Planet 405gp board
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/todc.h>
+#include <platforms/ibm_ocp.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+u8 *ep405_bcsr;
+u8 *ep405_nvram;
+
+static struct {
+	u8 cpld_xirq_select;
+	int pci_idsel;
+	int irq;
+} ep405_devtable[] = {
+#ifdef CONFIG_EP405PC
+	{0x07, 0x0E, 25},		/* EP405PC: USB */
+#endif
+};
+#define EP405_DEVTABLE_SIZE (sizeof(ep405_devtable)/sizeof(ep405_devtable[0]))
+
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	int i;
+
+	/* AFAICT this is only called a few times during PCI setup, so
+	   performance is not critical */
+	for (i = 0; i < EP405_DEVTABLE_SIZE; i++) {
+		if (idsel == ep405_devtable[i].pci_idsel)
+			return ep405_devtable[i].irq;
+	}
+	return -1;
+};
+
+void __init
+board_setup_arch(void)
+{
+	bd_t *bip = (bd_t *) __res;
+
+	if (bip->bi_nvramsize == 512*1024) {
+		/* FIXME: we should properly handle NVRTCs of different sizes */
+		TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8);
+	}
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+	unsigned int bar_response, bar;
+	/*
+	 * Expected PCI mapping:
+	 *
+	 *  PLB addr             PCI memory addr
+	 *  ---------------------       ---------------------
+	 *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
+	 *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
+	 *
+	 *  PLB addr             PCI io addr
+	 *  ---------------------       ---------------------
+	 *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
+	 *
+	 */
+
+	/* Disable region zero first */
+	out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+	/* PLB starting addr, PCI: 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+	/* PCI start addr, 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+	/* 512MB range of PLB to PCI */
+	out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+	/* Enable no pre-fetch, enable region */
+	out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+						(PPC405_PCI_UPPER_MEM -
+						 PPC405_PCI_MEM_BASE)) | 0x01));
+
+	/* Disable region one */
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm1ms), 0x00000000);
+
+	/* Disable region two */
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+	/* Configure PTM (PCI->PLB) region 1 */
+	out_le32((void *) &(pcip->ptm1la), 0x00000000); /* PLB base address */
+	/* Disable PTM region 2 */
+	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+	/* Zero config bars */
+	for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+		early_write_config_dword(hose, hose->first_busno,
+					 PCI_FUNC(hose->first_busno), bar,
+					 0x00000000);
+		early_read_config_dword(hose, hose->first_busno,
+					PCI_FUNC(hose->first_busno), bar,
+					&bar_response);
+		DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+		    hose->first_busno, PCI_SLOT(hose->first_busno),
+		    PCI_FUNC(hose->first_busno), bar, bar_response);
+	}
+	/* end work arround */
+}
+
+void __init
+board_io_mapping(void)
+{
+	bd_t *bip = (bd_t *) __res;
+
+	ep405_bcsr = ioremap(EP405_BCSR_PADDR, EP405_BCSR_SIZE);
+
+	if (bip->bi_nvramsize > 0) {
+		ep405_nvram = ioremap(EP405_NVRAM_PADDR, bip->bi_nvramsize);
+	}
+}
+
+void __init
+board_setup_irq(void)
+{
+	int i;
+
+	/* Workaround for a bug in the firmware it incorrectly sets
+	   the IRQ polarities for XIRQ0 and XIRQ1 */
+	mtdcr(DCRN_UIC_PR(DCRN_UIC0_BASE), 0xffffff80); /* set the polarity */
+	mtdcr(DCRN_UIC_SR(DCRN_UIC0_BASE), 0x00000060); /* clear bogus interrupts */
+
+	/* Activate the XIRQs from the CPLD */
+	writeb(0xf0, ep405_bcsr+10);
+
+	/* Set up IRQ routing */
+	for (i = 0; i < EP405_DEVTABLE_SIZE; i++) {
+		if ( (ep405_devtable[i].irq >= 25)
+		     && (ep405_devtable[i].irq) <= 31) {
+			writeb(ep405_devtable[i].cpld_xirq_select, ep405_bcsr+5);
+			writeb(ep405_devtable[i].irq - 25, ep405_bcsr+6);
+		}
+	}
+}
+
+void __init
+board_init(void)
+{
+#ifdef CONFIG_PPC_RTC
+	bd_t *bip = (bd_t *) __res;
+
+	/* FIXME: we should be able to access the NVRAM even if PPC_RTC is not configured */
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+
+	if (bip->bi_nvramsize == 512*1024) {
+		ppc_md.time_init = todc_time_init;
+		ppc_md.set_rtc_time = todc_set_rtc_time;
+		ppc_md.get_rtc_time = todc_get_rtc_time;
+	} else {
+		printk("EP405: NVRTC size is not 512k (not a DS1557).  Not sure what to do with it\n");
+	}
+
+#endif
+}
diff -Nru a/arch/ppc/platforms/4xx/ep405.h b/arch/ppc/platforms/4xx/ep405.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ep405.h	Fri Oct 11 21:22:51 2002
@@ -0,0 +1,47 @@
+/*
+ *    Copyright 2000 MontaVista Software Inc.
+ *    	http://www.mvista.com
+ *	<mlocke@mvista.com>
+ *
+ *         Embedded Planet 405GP board
+ *         http://www.embeddedplanet.com
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_EP405_H__
+#define __ASM_EP405_H__
+
+/* We have a 405GP core */
+#include <platforms/ibm405gp.h>
+
+#ifndef __ASSEMBLY__
+typedef struct board_info {
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
+	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
+	unsigned int	 bi_nvramsize;		/* Size of the NVRAM/RTC */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+extern u8 *ep405_bcsr;
+extern u8 *ep405_nvram;
+
+/* Map for the BCSR and NVRAM space */
+#define EP405_BCSR_PADDR	((uint)0xf4000000)
+#define EP405_BCSR_SIZE		((uint)16)
+#define EP405_NVRAM_PADDR	((uint)0xf4200000)
+
+/* serial defines */
+#define BASE_BAUD		399193
+
+#define PPC4xx_MACHINE_NAME "Embedded Planet 405GP"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_EP405_H__ */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibm405gp.c b/arch/ppc/platforms/4xx/ibm405gp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibm405gp.c	Fri Oct 11 21:23:00 2002
@@ -0,0 +1,63 @@
+/*
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *	Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *
+ *    Module name: ibm405gp.c
+ *
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *      History: 12/26/2001 - armin
+ *		initial release
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <platforms/ibm405gp.h>
+
+const struct pcil0_regs *PCIL_ADDR[] = {
+	(struct pcil0_regs *) PCIL0_BASE,
+};
+
+const struct NS16550 *COM_PORTS[] = {
+	(struct NS16550 *) UART0_IO_BASE,
+	(struct NS16550 *) UART1_IO_BASE,
+};
+
+struct iic_regs *IIC_ADDR[] = {
+	(struct iic_regs *) IIC0_BASE,
+};
+
+const struct gpio_regs *GPIO_ADDR[] = {
+	(struct gpio_regs *) GPIO0_BASE,
+};
+
+const struct emac_regs *EMAC_ADDR[] = {
+	(struct emac_regs *) EMAC0_BASE,
+};
diff -Nru a/arch/ppc/platforms/4xx/ibm405gp.h b/arch/ppc/platforms/4xx/ibm405gp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibm405gp.h	Fri Oct 11 21:22:50 2002
@@ -0,0 +1,195 @@
+/*
+ * ibm405gp.h
+ *
+ *	This was derived from the ppc4xx.h and all 405GP specific
+ *	definition and board inclusions were moved here.
+ *
+ *      Armin Kuster akuster@mvista.com
+ *      Oct, 2001
+ *
+ *
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 (01/10/10) - A. Kuster
+ *	Initial version	 - moved 40GP  specific out of ppc4xx.h
+ *			- moved emac reg from ppc405_enet.h
+ *
+ *	Version 1.1 02/01/17 - A. Kuster
+ *	Moved offsets to ibm405.h
+ *
+ *	Version 1.2 05/01/02 - Armin
+ *	 added IIC_PORT_DFNS
+ *
+ *	Version 1.3 - armin
+ *	  removed iic & uart num defines
+ *	  and IIC_PORT_DFNS
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBM405GP_H__
+#define __ASM_IBM405GP_H__
+
+#include <linux/config.h>
+#include <platforms/ibm_ocp.h>
+
+/* ibm405.h at bottom of this file */
+
+/* PCI
+ * PCI Bridge config reg definitions
+ * see 17-19 of manual
+ */
+
+#define PPC405_PCI_CONFIG_ADDR	0xeec00000
+#define PPC405_PCI_CONFIG_DATA	0xeec00004
+
+#define PPC405_PCI_PHY_MEM_BASE	0x80000000	/* hose_a->pci_mem_offset */
+						/* setbat */
+#define PPC405_PCI_MEM_BASE	PPC405_PCI_PHY_MEM_BASE	/* setbat */
+#define PPC405_PCI_PHY_IO_BASE	0xe8000000	/* setbat */
+#define PPC405_PCI_IO_BASE	PPC405_PCI_PHY_IO_BASE	/* setbat */
+
+#define PPC405_PCI_LOWER_MEM	0x80000000	/* hose_a->mem_space.start */
+#define PPC405_PCI_UPPER_MEM	0xBfffffff	/* hose_a->mem_space.end */
+#define PPC405_PCI_LOWER_IO	0x00000000	/* hose_a->io_space.start */
+#define PPC405_PCI_UPPER_IO	0x0000ffff	/* hose_a->io_space.end */
+
+#define PPC405_ISA_IO_BASE	PPC405_PCI_IO_BASE
+
+#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
+#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
+#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
+#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
+#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
+#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
+#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
+#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
+#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
+
+/* serial port defines */
+#define RS_TABLE_SIZE	2
+
+#define UART0_INT	0
+#define UART1_INT	1
+
+#define PCIL0_BASE	0xEF400000
+#define UART0_IO_BASE	0xEF600300
+#define UART1_IO_BASE	0xEF600400
+#define IIC0_BASE	0xEF600500
+#define OPB0_BASE	0xEF600600
+#define GPIO0_BASE	0xEF600700
+#define EMAC0_BASE	0xEF600800
+
+#define EMAC_NUMS	1
+#define IIC0_IRQ	2
+#define IIC1_IRQ	0
+
+#define IIC_OWN		0x55
+#define IIC_CLOCK	50
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: (u8 *)UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_DEBUG_IO_BASE	UART0_IO_BASE
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_DEBUG_IO_BASE	UART1_IO_BASE
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(1)		\
+	STD_UART_OP(0)
+#endif
+
+/* DCR defines */
+#define DCRN_CHCR_BASE		0x0B1
+#define DCRN_CHPSR_BASE		0x0B4
+#define DCRN_CPMSR_BASE		0x0B8
+#define DCRN_CPMFR_BASE		0x0BA
+
+#define CHR0_U0EC	0x00000080	/* Select external clock for UART0 */
+#define CHR0_U1EC	0x00000040	/* Select external clock for UART1 */
+#define CHR0_UDIV	0x0000003E	/* UART internal clock divisor */
+#define CHR1_CETE	0x00800000	/* CPU external timer enable */
+
+#define DCRN_CHPSR_BASE         0x0B4
+#define  PSR_PLL_FWD_MASK        0xC0000000
+#define  PSR_PLL_FDBACK_MASK     0x30000000
+#define  PSR_PLL_TUNING_MASK     0x0E000000
+#define  PSR_PLB_CPU_MASK        0x01800000
+#define  PSR_OPB_PLB_MASK        0x00600000
+#define  PSR_PCI_PLB_MASK        0x00180000
+#define  PSR_EB_PLB_MASK         0x00060000
+#define  PSR_ROM_WIDTH_MASK      0x00018000
+#define  PSR_ROM_LOC             0x00004000
+#define  PSR_PCI_ASYNC_EN        0x00001000
+#define  PSR_PCI_ARBIT_EN        0x00000400
+
+#define CPM_IIC0		0x80000000	/* IIC interface */
+#define CPM_PCI			0x40000000	/* PCI bridge */
+#define CPM_CPU			0x20000000	/* processor core */
+#define CPM_DMA			0x10000000	/* DMA controller */
+#define CPM_BRG			0x08000000	/* PLB to OPB bridge */
+#define CPM_DCP			0x04000000	/* CodePack */
+#define CPM_EBC			0x02000000	/* ROM/SRAM peripheral controller */
+#define CPM_SDRAM0		0x01000000	/* SDRAM memory controller */
+#define CPM_PLB			0x00800000	/* PLB bus arbiter */
+#define CPM_GPIO0		0x00400000	/* General Purpose IO (??) */
+#define CPM_UART0		0x00200000	/* serial port 0 */
+#define CPM_UART1		0x00100000	/* serial port 1 */
+#define CPM_UIC			0x00080000	/* Universal Interrupt Controller */
+#define CPM_TMRCLK		0x00040000	/* CPU timers */
+#define CPM_EMAC_MM		0x00020000	/* on-chip ethernet MM unit */
+#define CPM_EMAC_RM		0x00010000	/* on-chip ethernet RM unit */
+#define CPM_EMAC_TM		0x00008000	/* on-chip ethernet TM unit */
+
+#define DCRN_DMA0_BASE		0x100
+#define DCRN_DMA1_BASE		0x108
+#define DCRN_DMA2_BASE		0x110
+#define DCRN_DMA3_BASE		0x118
+#define DCRNCAP_DMA_SG		1	/* have DMA scatter/gather capability */
+#define DCRN_DMASR_BASE		0x120
+#define DCRN_EBC_BASE		0x012
+#define DCRN_DCP0_BASE		0x014
+#define DCRN_MAL_BASE		0x180
+#define DCRN_OCM0_BASE		0x018
+#define DCRN_PLB0_BASE		0x084
+#define DCRN_PLLMR_BASE		0x0B0
+#define DCRN_POB0_BASE		0x0A0
+#define DCRN_SDRAM0_BASE	0x010
+#define DCRN_UIC0_BASE		0x0C0
+#define UIC0 DCRN_UIC0_BASE
+
+#include <platforms/ibm405.h>
+
+#endif				/* __ASM_IBM405GP_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibm_ocp.h b/arch/ppc/platforms/4xx/ibm_ocp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibm_ocp.h	Fri Oct 11 21:23:04 2002
@@ -0,0 +1,192 @@
+/*
+ * ibm_ocp.h
+ *
+ *	This was dirived from the ppc4xx.h and all 405GP specific definition and board
+ *	inclusions where moved here.
+ *
+ * 	Current Maintainer
+ *      Armin Kuster akuster@mvista.com
+ *      Nov, 2001
+ *
+ *
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 (01/11/26) - A. Kuster
+ *	Initial version	 -
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBM_OCP_H__
+#define __ASM_IBM_OCP_H__
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
+ /* PCI 32 */
+
+struct pmm_regs {
+	u32 la;
+	u32 ma;
+	u32 pcila;
+	u32 pciha;
+};
+
+typedef struct pcil0_regs {
+	struct pmm_regs pmm[3];
+	u32 ptm1ms;
+	u32 ptm1la;
+	u32 ptm2ms;
+	u32 ptm2la;
+} pci0_t;
+
+/* Serial Ports */
+
+#define thr rbr
+#define iir fcr
+#define dll rbr
+#define dlm ier
+
+typedef struct NS16550 {
+	u8 rbr;			/* 0 */
+	u8 ier;			/* 1 */
+	u8 fcr;			/* 2 */
+	u8 lcr;			/* 3 */
+	u8 mcr;			/* 4 */
+	u8 lsr;			/* 5 */
+	u8 msr;			/* 6 */
+	u8 scr;			/* 7 */
+} uart_t;
+
+/* I2c */
+typedef struct iic_regs {
+	u16 mdbuf;
+	u16 sbbuf;
+	u8 lmadr;
+	u8 hmadr;
+	u8 cntl;
+	u8 mdcntl;
+	u8 sts;
+	u8 extsts;
+	u8 lsadr;
+	u8 hsadr;
+	u8 clkdiv;
+	u8 intmsk;
+	u8 xfrcnt;
+	u8 xtcntlss;
+	u8 directcntl;
+} iic_t;
+
+/* OPB arbiter */
+typedef struct opb {
+	u8 pr;
+	u8 cr;
+} opb_t;
+
+/* General purpose i/o */
+
+typedef struct gpio_regs {
+	u32 or;
+	u32 tcr;
+	u32 pad[4];
+	u32 odr;
+	u32 ir;
+} gpio_t;
+
+/* Emac */
+typedef struct emac_regs {
+	volatile u32 em0mr0;
+	volatile u32 em0mr1;
+	volatile u32 em0tmr0;
+	volatile u32 em0tmr1;
+	volatile u32 em0rmr;
+	volatile u32 em0isr;
+	volatile u32 em0iser;
+	volatile u32 em0iahr;
+	volatile u32 em0ialr;
+	volatile u32 em0vtpid;
+	volatile u32 em0vtci;
+	volatile u32 em0ptr;
+	volatile u32 em0iaht1;
+	volatile u32 em0iaht2;
+	volatile u32 em0iaht3;
+	volatile u32 em0iaht4;
+	volatile u32 em0gaht1;
+	volatile u32 em0gaht2;
+	volatile u32 em0gaht3;
+	volatile u32 em0gaht4;
+	volatile u32 em0lsal;
+	volatile u32 em0lsah;
+	volatile u32 em0ipgvr;
+	volatile u32 em0stacr;
+	volatile u32 em0trtr;
+	volatile u32 em0rwmr;
+} emac_t;
+
+/* ZMII bridge */
+typedef struct zmii_regs {
+	u32 fer;		/* Function enable reg */
+	u32 ssr;		/* Spedd select reg */
+	u32 smiirs;		/* SMII status reg */
+} zmii_t;
+
+/* Structure of the memory mapped IDE control.
+*/
+typedef struct ide_regs {
+	unsigned int si_stat;	/* IDE status */
+	unsigned int si_intenable;	/* IDE interrupt enable */
+	unsigned int si_control;	/* IDE control */
+	unsigned int pad0[0x3d];
+	unsigned int si_c0rt;	/* Chan 0 Register transfer timing */
+	unsigned int si_c0fpt;	/* Chan 0 Fast PIO transfer timing */
+	unsigned int si_c0timo;	/* Chan 0 timeout */
+	unsigned int pad1[2];
+	unsigned int si_c0d0u;	/* Chan 0 UDMA transfer timing */
+#define si_c0d0m si_c0d0u	/* Chan 0 Multiword DMA timing */
+	unsigned int pad2;
+	unsigned int si_c0d1u;	/* Chan 0 dev 1 UDMA timing */
+#define si_c0d1m si_c0d1u	/* Chan 0 dev 1 Multiword DMA timing */
+	unsigned int si_c0c;	/* Chan 0 Control */
+	unsigned int si_c0s0;	/* Chan 0 Status 0 */
+	unsigned int si_c0ie;	/* Chan 0 Interrupt Enable */
+	unsigned int si_c0s1;	/* Chan 0 Status 0 */
+	unsigned int pad4[4];
+	unsigned int si_c0dcm;	/* Chan 0 DMA Command */
+	unsigned int si_c0tb;	/* Chan 0 PRD Table base address */
+	unsigned int si_c0dct;	/* Chan 0 DMA Count */
+	unsigned int si_c0da;	/* Chan 0 DMA Address */
+	unsigned int si_c0sr;	/* Chan 0 Slew Rate Output Control */
+	unsigned char pad5[0xa2];
+	unsigned short si_c0adc;	/* Chan 0 Alt status/control */
+	unsigned char si_c0d;	/* Chan 0 data */
+	unsigned char si_c0ef;	/* Chan 0 error/features */
+	unsigned char si_c0sct;	/* Chan 0 sector count */
+	unsigned char si_c0sn;	/* Chan 0 sector number */
+	unsigned char si_c0cl;	/* Chan 0 cylinder low */
+	unsigned char si_c0ch;	/* Chan 0 cylinder high */
+	unsigned char si_c0dh;	/* Chan 0 device/head */
+	unsigned char si_c0scm;	/* Chan 0 status/command */
+} ide_t;
+
+#endif				/* __ASSEMBLY__ */
+#endif				/* __ASM_IBM_OCP_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405h.c b/arch/ppc/platforms/4xx/ibmnp405h.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmnp405h.c	Fri Oct 11 21:23:04 2002
@@ -0,0 +1,78 @@
+/*
+ *
+ *    Copyright 2000-2002 MontaVista Software Inc.
+ *      Completed implementation.
+ *	Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *
+ *    Module name: ibmnp405h.c
+ *
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *      History: 01/02/2002 - armin
+ *		initial release
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <platforms/ibmnp405h.h>
+
+const struct NS16550* COM_PORTS[] =
+{
+  (struct NS16550*) UART0_IO_BASE,
+  (struct NS16550*) UART1_IO_BASE,
+};
+
+const struct pcil0_regs* PCIL0[]=
+{
+	(struct pcil0_regs*)	PCIL0_BASE,
+};
+
+
+const struct iic_regs* IIC_ADDR[]=
+{
+	(struct iic_regs*) IIC0_BASE,
+};
+
+
+const struct gpio_regs* GPIO_ADDR[] =
+{
+	(struct gpio_regs*)	GPIO0_BASE,
+};
+
+const struct emac_regs* EMAC_ADDR[]=
+{
+	(struct emac_regs*) EMAC0_BASE,
+	(struct emac_regs*) EMAC1_BASE,
+	(struct emac_regs*) EMAC2_BASE,
+	(struct emac_regs*) EMAC3_BASE
+};
+
+const struct zmii_regs* ZMII_ADDR[]=
+{
+	(zmii_t*)	ZMII0_BASE,
+};
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405h.h b/arch/ppc/platforms/4xx/ibmnp405h.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmnp405h.h	Fri Oct 11 21:22:59 2002
@@ -0,0 +1,172 @@
+/*
+ * ibmnp405h.h
+ *
+ *	This was dirived from the ibm405gp.h and other previus works in ppc4xx.h
+ *
+ *      Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *      Jan, 2002
+ *
+ *
+ * Copyright 2002 MontaVista Softare Inc.
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 (02/01/03) - A. Kuster
+ *	Initial version
+ *
+ *	Version 1.1 02/01/17 - A. Kuster
+ *	moved common ofsets to ibm405.h
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBMNP405H_H__
+#define __ASM_IBMNP405H_H__
+
+#include <linux/config.h>
+#include <platforms/ibm_ocp.h>
+
+/* ibm405.h at bottom of this file */
+
+#define PPC405_PCI_CONFIG_ADDR	0xeec00000
+#define PPC405_PCI_CONFIG_DATA	0xeec00004
+#define PPC405_PCI_PHY_MEM_BASE	0x80000000	/* hose_a->pci_mem_offset */
+						/* setbat */
+#define PPC405_PCI_MEM_BASE	PPC405_PCI_PHY_MEM_BASE	/* setbat */
+#define PPC405_PCI_PHY_IO_BASE	0xe8000000	/* setbat */
+#define PPC405_PCI_IO_BASE	PPC405_PCI_PHY_IO_BASE	/* setbat */
+
+#define PPC405_PCI_LOWER_MEM	0x00000000	/* hose_a->mem_space.start */
+#define PPC405_PCI_UPPER_MEM	0xBfffffff	/* hose_a->mem_space.end */
+#define PPC405_PCI_LOWER_IO	0x00000000	/* hose_a->io_space.start */
+#define PPC405_PCI_UPPER_IO	0x0000ffff	/* hose_a->io_space.end */
+
+#define PPC405_ISA_IO_BASE	PPC405_PCI_IO_BASE
+
+#define PPC4xx_PCI_IO_ADDR	((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
+#define PPC4xx_PCI_CFG_ADDR	((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
+#define PPC4xx_PCI_LCFG_ADDR	((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
+#define PPC4xx_ONB_IO_ADDR	((uint)0xef600000)
+#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
+
+/* serial port defines */
+#define RS_TABLE_SIZE	4
+
+#define UART0_INT	0
+#define UART1_INT	1
+#define PCIL0_BASE	0xEF400000
+#define UART0_IO_BASE	0xEF600300
+#define UART1_IO_BASE	0xEF600400
+#define IIC0_BASE	0xEF600500
+#define OPB0_BASE	0xEF600600
+#define GPIO0_BASE	0xEF600700
+#define EMAC0_BASE	0xEF600800
+#define EMAC1_BASE	0xEF600900
+#define EMAC2_BASE	0xEF600900
+#define EMAC3_BASE	0xEF600900
+#define ZMII0_BASE	0xEF600C10
+
+#define EMAC_NUMS	4
+#define UART_NUMS	2
+#define ZMII_NUMS	1
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_PORT_DFNS        \
+        STD_UART_OP(0)          \
+        STD_UART_OP(1)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_PORT_DFNS        \
+        STD_UART_OP(1)          \
+        STD_UART_OP(0)
+#endif
+
+/* DCR defines */
+/* ------------------------------------------------------------------------- */
+
+#define DCRN_CHCR_BASE	0x0B1
+#define DCRN_CHPSR_BASE	0x0B4
+#define DCRN_CPMSR_BASE	0x0B8
+#define DCRN_CPMFR_BASE	0x0BA
+
+#define CPM_IIC0	0x80000000	/* IIC interface */
+#define CPM_PCI		0x40000000	/* PCI bridge */
+#define CPM_CPU		0x20000000	/* processor core */
+#define CPM_DMA		0x10000000	/* DMA controller */
+#define CPM_BRG		0x08000000	/* PLB to OPB bridge */
+#define CPM_DCP		0x04000000	/* CodePack */
+#define CPM_EBC		0x02000000	/* ROM/SRAM peripheral controller */
+#define CPM_SDRAM0	0x01000000	/* SDRAM memory controller */
+#define CPM_PLB		0x00800000	/* PLB bus arbiter */
+#define CPM_GPIO0	0x00400000	/* General Purpose IO (??) */
+#define CPM_UART0	0x00200000	/* serial port 0 */
+#define CPM_UART1	0x00100000	/* serial port 1 */
+#define CPM_UIC	=	0x00080000	/* Universal Interrupt Controller */
+#define CPM_TMRCLK	0x00040000	/* CPU timers */
+#define CPM_EMAC_MM	0x00020000	/* on-chip ethernet MM unit */
+#define CPM_EMAC_RM	0x00010000	/* on-chip ethernet RM unit */
+#define CPM_EMAC_TM	0x00008000	/* on-chip ethernet TM unit */
+
+#define DCRN_DMA0_BASE	0x100
+#define DCRN_DMA1_BASE	0x108
+#define DCRN_DMA2_BASE	0x110
+#define DCRN_DMA3_BASE	0x118
+#define DCRNCAP_DMA_SG	1	/* have DMA scatter/gather capability */
+#define DCRN_DMASR_BASE	0x120
+#define DCRN_EBC_BASE	0x012
+#define DCRN_DCP0_BASE	0x014
+#define DCRN_MAL_BASE	0x180
+#define DCRN_OCM0_BASE	0x018
+#define DCRN_PLB0_BASE	0x084
+#define DCRN_PLLMR_BASE	0x0B0
+#define DCRN_POB0_BASE	0x0A0
+#define DCRN_SDRAM0_BASE 0x010
+#define DCRN_UIC0_BASE	0x0C0
+
+/* unique H offsets */
+
+#ifdef DCRN_UIC1_BASE
+#define DCRN_UIC1_SR	(DCRN_UIC1_BASE + 0x0)
+#define DCRN_UIC1_SRS	(DCRN_UIC1_BASE + 0x1)
+#define DCRN_UIC1_ER	(DCRN_UIC1_BASE + 0x2)
+#define DCRN_UIC1_CR	(DCRN_UIC1_BASE + 0x3)
+#define DCRN_UIC1_PR	(DCRN_UIC1_BASE + 0x4)
+#define DCRN_UIC1_TR	(DCRN_UIC1_BASE + 0x5)
+#define DCRN_UIC1_MSR	(DCRN_UIC1_BASE + 0x6)
+#define DCRN_UIC1_VR	(DCRN_UIC1_BASE + 0x7)
+#define DCRN_UIC1_VCR	(DCRN_UIC1_BASE + 0x8)
+#endif
+
+#include <platforms/ibm405.h>
+
+#endif				/* __ASM_IBMNP405H_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405l.c b/arch/ppc/platforms/4xx/ibmnp405l.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmnp405l.c	Fri Oct 11 21:22:54 2002
@@ -0,0 +1,70 @@
+/*
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *	Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *
+ *    Module name: ibmnp405l.c
+ *
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *      History: 12/26/2001 - armin
+ *		initial release
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <platforms/ibmnp405l.h>
+
+const struct NS16550* COM_PORTS[] =
+{
+  (struct NS16550*) UART0_IO_BASE,
+  (struct NS16550*) UART1_IO_BASE,
+};
+
+const struct iic_regs* IIC_ADDR[]=
+{
+	(struct iic_regs*) IIC0_BASE,
+};
+
+
+const struct gpio_regs* GPIO_ADDR[] =
+{
+	(struct gpio_regs*)	GPIO0_BASE,
+};
+
+const struct emac_regs* EMAC_ADDR[]=
+{
+	(struct emac_regs*) EMAC0_BASE,
+	(struct emac_regs*) EMAC1_BASE
+};
+
+const struct zmii_regs* ZMII_ADDR[]=
+{
+	(zmii_t*)	ZMII0_BASE,
+};
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405l.h b/arch/ppc/platforms/4xx/ibmnp405l.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmnp405l.h	Fri Oct 11 21:22:55 2002
@@ -0,0 +1,156 @@
+/*
+ * ibmnp405l.h
+ *
+ *	This was dirived from the ibm405gp.h and other previus works in ppc4xx.h
+ *
+ *      Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *      Oct, 2001
+ *
+ *
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 (01/10/10) - A. Kuster
+ *	Initial version
+ *
+ *	Version 1.1 (02/01/16) - A. Kuster
+ *	Cleaned out common 405B3 core stuff
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBMNP405L_H__
+#define __ASM_IBMNP405L_H__
+
+#include <linux/config.h>
+#include <platforms/ibm_ocp.h>
+
+/* ibm405.h at bottom of this file */
+
+#define PPC4xx_PCI_IO_ADDR	((uint)PPC405_PCI_PHY_IO_BASE)
+#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
+#define PPC4xx_PCI_CFG_ADDR	((uint)PPC405_PCI_CONFIG_ADDR)
+#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
+#define PPC4xx_PCI_LCFG_ADDR	((uint)0xef400000)
+#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
+#define PPC4xx_ONB_IO_ADDR	((uint)0xef600000)
+#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
+
+/* serial port defines */
+#define RS_TABLE_SIZE	2
+
+#define UART0_INT	0
+#define UART1_INT	1
+
+#define UART0_IO_BASE	(u8 *)0xEF600300
+#define UART1_IO_BASE	(u8 *)0xEF600400
+#define IIC0_BASE	0xEF600500
+#define OPB0_BASE	0xEF600600
+#define GPIO0_BASE	0xEF600700
+#define EMAC0_BASE	0xEF600800
+#define EMAC1_BASE	0xEF600900
+#define ZMII0_BASE	0xEF600C10
+
+#define EMAC_NUMS	2
+#define UART_NUMS	2
+#define ZMII_NUMS	1
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_PORT_DFNS        \
+        STD_UART_OP(0)          \
+        STD_UART_OP(1)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_PORT_DFNS        \
+        STD_UART_OP(1)          \
+        STD_UART_OP(0)
+#endif
+
+/* DCR defines */
+/* ------------------------------------------------------------------------- */
+
+#define DCRN_CHCR_BASE	0x0B1
+#define DCRN_CHPSR_BASE	0x0B4
+#define DCRN_CPMSR_BASE	0x0B8
+#define DCRN_CPMFR_BASE	0x0BA
+
+#define CPM_IIC0	0x80000000	/* IIC interface */
+#define CPM_PCI		0x40000000	/* PCI bridge */
+#define CPM_CPU		0x20000000	/* processor core */
+#define CPM_DMA		0x10000000	/* DMA controller */
+#define CPM_BRG		0x08000000	/* PLB to OPB bridge */
+#define CPM_DCP		0x04000000	/* CodePack */
+#define CPM_EBC		0x02000000	/* ROM/SRAM peripheral controller */
+#define CPM_SDRAM0	0x01000000	/* SDRAM memory controller */
+#define CPM_PLB		0x00800000	/* PLB bus arbiter */
+#define CPM_GPIO0	0x00400000	/* General Purpose IO (??) */
+#define CPM_UART0	0x00200000	/* serial port 0 */
+#define CPM_UART1	0x00100000	/* serial port 1 */
+#define CPM_UIC		0x00080000	/* Universal Interrupt Controller */
+#define CPM_TMRCLK	0x00040000	/* CPU timers */
+#define CPM_EMAC_MM	0x00020000	/* on-chip ethernet MM unit */
+#define CPM_EMAC_RM	0x00010000	/* on-chip ethernet RM unit */
+#define CPM_EMAC_TM	0x00008000	/* on-chip ethernet TM unit */
+
+#define DCRN_DMA0_BASE	0x100
+#define DCRN_DMA1_BASE	0x108
+#define DCRN_DMA2_BASE	0x110
+#define DCRN_DMA3_BASE	0x118
+#define DCRNCAP_DMA_SG	1	/* have DMA scatter/gather capability */
+#define DCRN_DMASR_BASE	0x120
+#define DCRN_EBC_BASE	0x012
+#define DCRN_DCP0_BASE	0x014
+#define DCRN_MAL_BASE	0x180
+#define DCRN_OCM0_BASE	0x018
+#define DCRN_PLB0_BASE	0x084
+#define DCRN_PLLMR_BASE	0x0B0
+#define DCRN_POB0_BASE	0x0A0
+#define DCRN_SDRAM0_BASE 0x010
+#define DCRN_UIC0_BASE	0x0C0
+#define DCRN_UIC1_BASE	0x0C0
+
+/* need to clean this up - armin */
+
+#ifdef DCRN_UIC1_BASE
+#define DCRN_UIC1_SR	(DCRN_UIC1_BASE + 0x0)
+#define DCRN_UIC1_SRS	(DCRN_UIC1_BASE + 0x1)
+#define DCRN_UIC1_ER	(DCRN_UIC1_BASE + 0x2)
+#define DCRN_UIC1_CR	(DCRN_UIC1_BASE + 0x3)
+#define DCRN_UIC1_PR	(DCRN_UIC1_BASE + 0x4)
+#define DCRN_UIC1_TR	(DCRN_UIC1_BASE + 0x5)
+#define DCRN_UIC1_MSR	(DCRN_UIC1_BASE + 0x6)
+#define DCRN_UIC1_VR	(DCRN_UIC1_BASE + 0x7)
+#define DCRN_UIC1_VCR	(DCRN_UIC1_BASE + 0x8)
+#endif
+
+#include <platforms/ibm405.h>
+
+#endif				/* __ASM_IBMNP405L_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmstb3.c b/arch/ppc/platforms/4xx/ibmstb3.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmstb3.c	Fri Oct 11 21:22:50 2002
@@ -0,0 +1,53 @@
+/*
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *	Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *
+ *    Module name: ibmstb3.c
+ *
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *      History: 01/08/2002 - armin
+ *		initial release
+ *
+ */
+
+#include <linux/config.h>
+#include <platforms/ibmstb3.h>
+
+const struct NS16550* COM_PORTS[] =
+{
+  (struct NS16550*) UART0_IO_BASE,
+};
+
+const struct iic_regs* IIC_ADDR[]=
+{
+	(struct iic_regs*) IIC0_BASE,
+};
+
+const struct gpio_regs* GPIO_ADDR[] =
+{
+	(struct gpio_regs*)	GPIO0_BASE,
+};
+
diff -Nru a/arch/ppc/platforms/4xx/ibmstb3.h b/arch/ppc/platforms/4xx/ibmstb3.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmstb3.h	Fri Oct 11 21:23:04 2002
@@ -0,0 +1,288 @@
+/*
+ * ibmstbx.h
+ *
+ *	This was dirived from the ppc4xx.h and all stbx specific definitions
+ *	are located here.
+ *
+ *      Armin Kuster <akuster@mvista.com>
+ *      Tom Rini <trini@mvista.com>
+ *      Oct, 2001
+ *
+ *
+ *
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 Oct 10, 2001 - A. Kuster
+ *	Initial version	 - moved stbx  specific out of ibm4xx.h
+ *
+ *	Version 1.1 Oct 25, 2001 - T. Rini
+ *	Lots of cleanups, and we get included by the board-specific file.
+ *
+ *	Version 1.2 Jan 16, 2002 - A. Kuster
+ *	Removed common dcr offests that are now in ibm405.h 
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBMSTBX_H__
+#define __ASM_IBMSTBX_H__
+
+#include <linux/config.h>
+#include <platforms/ibm_ocp.h>
+
+/* ibm405.h at bottom of this file */
+
+/*
+ * Memory map for the IBM "Redwood-4" STB03xxx evaluation board.
+ *
+ * The  STB03xxx internal i/o addresses don't work for us 1:1,
+ * so we need to map them at a well know virtual address.
+ *
+ * 4000 000x   uart1           -> 0xe000 000x
+ * 4001 00xx   ppu
+ * 4002 00xx   smart card
+ * 4003 000x   iic
+ * 4004 000x   uart0
+ * 4005 0xxx   timer
+ * 4006 00xx   gpio
+ * 4007 00xx   smart card
+ * 400b 000x   iic
+ * 400c 000x   scp
+ * 400d 000x   modem
+ */
+
+#define STB03xxx_IO_BASE	((uint)0xe0000000)
+#define PPC4xx_ONB_IO_PADDR	((uint)0x40000000)
+#define PPC4xx_ONB_IO_VADDR	STB03xxx_IO_BASE
+#define PPC4xx_ONB_IO_SIZE	((uint)14*64*1024)
+
+/* Since we're into address mapping hacks, at least try to hide
+ * it under a macro.....
+ */
+#define STB03xxx_MAP_IO_ADDR(a)	(((uint)(a) & 0x000fffff) + PPC4xx_ONB_IO_VADDR)
+
+#define RS_TABLE_SIZE		1
+#define UART0_INT		20
+#ifdef __BOOTER__
+#define UART0_IO_BASE		(u8 *)0x40040000
+#else
+#define UART0_IO_BASE		(u8 *)STB03xxx_MAP_IO_ADDR(0x40040000)
+#endif
+
+ /* UART 0 is duped here so when the SICC is the default console
+  * then ttys1 is configured properly - armin 
+  */
+
+#define UART1_INT		20
+#ifdef __BOOTER__
+#define UART1_IO_BASE		(u8 *)0x40040000
+#else
+#define UART1_IO_BASE		(u8 *)STB03xxx_MAP_IO_ADDR(0x40040000)
+#endif
+
+/* need to make this work in scheme - armin */
+
+#define SICC0_INTRX		21
+#define SICC0_INTTX		22
+#define SICC0_IO_BASE		((uint* )0x40000000)
+
+#define IIC0_BASE	0x40030000
+#define IIC1_BASE	0x400b0000
+#define OPB0_BASE	0x40010000
+#define GPIO0_BASE	0x40060000
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(1)
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#define DCRN_DCRX_BASE		0x020
+#define DCRN_CIC_BASE 		0x030
+#define DCRN_UIC0_BASE		0x040
+#define DCRN_PLB0_BASE		0x054
+#define DCRN_PLB1_BASE		0x064
+#define DCRN_EBIMC_BASE		0x070
+#define DCRN_POB0_BASE		0x0B0
+
+#define DCRN_BE_BASE		0x090
+#define DCRN_DMA0_BASE		0x0C0
+#define DCRN_DMA1_BASE		0x0C8
+#define DCRN_DMA2_BASE		0x0D0
+#define DCRN_DMA3_BASE		0x0D8
+#define DCRNCAP_DMA_CC		1	/* have DMA chained count capability */
+#define DCRN_DMASR_BASE		0x0E0
+
+#define DCRN_CPMFR_BASE		0x102
+#define DCRN_SCCR_BASE		0x120
+
+#define CPM_IIC0	0x80000000	/* IIC 0 interface */
+#define CPM_I1284	0x40000000	/* IEEE-1284 */
+#define CPM_IIC1	0x20000000	/* IIC 1 interface */
+#define CPM_CPU		0x10000000	/* PPC405B3 clock control */
+#define CPM_AUD		0x08000000	/* Audio Decoder */
+#define CPM_EBIU	0x04000000	/* External Bus Interface Unit */
+#define CPM_SDRAM1	0x02000000	/* SDRAM 1 memory controller */
+#define CPM_DMA		0x01000000	/* DMA controller */
+#define CPM_RES_1	0x00800000	/* reserved */
+#define CPM_RES_2	0x00400000	/* reserved */
+#define CPM_RES_3	0x00200000	/* reserved */
+#define CPM_UART1	0x00100000	/* Serial 1 / Infrared */
+#define CPM_UART0	0x00080000	/* Serial 0 / 16550 */
+#define CPM_DCRX	0x00040000	/* DCR Extension */
+#define CPM_SC0		0x00020000	/* Smart Card 0 */
+#define CPM_RES_4	0x00010000	/* reserved */
+#define CPM_SC1		0x00008000	/* Smart Card 1 */
+#define CPM_SDRAM0	0x00004000	/* SDRAM 0 memory controller */
+#define CPM_XPT54	0x00002000	/* Transport - 54 Mhz */
+#define CPM_CBS		0x00001000	/* Cross Bar Switch */
+#define CPM_GPT		0x00000800	/* GPTPWM */
+#define CPM_GPIO0	0x00000400	/* General Purpose IO 0 */
+#define CPM_DENC	0x00000200	/* Digital video Encoder */
+#define CPM_TMRCLK	0x00000100	/* CPU timers */
+#define CPM_XPT27	0x00000080	/* Transport - 27 Mhz */
+#define CPM_UIC		0x00000040	/* Universal Interrupt Controller */
+#define CPM_RES_5	0x00000020	/* reserved */
+#define CPM_MSI		0x00000010	/* Modem Serial Interface (SSP) */
+#define CPM_UART2	0x00000008	/* Serial Control Port */
+#define CPM_DSCR	0x00000004	/* Descrambler */
+#define CPM_VID2	0x00000002	/* Video Decoder clock domain 2 */
+#define CPM_RES_6	0x00000001	/* reserved */
+
+/*			0x80000000 */
+#define UIC_XPORT	0x40000000	/* 1 Transport */
+#define UIC_AUDIO	0x20000000	/* 2 Audio Decoder */
+#define UIC_VIDEO	0x10000000	/* 3 Video Decoder */
+#define UIC_D0		0x08000000	/* 4 DMA Channel 0 */
+#define UIC_D1		0x04000000	/* 5 DMA Channel 1 */
+#define UIC_D2		0x02000000	/* 6 DMA Channel 2 */
+#define UIC_D3		0x01000000	/* 7 DMA Channel 3 */
+#define UIC_SC0		0x00800000	/* 8 SmartCard 0 Controller */
+#define UIC_IIC0	0x00400000	/* 9 IIC 0 */
+#define UIC_IIC1	0x00200000	/* 10 IIC 1 */
+#define UIC_PWM0	0x00100000	/* 11 GPT_PWM 0: Capture Timers */
+#define UIC_PWM1	0x00080000	/* 12 GPT_PWM 1: Compare Timers */
+#define UIC_SCP		0x00040000	/* 13 Serial Control Port */
+#define UIC_SSP		0x00020000	/* 14 Soft Modem/Synchronous Serial Port */
+#define UIC_PWM2	0x00010000	/* 15 GPT_PWM 2: Down Counters */
+#define UIC_SC1		0x00008000	/* 16 SmartCard 1 Controller */
+#define UIC_EIR7	0x00004000	/* 17 External IRQ 7 */
+#define UIC_EIR8	0x00002000	/* 18 External IRQ 8 */
+#define UIC_EIR9	0x00001000	/* 19 External IRQ 9 */
+#define UIC_U0		0x00000800	/* 20 UART0 */
+#define UIC_IR_RCV	0x00000400	/* 21 Serial 1 / Infrared UART Receive */
+#define UIC_IR_XMIT	0x00000200	/* 22 Serial 1 / Infrared UART Transmit */
+#define UIC_IEEE1284	0x00000100	/* 23 IEEE-1284 / PPU */
+#define UIC_DCRX	0x00000080	/* 24 DCRX */
+#define UIC_EIR0	0x00000040	/* 25 External IRQ 0 */
+#define UIC_EIR1	0x00000020	/* 26 External IRQ 1 */
+#define UIC_EIR2	0x00000010	/* 27 External IRQ 2 */
+#define UIC_EIR3	0x00000008	/* 28 External IRQ 3 */
+#define UIC_EIR4	0x00000004	/* 29 External IRQ 4 */
+#define UIC_EIR5	0x00000002	/* 30 External IRQ 5 */
+#define UIC_EIR6	0x00000001	/* 31 External IRQ 6 */
+
+#ifdef DCRN_CIC_BASE
+#define DCRN_CICCR	(DCRN_CIC_BASE + 0x0)	/* CIC Control Register */
+#define DCRN_DMAS1	(DCRN_CIC_BASE + 0x1)	/* DMA Select1 Register */
+#define DCRN_DMAS2	(DCRN_CIC_BASE + 0x2)	/* DMA Select2 Register */
+#define DCRN_CICVCR	(DCRN_CIC_BASE + 0x3)	/* CIC Video COntro Register */
+#define DCRN_CICSEL3	(DCRN_CIC_BASE + 0x5)	/* CIC Select 3 Register */
+#define DCRN_SGPO	(DCRN_CIC_BASE + 0x6)	/* CIC GPIO Output Register */
+#define DCRN_SGPOD	(DCRN_CIC_BASE + 0x7)	/* CIC GPIO OD Register */
+#define DCRN_SGPTC	(DCRN_CIC_BASE + 0x8)	/* CIC GPIO Tristate Ctrl Reg */
+#define DCRN_SGPI	(DCRN_CIC_BASE + 0x9)	/* CIC GPIO Input Reg */
+#endif
+
+#ifdef DCRN_DCRX_BASE
+#define DCRN_DCRXICR	(DCRN_DCRX_BASE + 0x0)	/* Internal Control Register */
+#define DCRN_DCRXISR	(DCRN_DCRX_BASE + 0x1)	/* Internal Status Register */
+#define DCRN_DCRXECR	(DCRN_DCRX_BASE + 0x2)	/* External Control Register */
+#define DCRN_DCRXESR	(DCRN_DCRX_BASE + 0x3)	/* External Status Register */
+#define DCRN_DCRXTAR	(DCRN_DCRX_BASE + 0x4)	/* Target Address Register */
+#define DCRN_DCRXTDR	(DCRN_DCRX_BASE + 0x5)	/* Target Data Register */
+#define DCRN_DCRXIGR	(DCRN_DCRX_BASE + 0x6)	/* Interrupt Generation Register */
+#define DCRN_DCRXBCR	(DCRN_DCRX_BASE + 0x7)	/* Line Buffer Control Register */
+#endif
+
+#ifdef DCRN_EBC_BASE
+#define DCRN_EBCCFGADR	(DCRN_EBC_BASE + 0x0)	/* Peripheral Controller Address */
+#define DCRN_EBCCFGDATA	(DCRN_EBC_BASE + 0x1)	/* Peripheral Controller Data */
+#endif
+
+#ifdef DCRN_EBIMC_BASE
+#define DCRN_BRCRH0	(DCRN_EBIMC_BASE + 0x0)	/* Bus Region Config High 0 */
+#define DCRN_BRCRH1	(DCRN_EBIMC_BASE + 0x1)	/* Bus Region Config High 1 */
+#define DCRN_BRCRH2	(DCRN_EBIMC_BASE + 0x2)	/* Bus Region Config High 2 */
+#define DCRN_BRCRH3	(DCRN_EBIMC_BASE + 0x3)	/* Bus Region Config High 3 */
+#define DCRN_BRCRH4	(DCRN_EBIMC_BASE + 0x4)	/* Bus Region Config High 4 */
+#define DCRN_BRCRH5	(DCRN_EBIMC_BASE + 0x5)	/* Bus Region Config High 5 */
+#define DCRN_BRCRH6	(DCRN_EBIMC_BASE + 0x6)	/* Bus Region Config High 6 */
+#define DCRN_BRCRH7	(DCRN_EBIMC_BASE + 0x7)	/* Bus Region Config High 7 */
+#define DCRN_BRCR0	(DCRN_EBIMC_BASE + 0x10)	/* BRC 0 */
+#define DCRN_BRCR1	(DCRN_EBIMC_BASE + 0x11)	/* BRC 1 */
+#define DCRN_BRCR2	(DCRN_EBIMC_BASE + 0x12)	/* BRC 2 */
+#define DCRN_BRCR3	(DCRN_EBIMC_BASE + 0x13)	/* BRC 3 */
+#define DCRN_BRCR4	(DCRN_EBIMC_BASE + 0x14)	/* BRC 4 */
+#define DCRN_BRCR5	(DCRN_EBIMC_BASE + 0x15)	/* BRC 5 */
+#define DCRN_BRCR6	(DCRN_EBIMC_BASE + 0x16)	/* BRC 6 */
+#define DCRN_BRCR7	(DCRN_EBIMC_BASE + 0x17)	/* BRC 7 */
+#define DCRN_BEAR0	(DCRN_EBIMC_BASE + 0x20)	/* Bus Error Address Register */
+#define DCRN_BESR0	(DCRN_EBIMC_BASE + 0x21)	/* Bus Error Status Register */
+#define DCRN_BIUCR	(DCRN_EBIMC_BASE + 0x2A)	/* Bus Interfac Unit Ctrl Reg */
+#endif
+
+#ifdef DCRN_SCCR_BASE
+#define DCRN_SCCR	(DCRN_SCCR_BASE + 0x0)
+#endif
+
+#ifdef DCRN_SDRAM0_BASE
+#define DCRN_SDRAM0_CFGADDR	(DCRN_SDRAM0_BASE + 0x0)	/* Memory Controller Address */
+#define DCRN_SDRAM0_CFGDATA	(DCRN_SDRAM0_BASE + 0x1)	/* Memory Controller Data */
+#endif
+
+#ifdef DCRN_OCM0_BASE
+#define DCRN_OCMISARC	(DCRN_OCM0_BASE + 0x0)	/* OCM Instr Side Addr Range Compare */
+#define DCRN_OCMISCR	(DCRN_OCM0_BASE + 0x1)	/* OCM Instr Side Control */
+#define DCRN_OCMDSARC	(DCRN_OCM0_BASE + 0x2)	/* OCM Data Side Addr Range Compare */
+#define DCRN_OCMDSCR	(DCRN_OCM0_BASE + 0x3)	/* OCM Data Side Control */
+#endif
+
+#include <platforms/ibm405.h>
+
+#endif				/* __ASM_IBMSTBX_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmstb4.c b/arch/ppc/platforms/4xx/ibmstb4.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmstb4.c	Fri Oct 11 21:22:54 2002
@@ -0,0 +1,61 @@
+/*
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *	Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *
+ *    Module name: ibmstb4.c
+ *
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *      History: 12/26/2001 - armin
+ *		initial release
+ *
+ */
+
+#include <linux/config.h>
+#include <platforms/ibmstb4.h>
+
+const struct NS16550* COM_PORTS[] =
+{
+  (struct NS16550*) UART0_IO_BASE,
+  (struct NS16550*) UART1_IO_BASE,
+  (struct NS16550*) UART2_IO_BASE,
+};
+
+const struct iic_regs* IIC_ADDR[]=
+{
+	(struct iic_regs*) IIC0_BASE,
+};
+
+
+const struct gpio_regs* GPIO_ADDR[] =
+{
+	(struct gpio_regs*)	GPIO0_BASE,
+};
+
+const struct ide_regs* IDE_ADDR[] =
+{
+	(struct ide_regs*) IDE0_IO_ADDR,
+
+};
diff -Nru a/arch/ppc/platforms/4xx/ibmstb4.h b/arch/ppc/platforms/4xx/ibmstb4.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/ibmstb4.h	Fri Oct 11 21:23:04 2002
@@ -0,0 +1,268 @@
+/*
+ * ibmstb4.h
+ *
+ *	This was dirived from the ibm405gp.h and other previus works in ppc4xx.h
+ *
+ *      Current maintainer
+ *      Armin Kuster akuster@mvista.com
+ *      DEC, 2001
+ *
+ *
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 (01/10/10) - A. Kuster
+ *	Initial version	
+ *
+ *	Version 1.1 02/01/17 - A. Kuster
+ *	moved common offsets to ibm405.h
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBMSTB4_H__
+#define __ASM_IBMSTB4_H__
+
+#include <linux/config.h>
+#include <platforms/ibm_ocp.h>
+
+/* serial port defines */
+#define STB04xxx_IO_BASE	((uint)0xe0000000)
+#define PPC4xx_PCI_IO_ADDR	STB04xxx_IO_BASE
+#define PPC4xx_ONB_IO_PADDR	STB04xxx_IO_BASE
+#define PPC4xx_ONB_IO_VADDR	((uint)0xe0000000)
+#define PPC4xx_ONB_IO_SIZE	((uint)14*64*1024)
+
+/*
+ * map STB04xxx internal i/o address (0x400x00xx) to an address
+ * which is below the 2GB limit...
+ *
+ * 4000 000x	uart1		-> 0xe000 000x
+ * 4001 00xx	ppu
+ * 4002 00xx	smart card
+ * 4003 000x	iic
+ * 4004 000x	uart0
+ * 4005 0xxx	timer
+ * 4006 00xx	gpio
+ * 4007 00xx	smart card
+ * 400b 000x	iic
+ * 400c 000x	scp
+ * 400d 000x	modem
+ * 400e 000x	uart2
+*/
+#define STB04xxx_MAP_IO_ADDR(a)	(((uint)(a)) + (STB04xxx_IO_BASE - 0x40000000))
+
+#define RS_TABLE_SIZE		3
+#define UART0_INT		20
+#define UART0_IO_BASE		(u8 *)0x40040000
+#define UART1_INT		21
+#define UART1_IO_BASE		(u8 *)0x40000000
+#define UART2_INT		31
+#define UART2_IO_BASE		(u8 *)0x400e0000
+
+#define IDE0_IO_ADDR	0x400F0000
+#define IDE0_IO_SIZE	0x200
+
+#define IIC0_BASE	0x40030000
+#define IIC1_BASE	0x400b0000
+#define OPB0_BASE	0x40000000
+#define GPIO0_BASE	0x40060000
+
+#define UART_NUMS	3
+
+#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM},
+
+#if defined(CONFIG_UART0_TTYS0)
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)		\
+	STD_UART_OP(2)
+#endif
+
+#if defined(CONFIG_UART0_TTYS1)
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(1)		\
+	STD_UART_OP(0)		\
+	STD_UART_OP(2)
+#endif
+
+#if defined(CONFIG_UART0_TTYS2)
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(2)		\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)
+#endif
+
+#define DCRN_BE_BASE		0x090
+#define DCRN_DMA0_BASE		0x0C0
+#define DCRN_DMA1_BASE		0x0C8
+#define DCRN_DMA2_BASE		0x0D0
+#define DCRN_DMA3_BASE		0x0D8
+#define DCRNCAP_DMA_CC		1	/* have DMA chained count capability */
+#define DCRN_DMASR_BASE		0x0E0
+#define DCRN_PLB0_BASE		0x054
+#define DCRN_PLB1_BASE		0x064
+#define DCRN_POB0_BASE		0x0B0
+#define DCRN_SCCR_BASE		0x120
+#define DCRN_UIC0_BASE		0x040
+#define DCRN_BE_BASE		0x090
+#define DCRN_DMA0_BASE		0x0C0
+#define DCRN_DMA1_BASE		0x0C8
+#define DCRN_DMA2_BASE		0x0D0
+#define DCRN_DMA3_BASE		0x0D8
+#define DCRN_CIC_BASE 		0x030
+#define DCRN_DMASR_BASE		0x0E0
+#define DCRN_EBIMC_BASE		0x070
+#define DCRN_DCRX_BASE		0x020
+#define DCRN_CPMFR_BASE		0x102
+#define DCRN_SCCR_BASE		0x120
+
+#define CPM_IIC0	0x80000000	/* IIC 0 interface */
+#define CPM_I1284	0x40000000	/* IEEE-1284 */
+#define CPM_IIC1	0x20000000	/* IIC 1 interface */
+#define CPM_CPU		0x10000000	/* PPC405B3 clock control */
+#define CPM_AUD		0x08000000	/* Audio Decoder */
+#define CPM_EBIU	0x04000000	/* External Bus Interface Unit */
+#define CPM_SDRAM1	0x02000000	/* SDRAM 1 memory controller */
+#define CPM_DMA		0x01000000	/* DMA controller */
+#define CPM_RES_1	0x00800000	/* reserved */
+#define CPM_RES_2	0x00400000	/* reserved */
+#define CPM_RES_3	0x00200000	/* reserved */
+#define CPM_UART1	0x00100000	/* Serial 1 / Infrared */
+#define CPM_UART0	0x00080000	/* Serial 0 / 16550 */
+#define CPM_DCRX	0x00040000	/* DCR Extension */
+#define CPM_SC0		0x00020000	/* Smart Card 0 */
+#define CPM_RES_4	0x00010000	/* reserved */
+#define CPM_SC1		0x00008000	/* Smart Card 1 */
+#define CPM_SDRAM0	0x00004000	/* SDRAM 0 memory controller */
+#define CPM_XPT54	0x00002000	/* Transport - 54 Mhz */
+#define CPM_CBS		0x00001000	/* Cross Bar Switch */
+#define CPM_GPT		0x00000800	/* GPTPWM */
+#define CPM_GPIO0	0x00000400	/* General Purpose IO 0 */
+#define CPM_DENC	0x00000200	/* Digital video Encoder */
+#define CPM_TMRCLK	0x00000100	/* CPU timers */
+#define CPM_XPT27	0x00000080	/* Transport - 27 Mhz */
+#define CPM_UIC		0x00000040	/* Universal Interrupt Controller */
+#define CPM_RES_5	0x00000020	/* reserved */
+#define CPM_MSI		0x00000010	/* Modem Serial Interface (SSP) */
+#define CPM_UART2	0x00000008	/* Serial Control Port */
+#define CPM_DSCR	0x00000004	/* Descrambler */
+#define CPM_VID2	0x00000002	/* Video Decoder clock domain 2 */
+#define CPM_RES_6	0x00000001	/* reserved */
+
+/*			0x80000000 */
+#define UIC_XPORT	0x40000000	/* 1 Transport */
+#define UIC_AUDIO	0x20000000	/* 2 Audio Decoder */
+#define UIC_VIDEO	0x10000000	/* 3 Video Decoder */
+#define UIC_D0		0x08000000	/* 4 DMA Channel 0 */
+#define UIC_D1		0x04000000	/* 5 DMA Channel 1 */
+#define UIC_D2		0x02000000	/* 6 DMA Channel 2 */
+#define UIC_D3		0x01000000	/* 7 DMA Channel 3 */
+#define UIC_SC0		0x00800000	/* 8 SmartCard 0 Controller */
+#define UIC_IIC0	0x00400000	/* 9 IIC 0 */
+#define UIC_IIC1	0x00200000	/* 10 IIC 1 */
+#define UIC_PWM0	0x00100000	/* 11 GPT_PWM 0: Capture Timers */
+#define UIC_PWM1	0x00080000	/* 12 GPT_PWM 1: Compare Timers */
+#define UIC_SCP		0x00040000	/* 13 Serial Control Port */
+#define UIC_SSP		0x00020000	/* 14 Soft Modem/Synchronous Serial Port */
+#define UIC_PWM2	0x00010000	/* 15 GPT_PWM 2: Down Counters */
+#define UIC_SC1		0x00008000	/* 16 SmartCard 1 Controller */
+#define UIC_EIR7	0x00004000	/* 17 External IRQ 7 */
+#define UIC_EIR8	0x00002000	/* 18 External IRQ 8 */
+#define UIC_EIR9	0x00001000	/* 19 External IRQ 9 */
+#define UIC_U0		0x00000800	/* 20 UART0 */
+#define UIC_IR_RCV	0x00000400	/* 21 Serial 1 / Infrared UART Receive */
+#define UIC_IR_XMIT	0x00000200	/* 22 Serial 1 / Infrared UART Transmit */
+#define UIC_IEEE1284	0x00000100	/* 23 IEEE-1284 / PPU */
+#define UIC_DCRX	0x00000080	/* 24 DCRX */
+#define UIC_EIR0	0x00000040	/* 25 External IRQ 0 */
+#define UIC_EIR1	0x00000020	/* 26 External IRQ 1 */
+#define UIC_EIR2	0x00000010	/* 27 External IRQ 2 */
+#define UIC_EIR3	0x00000008	/* 28 External IRQ 3 */
+#define UIC_EIR4	0x00000004	/* 29 External IRQ 4 */
+#define UIC_EIR5	0x00000002	/* 30 External IRQ 5 */
+#define UIC_EIR6	0x00000001	/* 31 External IRQ 6 */
+
+#define DCRN_BEAR	(DCRN_BE_BASE + 0x0)	/* Bus Error Address Register */
+#define DCRN_BESR	(DCRN_BE_BASE + 0x1)	/* Bus Error Syndrome Register */
+/* DCRN_BESR */
+#define BESR_DSES	0x80000000	/* Data-Side Error Status */
+#define BESR_DMES	0x40000000	/* DMA Error Status */
+#define BESR_RWS	0x20000000	/* Read/Write Status */
+#define BESR_ETMASK	0x1C000000	/* Error Type */
+#define ET_PROT		0
+#define ET_PARITY	1
+#define ET_NCFG		2
+#define ET_BUSERR	4
+#define ET_BUSTO	6
+
+#define CHR1_CETE	0x00800000	/* CPU external timer enable */
+#define CHR1_PCIPW	0x00008000	/* PCI Int enable/Peripheral Write enable */
+
+#define DCRN_CICCR	(DCRN_CIC_BASE + 0x0)	/* CIC Control Register */
+#define DCRN_DMAS1	(DCRN_CIC_BASE + 0x1)	/* DMA Select1 Register */
+#define DCRN_DMAS2	(DCRN_CIC_BASE + 0x2)	/* DMA Select2 Register */
+#define DCRN_CICVCR	(DCRN_CIC_BASE + 0x3)	/* CIC Video COntro Register */
+#define DCRN_CICSEL3	(DCRN_CIC_BASE + 0x5)	/* CIC Select 3 Register */
+#define DCRN_SGPO	(DCRN_CIC_BASE + 0x6)	/* CIC GPIO Output Register */
+#define DCRN_SGPOD	(DCRN_CIC_BASE + 0x7)	/* CIC GPIO OD Register */
+#define DCRN_SGPTC	(DCRN_CIC_BASE + 0x8)	/* CIC GPIO Tristate Ctrl Reg */
+#define DCRN_SGPI	(DCRN_CIC_BASE + 0x9)	/* CIC GPIO Input Reg */
+
+#define DCRN_DCRXICR	(DCRN_DCRX_BASE + 0x0)	/* Internal Control Register */
+#define DCRN_DCRXISR	(DCRN_DCRX_BASE + 0x1)	/* Internal Status Register */
+#define DCRN_DCRXECR	(DCRN_DCRX_BASE + 0x2)	/* External Control Register */
+#define DCRN_DCRXESR	(DCRN_DCRX_BASE + 0x3)	/* External Status Register */
+#define DCRN_DCRXTAR	(DCRN_DCRX_BASE + 0x4)	/* Target Address Register */
+#define DCRN_DCRXTDR	(DCRN_DCRX_BASE + 0x5)	/* Target Data Register */
+#define DCRN_DCRXIGR	(DCRN_DCRX_BASE + 0x6)	/* Interrupt Generation Register */
+#define DCRN_DCRXBCR	(DCRN_DCRX_BASE + 0x7)	/* Line Buffer Control Register */
+
+#define DCRN_BRCRH0	(DCRN_EBIMC_BASE + 0x0)	/* Bus Region Config High 0 */
+#define DCRN_BRCRH1	(DCRN_EBIMC_BASE + 0x1)	/* Bus Region Config High 1 */
+#define DCRN_BRCRH2	(DCRN_EBIMC_BASE + 0x2)	/* Bus Region Config High 2 */
+#define DCRN_BRCRH3	(DCRN_EBIMC_BASE + 0x3)	/* Bus Region Config High 3 */
+#define DCRN_BRCRH4	(DCRN_EBIMC_BASE + 0x4)	/* Bus Region Config High 4 */
+#define DCRN_BRCRH5	(DCRN_EBIMC_BASE + 0x5)	/* Bus Region Config High 5 */
+#define DCRN_BRCRH6	(DCRN_EBIMC_BASE + 0x6)	/* Bus Region Config High 6 */
+#define DCRN_BRCRH7	(DCRN_EBIMC_BASE + 0x7)	/* Bus Region Config High 7 */
+#define DCRN_BRCR0	(DCRN_EBIMC_BASE + 0x10)	/* BRC 0 */
+#define DCRN_BRCR1	(DCRN_EBIMC_BASE + 0x11)	/* BRC 1 */
+#define DCRN_BRCR2	(DCRN_EBIMC_BASE + 0x12)	/* BRC 2 */
+#define DCRN_BRCR3	(DCRN_EBIMC_BASE + 0x13)	/* BRC 3 */
+#define DCRN_BRCR4	(DCRN_EBIMC_BASE + 0x14)	/* BRC 4 */
+#define DCRN_BRCR5	(DCRN_EBIMC_BASE + 0x15)	/* BRC 5 */
+#define DCRN_BRCR6	(DCRN_EBIMC_BASE + 0x16)	/* BRC 6 */
+#define DCRN_BRCR7	(DCRN_EBIMC_BASE + 0x17)	/* BRC 7 */
+#define DCRN_BEAR0	(DCRN_EBIMC_BASE + 0x20)	/* Bus Error Address Register */
+#define DCRN_BESR0	(DCRN_EBIMC_BASE + 0x21)	/* Bus Error Status Register */
+#define DCRN_BIUCR	(DCRN_EBIMC_BASE + 0x2A)	/* Bus Interfac Unit Ctrl Reg */
+
+#include <platforms/ibm405.h>
+
+#endif				/* __ASM_IBMSTB4_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/redwood.c b/arch/ppc/platforms/4xx/redwood.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/redwood.c	Fri Oct 11 21:23:03 2002
@@ -0,0 +1,47 @@
+/*
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *      Author: MontaVista Software, Inc.  <source@mvista.com>
+ *              Frank Rowand <frank_rowand@mvista.com>
+ *
+ *    Module name: redwood.c
+ *
+ *    Description:
+ *
+ *      History:  11/09/2001 - Armin
+ *      added board_init to add in additional instuctions needed during platfrom_init
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/pgtable.h>
+#include <asm/ibm4xx.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+void __init
+board_setup_arch(void)
+{
+}
+
+void __init
+board_io_mapping(void)
+{
+	int i;
+
+	io_block_mapping(OAKNET_IO_VADDR,
+			 OAKNET_IO_PADDR, OAKNET_IO_SIZE, _PAGE_IO);
+
+}
+
+void __init
+board_setup_irq(void)
+{
+}
+
+void __init
+board_init(void)
+{
+}
diff -Nru a/arch/ppc/platforms/4xx/redwood.h b/arch/ppc/platforms/4xx/redwood.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/redwood.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,51 @@
+/*
+ *    Copyright 2001 MontaVista Software Inc.
+ *	PPC405 modifications
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ *
+ *    Module name: redwood.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to the IBM PowerPC
+ *      STB03xxx "Redwood" evaluation board.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_REDWOOD_H__
+#define __ASM_REDWOOD_H__
+
+/* Redwoods have an STB03xxx or STB04xxx core */
+#include <platforms/ibmstb3.h>
+
+#ifndef __ASSEMBLY__
+typedef struct board_info {
+	unsigned char	bi_s_version[4];	/* Version of this structure */
+	unsigned char	bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	bi_memsize;		/* DRAM installed, in bytes */
+	unsigned int	bi_dummy;		/* field shouldn't exist */
+	unsigned char	bi_enetaddr[6];		/* Ethernet MAC address */
+	unsigned int	bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	bi_busfreq;		/* Bus speed, in Hz */
+	unsigned int	bi_tbfreq;		/* Software timebase freq */
+} bd_t;
+#endif /* !__ASSEMBLY__ */
+
+#define OAKNET_IO_PADDR		((uint)0xf2000000)
+#define OAKNET_IO_VADDR		OAKNET_IO_PADDR
+#define OAKNET_IO_BASE		OAKNET_IO_VADDR
+
+/* ftr revisit- io size was 0xffff in old-line, is 0x40 in oak.h */
+#define OAKNET_IO_SIZE		0xffff
+#define OAKNET_INT		26	/* EXTINT1 */
+
+#define _IO_BASE	0
+#define _ISA_MEM_BASE	0
+#define PCI_DRAM_OFFSET	0
+
+#define BASE_BAUD		1312500
+
+#define PPC4xx_MACHINE_NAME	"IBM Redwood"
+
+#endif /* __ASM_REDWOOD_H__ */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/redwood5.c b/arch/ppc/platforms/4xx/redwood5.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/redwood5.c	Fri Oct 11 21:22:55 2002
@@ -0,0 +1,82 @@
+/*
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *      Author: Armin Kuster
+ *
+ *    Module name: redwood5.c
+ *
+ *    Description:
+ *    	IBM redwood5 eval board file
+ *
+ *      History:  12/29/2001 - Armin
+ *    	initail release
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+void __init
+board_setup_arch(void)
+{
+
+	bd_t *bip = (bd_t *)__res;
+
+#define CONFIG_DEBUG_BRINGUP
+#ifdef CONFIG_DEBUG_BRINGUP
+	printk("\n");
+	printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
+	printk("\n");
+	printk("bi_s_version\t %s\n",      bip->bi_s_version);
+	printk("bi_r_version\t %s\n",      bip->bi_r_version);
+	printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000));
+	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
+	bip->bi_enetaddr[0], bip->bi_enetaddr[1],
+	bip->bi_enetaddr[2], bip->bi_enetaddr[3],
+	bip->bi_enetaddr[4], bip->bi_enetaddr[5]);
+
+	printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
+	       bip->bi_intfreq, bip->bi_intfreq/ 1000000);
+
+	printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
+		bip->bi_busfreq, bip->bi_busfreq / 1000000 );
+	printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n",
+	       bip->bi_tbfreq, bip->bi_tbfreq/1000000);
+
+	printk("\n");
+#endif
+
+}
+
+void __init
+board_io_mapping(void)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+	 unsigned long v, p;
+
+	/* 0x400x0000 -> 0xe00x0000 */
+	p = 0x40000000 | (i << 16);
+	v = STB04xxx_IO_BASE | (i << 16);
+
+	io_block_mapping(v, p, PAGE_SIZE,
+		 _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) | _PAGE_GUARDED);
+	}
+
+
+}
+
+void __init
+board_setup_irq(void)
+{
+}
+
+void __init
+board_init(void)
+{
+}
diff -Nru a/arch/ppc/platforms/4xx/redwood5.h b/arch/ppc/platforms/4xx/redwood5.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/redwood5.h	Fri Oct 11 21:22:52 2002
@@ -0,0 +1,54 @@
+/*
+ *    Copyright 2001 MontaVista Software Inc.
+ *	PPC405 modifications
+ * 	Author: MontaVista Software, Inc.
+ *          Armin Kuster
+ *
+ *    Module name: redwood5.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to the IBM PowerPC
+ *      STB03xxx "Redwood" evaluation board.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_REDWOOD5_H__
+#define __ASM_REDWOOD5_H__
+
+/* Redwood5 has an STB04xxx core */
+#include <platforms/ibmstb4.h>
+
+#ifndef __ASSEMBLY__
+typedef struct board_info {
+	unsigned char	bi_s_version[4];	/* Version of this structure */
+	unsigned char	bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	bi_memsize;		/* DRAM installed, in bytes */
+	unsigned int	bi_dummy;		/* field shouldn't exist */
+	unsigned char	bi_enetaddr[6];		/* Ethernet MAC address */
+	unsigned int	bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	bi_busfreq;		/* Bus speed, in Hz */
+	unsigned int	bi_tbfreq;		/* Software timebase freq */
+} bd_t;
+#endif /* !__ASSEMBLY__ */
+
+
+#define SMC91111_BASE_ADDR	0xf2000300
+#define SMC91111_IRQ		28
+
+#ifdef MAX_HWIFS
+#undef MAX_HWIFS
+#endif
+#define MAX_HWIFS		1
+
+#define _IO_BASE	0
+#define _ISA_MEM_BASE	0
+#define PCI_DRAM_OFFSET	0
+
+/* serail defines moved from ppc4xx_serial.h *
+ */
+#define BASE_BAUD		1267200
+
+#define PPC4xx_MACHINE_NAME	"IBM Redwood5"
+
+#endif /* __ASM_REDWOOD5_H__ */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/walnut.c b/arch/ppc/platforms/4xx/walnut.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/walnut.c	Fri Oct 11 21:23:00 2002
@@ -0,0 +1,260 @@
+/*
+ *
+ *    Copyrigh t(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *      Author: MontaVista Software, Inc.  <source@mvista.com>
+ *
+ *    Module name: walnut.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      IBM PowerPC 4xx based boards. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ *      History: 11/09/2001 - armin
+ *      added board_init to add in additional instuctions needed during platfrom_init
+ *
+ *      01/22/2002 - Armin
+ *      converted pci to ocp
+ *
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <platforms/ibm_ocp.h>
+
+#ifdef CONFIG_PPC_RTC
+#include <asm/todc.h>
+#endif
+
+#include "walnut.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void *kb_cs;
+void *kb_data;
+void *walnut_rtc_base;
+
+/* Some IRQs unique to Walnut.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *      A       B       C       D
+	     */
+	{
+		{28, 28, 28, 28},	/* IDSEL 1 - PCI slot 1 */
+		{29, 29, 29, 29},	/* IDSEL 2 - PCI slot 2 */
+		{30, 30, 30, 30},	/* IDSEL 3 - PCI slot 3 */
+		{31, 31, 31, 31},	/* IDSEL 4 - PCI slot 4 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+board_setup_arch(void)
+{
+	void *fpga_brdc;
+	unsigned char fpga_brdc_data;
+	void *fpga_enable;
+	void *fpga_polarity;
+	void *fpga_status;
+	void *fpga_trigger;
+
+	kb_data = ioremap(WALNUT_PS2_BASE, 8);
+	if (!kb_data) {
+		printk(KERN_CRIT
+		       "walnut_setup_arch() kb_data ioremap failed\n");
+		return;
+	}
+
+	kb_cs = kb_data + 1;
+
+	fpga_status = ioremap(WALNUT_FPGA_BASE, 8);
+	if (!fpga_status) {
+		printk(KERN_CRIT
+		       "walnut_setup_arch() fpga_status ioremap failed\n");
+		return;
+	}
+
+	fpga_enable = fpga_status + 1;
+	fpga_polarity = fpga_status + 2;
+	fpga_trigger = fpga_status + 3;
+	fpga_brdc = fpga_status + 4;
+
+	/* split the keyboard and mouse interrupts */
+	fpga_brdc_data = readb(fpga_brdc);
+	fpga_brdc_data |= 0x80;
+	writeb(fpga_brdc_data, fpga_brdc);
+
+	writeb(0x3, fpga_enable);
+
+	writeb(0x3, fpga_polarity);
+
+	writeb(0x3, fpga_trigger);
+
+#ifdef CONFIG_PPC_RTC
+	/* RTC step for the walnut */
+	walnut_rtc_base = (void *) WALNUT_RTC_VADDR;
+	TODC_INIT(TODC_TYPE_DS1743, walnut_rtc_base, walnut_rtc_base,
+		  walnut_rtc_base, 8);
+#endif				/* CONFIG_PPC_RTC */
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, void *pcil0_base)
+{
+
+	unsigned int bar_response, bar;
+	struct pcil0_regs *pcip;
+	/*
+	 * Expected PCI mapping:
+	 *
+	 *  PLB addr             PCI memory addr
+	 *  ---------------------       ---------------------
+	 *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
+	 *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
+	 *
+	 *  PLB addr             PCI io addr
+	 *  ---------------------       ---------------------
+	 *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
+	 *
+	 * The following code is simplified by assuming that the bootrom
+	 * has been well behaved in following this mapping.
+	 */
+
+#ifdef DEBUG
+	int i;
+	pcip = (struct pcil0_regs *) pcil0_base;
+
+	printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+	printk("PCI bridge regs before fixup \n");
+	for (i = 0; i <= 3; i++) {
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+	}
+	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#else
+	pcip = (struct pcil0_regs *) pcil0_base;
+#endif
+
+	/* added for IBM boot rom version 1.15 bios bar changes  -AK */
+
+	/* Disable region first */
+	out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+	/* PLB starting addr, PCI: 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+	/* PCI start addr, 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+	/* 512MB range of PLB to PCI */
+	out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+	/* Enable no pre-fetch, enable region */
+	out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+						(PPC405_PCI_UPPER_MEM -
+						 PPC405_PCI_MEM_BASE)) | 0x01));
+
+	/* Disable region one */
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm1ms), 0x00000000);
+
+	/* Disable region two */
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+	/* Zero config bars */
+	for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+		early_write_config_dword(hose, hose->first_busno,
+					 PCI_FUNC(hose->first_busno), bar,
+					 0x00000000);
+		early_read_config_dword(hose, hose->first_busno,
+					PCI_FUNC(hose->first_busno), bar,
+					&bar_response);
+		DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+		    hose->first_busno, PCI_SLOT(hose->first_busno),
+		    PCI_FUNC(hose->first_busno), bar, bar_response);
+	}
+	/* end work arround */
+
+#ifdef DEBUG
+	printk("PCI bridge regs after fixup \n");
+	for (i = 0; i <= 3; i++) {
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+	}
+	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+}
+
+void __init
+board_io_mapping(void)
+{
+	io_block_mapping(WALNUT_RTC_VADDR,
+			 WALNUT_RTC_PADDR, WALNUT_RTC_SIZE, _PAGE_IO);
+}
+
+void __init
+board_setup_irq(void)
+{
+}
+
+void __init
+board_init(void)
+{
+#ifdef CONFIG_PPC_RTC
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+#endif
+}
diff -Nru a/arch/ppc/platforms/4xx/walnut.h b/arch/ppc/platforms/4xx/walnut.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/4xx/walnut.h	Fri Oct 11 21:22:58 2002
@@ -0,0 +1,80 @@
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Copyright 2000 MontaVista Software Inc.
+ *	PPC405 modifications
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *
+ *    Module name: ppc405.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to the IBM PowerPC
+ *      based boards.
+ *
+ *      This includes:
+ *
+ *         405GP "Walnut" evaluation board
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_WALNUT_H__
+#define __ASM_WALNUT_H__
+
+/* We have a 405GP core */
+#include <platforms/ibm405gp.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Walnut" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
+	unsigned char	 bi_pci_enetaddr[6];	/* PCI Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
+	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+
+/* Memory map for the IBM "Walnut" 405GP evaluation board.
+ * Generic 4xx plus RTC.
+ */
+
+extern void *walnut_rtc_base;
+#define WALNUT_RTC_PADDR	((uint)0xf0000000)
+#define WALNUT_RTC_VADDR	WALNUT_RTC_PADDR
+#define WALNUT_RTC_SIZE		((uint)8*1024)
+
+/* ps2 keyboard and mouse */
+#define KEYBOARD_IRQ		25
+#define AUX_IRQ			26
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD		201600
+#else
+#define BASE_BAUD		691200
+#endif
+
+#define WALNUT_PS2_BASE		0xF0100000
+#define WALNUT_FPGA_BASE	0xF0300000
+
+#define PPC4xx_MACHINE_NAME	"IBM Walnut"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_WALNUT_H__ */
+#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile	Fri Oct 11 21:23:05 2002
+++ b/arch/ppc/platforms/Makefile	Fri Oct 11 21:23:05 2002
@@ -14,13 +14,6 @@
 
 export-objs			:= prep_setup.o
 
-obj-$(CONFIG_CEDER)		+= ceder.o ibmnp405l.o
-obj-$(CONFIG_CPCI405)		+= cpci405.o ibm405gp.o
-obj-$(CONFIG_EP405)		+= ep405.o ibm405gp.o 
-obj-$(CONFIG_REDWOOD_4)		+= redwood.o ibmstb3.o
-obj-$(CONFIG_REDWOOD_5)		+= redwood5.o ibmstb4.o
-obj-$(CONFIG_WALNUT)		+= walnut.o ibm405gp.o
-obj-$(CONFIG_ASH)		+= ash.o ibmnp405h.o
 obj-$(CONFIG_APUS)		+= apus_setup.o
 ifeq ($(CONFIG_APUS),y)
 obj-$(CONFIG_PCI)		+= apus_pci.o
diff -Nru a/arch/ppc/platforms/ash.c b/arch/ppc/platforms/ash.c
--- a/arch/ppc/platforms/ash.c	Fri Oct 11 21:22:54 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,108 +0,0 @@
-/*
- *
- *    Copyright 2001 MontaVista Software Inc.
- *        <akuster@mvista.com>
- *	IBM NP405H ash eval board
- *
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/pci.h>
-
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_PPC_RTC
-#include <asm/todc.h>
-#endif
-
-void *ash_rtc_base;
-
-/* Some IRQs unique to Walnut.
- * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
- */
-int __init
-ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	/*
-	 *      PCI IDSEL/INTPIN->INTLINE
-	 *      A       B       C       D
-	 */
-	{
-		{28, 28, 28, 28},	/* IDSEL 1 - PCI slot 1 */
-		{29, 29, 29, 29},	/* IDSEL 2 - PCI slot 2 */
-		{30, 30, 30, 30},	/* IDSEL 3 - PCI slot 3 */
-		{31, 31, 31, 31},	/* IDSEL 4 - PCI slot 4 */
-	};
-
-	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-};
-
-void __init
-board_setup_arch(void)
-{
-
-	bd_t *bip = (bd_t *)__res;
-
-#ifdef CONFIG_PPC_RTC
-        /* RTC step for the walnut */
-        ash_rtc_base = (void *) ASH_RTC_VADDR;
-	TODC_INIT(TODC_TYPE_DS1743, ash_rtc_base, ash_rtc_base,ash_rtc_base, 8);
-#endif /* CONFIG_PPC_RTC */
-#define CONFIG_DEBUG_BRINGUP
-#ifdef CONFIG_DEBUG_BRINGUP
-	printk("\n");
-	printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
-	printk("\n");
-	printk("bi_s_version\t %s\n",      bip->bi_s_version);
-	printk("bi_r_version\t %s\n",      bip->bi_r_version);
-	printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000));
-	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
-	bip->bi_enetaddr[0][0], bip->bi_enetaddr[0][1],
-	bip->bi_enetaddr[0][2], bip->bi_enetaddr[0][3],
-	bip->bi_enetaddr[0][4], bip->bi_enetaddr[0][5]);
-
-	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 1,
-	bip->bi_enetaddr[1][0], bip->bi_enetaddr[1][1],
-	bip->bi_enetaddr[1][2], bip->bi_enetaddr[1][3],
-	bip->bi_enetaddr[1][4], bip->bi_enetaddr[1][5]);
-
-	printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
-	       bip->bi_intfreq, bip->bi_intfreq/ 1000000);
-
-	printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
-		bip->bi_busfreq, bip->bi_busfreq / 1000000 );
-	printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n",
-	       bip->bi_pci_busfreq, bip->bi_pci_busfreq/1000000);
-
-	printk("\n");
-#endif
-}
-
-void __init
-board_io_mapping(void)
-{
-	io_block_mapping(ASH_RTC_VADDR,
-		ASH_RTC_PADDR, ASH_RTC_SIZE, _PAGE_IO);
-}
-void __init
-board_setup_irq(void)
-{
-
-}
-
-void __init
-board_init(void)
-{
-#ifdef CONFIG_PPC_RTC
-	ppc_md.time_init = todc_time_init;
-	ppc_md.set_rtc_time = todc_set_rtc_time;
-	ppc_md.get_rtc_time = todc_get_rtc_time;
-	ppc_md.nvram_read_val = todc_direct_read_val;
-	ppc_md.nvram_write_val = todc_direct_write_val;
-#endif
-}
diff -Nru a/arch/ppc/platforms/ash.h b/arch/ppc/platforms/ash.h
--- a/arch/ppc/platforms/ash.h	Fri Oct 11 21:22:53 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,86 +0,0 @@
-/*
- *
- *
- *    Copyright 2000 MontaVista Software Inc.
- * 	Author: MontaVista Software, Inc.
- *         	akuster@mvista.com or source@mvista.com
- *
- *    Module name: ash.h
- *
- *    Description:
- *      Macros, definitions, and data structures specific to the IBM PowerPC
- *      Ash eval board.
- *
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_ASH_H__
-#define __ASM_ASH_H__
-#include <platforms/ibm_ocp.h>
-#include <platforms/ibmnp405h.h>
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Ash" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
-	unsigned char	 bi_s_version[4];	/* Version of this structure */
-	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[EMAC_NUMS][6];	/* Local Ethernet MAC address */
-	unsigned char	 bi_pci_enetaddr[6];
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
-	unsigned int	 bi_pci_busfreq;	/* PCI speed in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-/* Memory map for the IBM "Ash" NP405H evaluation board.
- */
-
-extern  void *ash_rtc_base;
-#define ASH_RTC_PADDR		((uint)0xf0000000)
-#define ASH_RTC_VADDR		ASH_RTC_PADDR
-#define ASH_RTC_SIZE		((uint)8*1024)
-
-
-/* Early initialization address mapping for block_io.
- * Standard 405GP map.
- */
-#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
-#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
-#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
-#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
-#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
-#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
-#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
-#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
-#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
-
-#define NR_BOARD_IRQS 32
-
-#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
-#define BASE_BAUD		201600
-#else
-#define BASE_BAUD		691200
-#endif
-
-#define PPC4xx_MACHINE_NAME "IBM NP405H Ceder"
-
-extern char pci_irq_table[][4];
-
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_ASH_H__ */
-#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ceder.c b/arch/ppc/platforms/ceder.c
--- a/arch/ppc/platforms/ceder.c	Fri Oct 11 21:22:54 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,83 +0,0 @@
-/*
- *
- *    Copyright 2001 MontaVista Software Inc.
- *        <akuster@mvista.com>
- *	IBM NP405L ceder eval board
- *
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <asm/machdep.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_PPC_RTC
-#include <asm/todc.h>
-#endif
-
-void *ceder_rtc_base;
-
-void __init
-board_setup_arch(void)
-{
-
-	bd_t *bip = (bd_t *)__res;
-
-#ifdef CONFIG_PPC_RTC
-        /* RTC step for the walnut */
-        ceder_rtc_base = (void *) CEDER_RTC_VADDR;
-	TODC_INIT(TODC_TYPE_DS1743, ceder_rtc_base, ceder_rtc_base,ceder_rtc_base, 8);
-#endif /* CONFIG_PPC_RTC */
-#define CONFIG_DEBUG_BRINGUP
-#ifdef CONFIG_DEBUG_BRINGUP
-	printk("\n");
-	printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
-	printk("\n");
-	printk("bi_s_version\t %s\n",      bip->bi_s_version);
-	printk("bi_r_version\t %s\n",      bip->bi_r_version);
-	printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000));
-	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
-	bip->bi_enetaddr[0][0], bip->bi_enetaddr[0][1],
-	bip->bi_enetaddr[0][2], bip->bi_enetaddr[0][3],
-	bip->bi_enetaddr[0][4], bip->bi_enetaddr[0][5]);
-
-	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 1,
-	bip->bi_enetaddr[1][0], bip->bi_enetaddr[1][1],
-	bip->bi_enetaddr[1][2], bip->bi_enetaddr[1][3],
-	bip->bi_enetaddr[1][4], bip->bi_enetaddr[1][5]);
-
-	printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
-	       bip->bi_intfreq, bip->bi_intfreq/ 1000000);
-
-	printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
-		bip->bi_busfreq, bip->bi_busfreq / 1000000 );
-	printk("bi_pci_busfreq\t 0x%8.8x\t pci bus clock:\t %dMHz\n",
-	       bip->bi_pci_busfreq, bip->bi_pci_busfreq/1000000);
-
-	printk("\n");
-#endif
-}
-
-void __init
-board_io_mapping(void)
-{
-	io_block_mapping(CEDER_RTC_VADDR,
-		CEDER_RTC_PADDR, CEDER_RTC_SIZE, _PAGE_IO);
-}
-void __init
-board_setup_irq(void)
-{
-}
-
-void __init
-board_init(void)
-{
-#ifdef CONFIG_PPC_RTC
-	ppc_md.time_init = todc_time_init;
-	ppc_md.set_rtc_time = todc_set_rtc_time;
-	ppc_md.get_rtc_time = todc_get_rtc_time;
-	ppc_md.nvram_read_val = todc_direct_read_val;
-	ppc_md.nvram_write_val = todc_direct_write_val;
-#endif
-}
diff -Nru a/arch/ppc/platforms/ceder.h b/arch/ppc/platforms/ceder.h
--- a/arch/ppc/platforms/ceder.h	Fri Oct 11 21:23:01 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,85 +0,0 @@
-/*
- *
- *
- *    Copyright 2000 MontaVista Software Inc.
- * 	Author: MontaVista Software, Inc.
- *         	akuster@mvista.com or source@mvista.com
- *
- *    Module name: ceder.h
- *
- *    Description:
- *      Macros, definitions, and data structures specific to the IBM PowerPC
- *      Ceder eval board.
- *
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_CEDER_H__
-#define __ASM_CEDER_H__
-#include <platforms/ibmnp405l.h>
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Ceder" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
-	unsigned char	 bi_s_version[4];	/* Version of this structure */
-	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[EMAC_NUMS][6];	/* Local Ethernet MAC address */
-	unsigned char	 bi_pci_mac[6];
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
-	unsigned int	 bi_pci_busfreq;	/* PCI speed in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-/* Memory map for the IBM "Ceder" NP405 evaluation board.
- */
-
-extern  void *ceder_rtc_base;
-#define CEDER_RTC_PADDR		((uint)0xf0000000)
-#define CEDER_RTC_VADDR		CEDER_RTC_PADDR
-#define CEDER_RTC_SIZE		((uint)8*1024)
-
-
-/* Early initialization address mapping for block_io.
- * Standard 405GP map.
- */
-#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
-#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
-#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
-#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
-#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
-#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
-#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
-#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
-#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
-
-#define NR_BOARD_IRQS 32
-
-#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
-#define BASE_BAUD		201600
-#else
-#define BASE_BAUD		691200
-#endif
-
-#define PPC4xx_MACHINE_NAME "IBM NP405L Ceder"
-
-extern char pci_irq_table[][4];
-
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_CEDER_H__ */
-#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/cpci405.c b/arch/ppc/platforms/cpci405.c
--- a/arch/ppc/platforms/cpci405.c	Fri Oct 11 21:23:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,78 +0,0 @@
-/*
- * arch/ppc/platforms/cpci405.c
- *
- * Board setup routines for the esd CPCI-405 cPCI Board.
- *
- * Author: Stefan Roese
- *         stefan.roese@esd-electronics.com
- *
- * Copyright 2001 esd electronic system design - hannover germany
- *
- * 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.
- *
- *	History: 11/09/2001 - armin
- *       added board_init to add in additional instuctions needed during platfrom_init
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <asm/system.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/todc.h>
-
-/*
- * Some IRQs unique to CPCI-405.
- */
-int __init
-ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	/*
-	 *      PCI IDSEL/INTPIN->INTLINE
-	 *      A       B       C       D
-	 */
-	{
-		{28,	28,	28,	28},	/* IDSEL 15 - cPCI slot 8 */
-		{29,	29,	29,	29},	/* IDSEL 16 - cPCI slot 7 */
-		{30,	30,	30,	30},	/* IDSEL 17 - cPCI slot 6 */
-		{27,	27,	27,	27},	/* IDSEL 18 - cPCI slot 5 */
-		{28,	28,	28,	28},	/* IDSEL 19 - cPCI slot 4 */
-		{29,	29,	29,	29},	/* IDSEL 20 - cPCI slot 3 */
-		{30,	30,	30,	30},	/* IDSEL 21 - cPCI slot 2 */
-        };
-	const long min_idsel = 15, max_idsel = 21, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-};
-
-void __init
-board_setup_arch(void)
-{
-}
-
-void __init
-board_io_mapping(void)
-{
-}
-
-void __init
-board_setup_irq(void)
-{
-}
-
-void __init
-board_init(void)
-{
-#ifdef CONFIG_PPC_RTC
-	ppc_md.time_init = todc_time_init;
-	ppc_md.set_rtc_time = todc_set_rtc_time;
-	ppc_md.get_rtc_time = todc_get_rtc_time;
-	ppc_md.nvram_read_val = todc_direct_read_val;
-	ppc_md.nvram_write_val = todc_direct_write_val;
-#endif
-}
diff -Nru a/arch/ppc/platforms/cpci405.h b/arch/ppc/platforms/cpci405.h
--- a/arch/ppc/platforms/cpci405.h	Fri Oct 11 21:23:02 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,45 +0,0 @@
-/*
- * CPCI-405 board specific definitions
- *
- * Copyright (c) 2001 Stefan Roese (stefan.roese@esd-electronics.com)
- */
-
-#ifndef __ASM_CPCI405_H__
-#define __ASM_CPCI405_H__
-
-#include <linux/config.h>
-
-/* We have a 405GP core */
-#include <platforms/ibm405gp.h>
-
-#include <asm/ppcboot.h>
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-/* Early initialization address mapping for block_io.
- * Standard 405GP map.
- */
-#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
-#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
-#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
-#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
-#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
-#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
-#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
-#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
-#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
-
-#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
-#define BASE_BAUD		201600
-#else
-#define BASE_BAUD		691200
-#endif
-
-#define PPC4xx_MACHINE_NAME "esd CPCI-405"
-
-#endif	/* __ASM_CPCI405_H__ */
diff -Nru a/arch/ppc/platforms/ep405.c b/arch/ppc/platforms/ep405.c
--- a/arch/ppc/platforms/ep405.c	Fri Oct 11 21:22:53 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,184 +0,0 @@
-/*
- *    Copyright 2001 MontaVista Software Inc.
- *        <mlocke@mvista.com>
- *
- * 	Not much is needed for the Embedded Planet 405gp board
- *
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <asm/system.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/todc.h>
-#include <platforms/ibm_ocp.h>
-
-#undef DEBUG
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-u8 *ep405_bcsr;
-u8 *ep405_nvram;
-
-static struct {
-	u8 cpld_xirq_select;
-	int pci_idsel;
-	int irq;
-} ep405_devtable[] = {
-#ifdef CONFIG_EP405PC
-	{0x07, 0x0E, 25},		/* EP405PC: USB */
-#endif
-};
-#define EP405_DEVTABLE_SIZE (sizeof(ep405_devtable)/sizeof(ep405_devtable[0]))
-
-int __init
-ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	int i;
-
-	/* AFAICT this is only called a few times during PCI setup, so
-	   performance is not critical */
-	for (i = 0; i < EP405_DEVTABLE_SIZE; i++) {
-		if (idsel == ep405_devtable[i].pci_idsel)
-			return ep405_devtable[i].irq;
-	}
-	return -1;
-};
-
-void __init
-board_setup_arch(void)
-{
-	bd_t *bip = (bd_t *) __res;
-
-	if (bip->bi_nvramsize == 512*1024) {
-		/* FIXME: we should properly handle NVRTCs of different sizes */
-		TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8);
-	}
-}
-
-void __init
-bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
-{
-	unsigned int bar_response, bar;
-	/*
-	 * Expected PCI mapping:
-	 *
-	 *  PLB addr             PCI memory addr
-	 *  ---------------------       ---------------------
-	 *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
-	 *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
-	 *
-	 *  PLB addr             PCI io addr
-	 *  ---------------------       ---------------------
-	 *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
-	 *
-	 */
-
-	/* Disable region zero first */
-	out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
-	/* PLB starting addr, PCI: 0x80000000 */
-	out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
-	/* PCI start addr, 0x80000000 */
-	out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
-	/* 512MB range of PLB to PCI */
-	out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
-	/* Enable no pre-fetch, enable region */
-	out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
-						(PPC405_PCI_UPPER_MEM -
-						 PPC405_PCI_MEM_BASE)) | 0x01));
-
-	/* Disable region one */
-	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-	out_le32((void *) &(pcip->ptm1ms), 0x00000000);
-
-	/* Disable region two */
-	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
-
-	/* Configure PTM (PCI->PLB) region 1 */
-	out_le32((void *) &(pcip->ptm1la), 0x00000000); /* PLB base address */
-	/* Disable PTM region 2 */
-	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
-
-	/* Zero config bars */
-	for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
-		early_write_config_dword(hose, hose->first_busno,
-					 PCI_FUNC(hose->first_busno), bar,
-					 0x00000000);
-		early_read_config_dword(hose, hose->first_busno,
-					PCI_FUNC(hose->first_busno), bar,
-					&bar_response);
-		DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
-		    hose->first_busno, PCI_SLOT(hose->first_busno),
-		    PCI_FUNC(hose->first_busno), bar, bar_response);
-	}
-	/* end work arround */
-}
-
-void __init
-board_io_mapping(void)
-{
-	bd_t *bip = (bd_t *) __res;
-
-	ep405_bcsr = ioremap(EP405_BCSR_PADDR, EP405_BCSR_SIZE);
-
-	if (bip->bi_nvramsize > 0) {
-		ep405_nvram = ioremap(EP405_NVRAM_PADDR, bip->bi_nvramsize);
-	}
-}
-
-void __init
-board_setup_irq(void)
-{
-	int i;
-
-	/* Workaround for a bug in the firmware it incorrectly sets
-	   the IRQ polarities for XIRQ0 and XIRQ1 */
-	mtdcr(DCRN_UIC_PR(DCRN_UIC0_BASE), 0xffffff80); /* set the polarity */
-	mtdcr(DCRN_UIC_SR(DCRN_UIC0_BASE), 0x00000060); /* clear bogus interrupts */
-
-	/* Activate the XIRQs from the CPLD */
-	writeb(0xf0, ep405_bcsr+10);
-
-	/* Set up IRQ routing */
-	for (i = 0; i < EP405_DEVTABLE_SIZE; i++) {
-		if ( (ep405_devtable[i].irq >= 25)
-		     && (ep405_devtable[i].irq) <= 31) {
-			writeb(ep405_devtable[i].cpld_xirq_select, ep405_bcsr+5);
-			writeb(ep405_devtable[i].irq - 25, ep405_bcsr+6);
-		}
-	}
-}
-
-void __init
-board_init(void)
-{
-#ifdef CONFIG_PPC_RTC
-	bd_t *bip = (bd_t *) __res;
-
-	/* FIXME: we should be able to access the NVRAM even if PPC_RTC is not configured */
-	ppc_md.nvram_read_val = todc_direct_read_val;
-	ppc_md.nvram_write_val = todc_direct_write_val;
-
-	if (bip->bi_nvramsize == 512*1024) {
-		ppc_md.time_init = todc_time_init;
-		ppc_md.set_rtc_time = todc_set_rtc_time;
-		ppc_md.get_rtc_time = todc_get_rtc_time;
-	} else {
-		printk("EP405: NVRTC size is not 512k (not a DS1557).  Not sure what to do with it\n");
-	}
-
-#endif
-}
diff -Nru a/arch/ppc/platforms/ep405.h b/arch/ppc/platforms/ep405.h
--- a/arch/ppc/platforms/ep405.h	Fri Oct 11 21:22:51 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-/*
- *    Copyright 2000 MontaVista Software Inc.
- *    	http://www.mvista.com
- *	<mlocke@mvista.com>
- *
- *         Embedded Planet 405GP board
- *         http://www.embeddedplanet.com
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_EP405_H__
-#define __ASM_EP405_H__
-
-/* We have a 405GP core */
-#include <platforms/ibm405gp.h>
-
-#ifndef __ASSEMBLY__
-typedef struct board_info {
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
-	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
-	unsigned int	 bi_nvramsize;		/* Size of the NVRAM/RTC */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-extern u8 *ep405_bcsr;
-extern u8 *ep405_nvram;
-
-/* Map for the BCSR and NVRAM space */
-#define EP405_BCSR_PADDR	((uint)0xf4000000)
-#define EP405_BCSR_SIZE		((uint)16)
-#define EP405_NVRAM_PADDR	((uint)0xf4200000)
-
-/* serial defines */
-#define BASE_BAUD		399193
-
-#define PPC4xx_MACHINE_NAME "Embedded Planet 405GP"
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_EP405_H__ */
-#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibm405.h b/arch/ppc/platforms/ibm405.h
--- a/arch/ppc/platforms/ibm405.h	Fri Oct 11 21:22:51 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,334 +0,0 @@
-/*
- * ibm405.h
- *
- *	This was derived from the ppc4xx.h and contains
- *	common 405 offsets
- *
- *      Armin Kuster akuster@pacbell.net
- *      Jan, 2002
- *
- *
- * Copyright 2002 MontaVista Softare Inc.
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 (02/01/17) - A. Kuster
- *	Initial version	 - moved 405  specific out of the other core.h's
- *
- *	Version 1.0 (02/08/02) - A. Kuster
- *	removed DCRN_UIC1_BASE to NP405L & H
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IBM405_H__
-#define __ASM_IBM405_H__
-
-#ifdef DCRN_BE_BASE
-#define DCRN_BEAR	(DCRN_BE_BASE + 0x0)	/* Bus Error Address Register */
-#define DCRN_BESR	(DCRN_BE_BASE + 0x1)	/* Bus Error Syndrome Register */
-#endif
-/* DCRN_BESR */
-#define BESR_DSES	0x80000000	/* Data-Side Error Status */
-#define BESR_DMES	0x40000000	/* DMA Error Status */
-#define BESR_RWS	0x20000000	/* Read/Write Status */
-#define BESR_ETMASK	0x1C000000	/* Error Type */
-#define ET_PROT	0
-#define ET_PARITY	1
-#define ET_NCFG	2
-#define ET_BUSERR	4
-#define ET_BUSTO	6
-
-#ifdef DCRN_CHCR_BASE
-#define DCRN_CHCR0	(DCRN_CHCR_BASE + 0x0)	/* Chip Control Register 1 */
-#define DCRN_CHCR1	(DCRN_CHCR_BASE + 0x1)	/* Chip Control Register 2 */
-#endif
-#define CHR1_PCIPW	0x00008000	/* PCI Int enable/Peripheral Write enable */
-
-#ifdef DCRN_CHPSR_BASE
-#define DCRN_CHPSR	(DCRN_CHPSR_BASE + 0x0)	/* Chip Pin Strapping */
-#endif
-
-#ifdef DCRN_CPMFR_BASE
-#define DCRN_CPMFR	(DCRN_CPMFR_BASE + 0x0)	/* CPM Force */
-#endif
-
-#ifdef DCRN_CPMSR_BASE
-#define DCRN_CPMSR	(DCRN_CPMSR_BASE + 0x0)	/* CPM Status */
-#define DCRN_CPMER	(DCRN_CPMSR_BASE + 0x1)	/* CPM Enable */
-#endif
-
-#ifdef DCRN_DCP0_BASE
-/* Decompression Controller Address */
-#define DCRN_DCP0_CFGADDR	(DCRN_DCP0_BASE + 0x0)
-/* Decompression Controller Data */
-#define DCRN_DCP0_CFGDATA	(DCRN_DCP0_BASE + 0x1)
-#else
-#define DCRN_DCP0_CFGADDR	0x0
-#define DCRN_DCP0_CFGDATA	0x0
-#endif
-
-#ifdef DCRN_DMA0_BASE
-/* DMA Channel Control Register 0 */
-#define DCRN_DMACR0	(DCRN_DMA0_BASE + 0x0)
-#define DCRN_DMACT0	(DCRN_DMA0_BASE + 0x1)	/* DMA Count Register 0 */
-/* DMA Destination Address Register 0 */
-#define DCRN_DMADA0	(DCRN_DMA0_BASE + 0x2)
-/* DMA Source Address Register 0 */
-#define DCRN_DMASA0	(DCRN_DMA0_BASE + 0x3)
-#ifdef DCRNCAP_DMA_CC
-/* DMA Chained Count Register 0 */
-#define DCRN_DMACC0	(DCRN_DMA0_BASE + 0x4)
-#endif
-#ifdef DCRNCAP_DMA_SG
-/* DMA Scatter/Gather Descriptor Addr 0 */
-#define DCRN_ASG0	(DCRN_DMA0_BASE + 0x4)
-#endif
-#endif
-
-#ifdef DCRN_DMA1_BASE
-/* DMA Channel Control Register 1 */
-#define DCRN_DMACR1	(DCRN_DMA1_BASE + 0x0)
-#define DCRN_DMACT1	(DCRN_DMA1_BASE + 0x1)	/* DMA Count Register 1 */
-/* DMA Destination Address Register 1 */
-#define DCRN_DMADA1	(DCRN_DMA1_BASE + 0x2)
-/* DMA Source Address Register 1 */
-#define DCRN_DMASA1	(DCRN_DMA1_BASE + 0x3)	/* DMA Source Address Register 1 */
-#ifdef DCRNCAP_DMA_CC
-/* DMA Chained Count Register 1 */
-#define DCRN_DMACC1	(DCRN_DMA1_BASE + 0x4)
-#endif
-#ifdef DCRNCAP_DMA_SG
-/* DMA Scatter/Gather Descriptor Addr 1 */
-#define DCRN_ASG1	(DCRN_DMA1_BASE + 0x4)
-#endif
-#endif
-
-#ifdef DCRN_DMA2_BASE
-#define DCRN_DMACR2	(DCRN_DMA2_BASE + 0x0)	/* DMA Channel Control Register 2 */
-#define DCRN_DMACT2	(DCRN_DMA2_BASE + 0x1)	/* DMA Count Register 2 */
-#define DCRN_DMADA2	(DCRN_DMA2_BASE + 0x2)	/* DMA Destination Address Register 2 */
-#define DCRN_DMASA2	(DCRN_DMA2_BASE + 0x3)	/* DMA Source Address Register 2 */
-#ifdef DCRNCAP_DMA_CC
-#define DCRN_DMACC2	(DCRN_DMA2_BASE + 0x4)	/* DMA Chained Count Register 2 */
-#endif
-#ifdef DCRNCAP_DMA_SG
-#define DCRN_ASG2	(DCRN_DMA2_BASE + 0x4)	/* DMA Scatter/Gather Descriptor Addr 2 */
-#endif
-#endif
-
-#ifdef DCRN_DMA3_BASE
-#define DCRN_DMACR3	(DCRN_DMA3_BASE + 0x0)	/* DMA Channel Control Register 3 */
-#define DCRN_DMACT3	(DCRN_DMA3_BASE + 0x1)	/* DMA Count Register 3 */
-#define DCRN_DMADA3	(DCRN_DMA3_BASE + 0x2)	/* DMA Destination Address Register 3 */
-#define DCRN_DMASA3	(DCRN_DMA3_BASE + 0x3)	/* DMA Source Address Register 3 */
-#ifdef DCRNCAP_DMA_CC
-#define DCRN_DMACC3	(DCRN_DMA3_BASE + 0x4)	/* DMA Chained Count Register 3 */
-#endif
-#ifdef DCRNCAP_DMA_SG
-#define DCRN_ASG3	(DCRN_DMA3_BASE + 0x4)	/* DMA Scatter/Gather Descriptor Addr 3 */
-#endif
-#endif
-
-#ifdef DCRN_DMASR_BASE
-#define DCRN_DMASR	(DCRN_DMASR_BASE + 0x0)	/* DMA Status Register */
-#ifdef DCRNCAP_DMA_SG
-#define DCRN_ASGC	(DCRN_DMASR_BASE + 0x3)	/* DMA Scatter/Gather Command */
-/* don't know if these two registers always exist if scatter/gather exists */
-#define DCRN_POL	(DCRN_DMASR_BASE + 0x6)	/* DMA Polarity Register */
-#define DCRN_SLP	(DCRN_DMASR_BASE + 0x5)	/* DMA Sleep Register */
-#endif
-#endif
-
-#ifdef DCRN_EBC_BASE
-#define DCRN_EBCCFGADR	(DCRN_EBC_BASE + 0x0)	/* Peripheral Controller Address */
-#define DCRN_EBCCFGDATA	(DCRN_EBC_BASE + 0x1)	/* Peripheral Controller Data */
-#endif
-
-#ifdef DCRN_EXIER_BASE
-#define DCRN_EXIER	(DCRN_EXIER_BASE + 0x0)	/* External Interrupt Enable Register */
-#endif
-
-#ifdef DCRN_EXISR_BASE
-#define DCRN_EXISR	(DCRN_EXISR_BASE + 0x0)	/* External Interrupt Status Register */
-#endif
-
-#define EXIER_CIE	0x80000000	/* Critical Interrupt Enable */
-#define EXIER_SRIE	0x08000000	/* Serial Port Rx Int. Enable */
-#define EXIER_STIE	0x04000000	/* Serial Port Tx Int. Enable */
-#define EXIER_JRIE	0x02000000	/* JTAG Serial Port Rx Int. Enable */
-#define EXIER_JTIE	0x01000000	/* JTAG Serial Port Tx Int. Enable */
-#define EXIER_D0IE	0x00800000	/* DMA Channel 0 Interrupt Enable */
-#define EXIER_D1IE	0x00400000	/* DMA Channel 1 Interrupt Enable */
-#define EXIER_D2IE	0x00200000	/* DMA Channel 2 Interrupt Enable */
-#define EXIER_D3IE	0x00100000	/* DMA Channel 3 Interrupt Enable */
-#define EXIER_E0IE	0x00000010	/* External Interrupt 0 Enable */
-#define EXIER_E1IE	0x00000008	/* External Interrupt 1 Enable */
-#define EXIER_E2IE	0x00000004	/* External Interrupt 2 Enable */
-#define EXIER_E3IE	0x00000002	/* External Interrupt 3 Enable */
-#define EXIER_E4IE	0x00000001	/* External Interrupt 4 Enable */
-
-#ifdef DCRN_IOCR_BASE
-#define DCRN_IOCR	(DCRN_IOCR_BASE + 0x0)	/* Input/Output Configuration Register */
-#endif
-#define IOCR_E0TE	0x80000000
-#define IOCR_E0LP	0x40000000
-#define IOCR_E1TE	0x20000000
-#define IOCR_E1LP	0x10000000
-#define IOCR_E2TE	0x08000000
-#define IOCR_E2LP	0x04000000
-#define IOCR_E3TE	0x02000000
-#define IOCR_E3LP	0x01000000
-#define IOCR_E4TE	0x00800000
-#define IOCR_E4LP	0x00400000
-#define IOCR_EDT	0x00080000
-#define IOCR_SOR	0x00040000
-#define IOCR_EDO	0x00008000
-#define IOCR_2XC	0x00004000
-#define IOCR_ATC	0x00002000
-#define IOCR_SPD	0x00001000
-#define IOCR_BEM	0x00000800
-#define IOCR_PTD	0x00000400
-#define IOCR_ARE	0x00000080
-#define IOCR_DRC	0x00000020
-#define IOCR_RDM(x)	(((x) & 0x3) << 3)
-#define IOCR_TCS	0x00000004
-#define IOCR_SCS	0x00000002
-#define IOCR_SPC	0x00000001
-
-#define DCRN_MALCR(base)	(base + 0x0)	/* MAL Configuration */
-#define DCRN_MALDBR(base)	((base) + 0x3)	/* Debug Register */
-#define DCRN_MALESR(base)	((base) + 0x1)	/* Error Status */
-#define DCRN_MALIER(base)	((base) + 0x2)	/* Interrupt Enable */
-#define DCRN_MALTXCARR(base)	((base) + 0x5)	/* TX Channed Active Reset Register */
-#define DCRN_MALTXCASR(base)	((base) + 0x4)	/* TX Channel Active Set Register */
-#define DCRN_MALTXDEIR(base)	((base) + 0x7)	/* Tx Descriptor Error Interrupt */
-#define DCRN_MALTXEOBISR(base)	((base) + 0x6)	/* Tx End of Buffer Interrupt Status */
-#define DCRN_MALRXCARR(base)	((base) + 0x11)	/* RX Channed Active Reset Register */
-#define DCRN_MALRXCASR(base)	((base) + 0x10)	/* RX Channel Active Set Register */
-#define DCRN_MALRXDEIR(base)	((base) + 0x13)	/* Rx Descriptor Error Interrupt */
-#define DCRN_MALRXEOBISR(base)	((base) + 0x12)	/* Rx End of Buffer Interrupt Status */
-#define DCRN_MALRXCTP0R(base)	((base) + 0x40)	/* Channel Rx 0 Channel Table Pointer */
-#define DCRN_MALRXCTP1R(base)	((base) + 0x41)	/* Channel Rx 1 Channel Table Pointer */
-#define DCRN_MALTXCTP0R(base)	((base) + 0x20)	/* Channel Tx 0 Channel Table Pointer */
-#define DCRN_MALTXCTP1R(base)	((base) + 0x21)	/* Channel Tx 1 Channel Table Pointer */
-#define DCRN_MALTXCTP2R(base)	((base) + 0x22)	/* Channel Tx 2 Channel Table Pointer */
-#define DCRN_MALTXCTP3R(base)	((base) + 0x23)	/* Channel Tx 3 Channel Table Pointer */
-#define DCRN_MALRCBS0(base)	((base) + 0x60)	/* Channel Rx 0 Channel Buffer Size */
-#define DCRN_MALRCBS1(base)	((base) + 0x61)	/* Channel Rx 1 Channel Buffer Size */
-
-/* EMAC DCRN's */
-#define DCRN_MALRXCTP2R(base)	((base) + 0x42)	/* Channel Rx 2 Channel Table Pointer */
-#define DCRN_MALRXCTP3R(base)	((base) + 0x43)	/* Channel Rx 3 Channel Table Pointer */
-#define DCRN_MALTXCTP4R(base)	((base) + 0x24)	/* Channel Tx 4 Channel Table Pointer */
-#define DCRN_MALTXCTP5R(base)	((base) + 0x25)	/* Channel Tx 5 Channel Table Pointer */
-#define DCRN_MALTXCTP6R(base)	((base) + 0x26)	/* Channel Tx 6 Channel Table Pointer */
-#define DCRN_MALTXCTP7R(base)	((base) + 0x27)	/* Channel Tx 7 Channel Table Pointer */
-#define DCRN_MALRCBS2(base)	((base) + 0x62)	/* Channel Rx 2 Channel Buffer Size */
-#define DCRN_MALRCBS3(base)	((base) + 0x63)	/* Channel Rx 3 Channel Buffer Size */
-
- /* DCRN_MALCR */
-#define MALCR_MMSR		0x80000000	/* MAL Software reset */
-#define MALCR_PLBP_1		0x00400000	/* MAL reqest priority: */
-#define MALCR_PLBP_2		0x00800000	/* lowsest is 00 */
-#define MALCR_PLBP_3		0x00C00000	/* highest */
-#define MALCR_GA		0x00200000	/* Guarded Active Bit */
-#define MALCR_OA		0x00100000	/* Ordered Active Bit */
-#define MALCR_PLBLE		0x00080000	/* PLB Lock Error Bit */
-#define MALCR_PLBLT_1		0x00040000	/* PLB Latency Timer */
-#define MALCR_PLBLT_2 		0x00020000
-#define MALCR_PLBLT_3		0x00010000
-#define MALCR_PLBLT_4		0x00008000
-#define MALCR_PLBLT_DEFAULT	0x00078000	/* JSP: Is this a valid default?? */
-#define MALCR_PLBB		0x00004000	/* PLB Burst Deactivation Bit */
-#define MALCR_OPBBL		0x00000080	/* OPB Lock Bit */
-#define MALCR_EOPIE		0x00000004	/* End Of Packet Interrupt Enable */
-#define MALCR_LEA		0x00000002	/* Locked Error Active */
-#define MALCR_MSD		0x00000001	/* MAL Scroll Descriptor Bit */
-/* DCRN_MALESR */
-#define MALESR_EVB		0x80000000	/* Error Valid Bit */
-#define MALESR_CIDRX		0x40000000	/* Channel ID Receive */
-#define MALESR_DE		0x00100000	/* Descriptor Error */
-#define MALESR_OEN		0x00080000	/* OPB Non-Fullword Error */
-#define MALESR_OTE		0x00040000	/* OPB Timeout Error */
-#define MALESR_OSE		0x00020000	/* OPB Slave Error */
-#define MALESR_PEIN		0x00010000	/* PLB Bus Error Indication */
-#define MALESR_DEI		0x00000010	/* Descriptor Error Interrupt */
-#define MALESR_ONEI		0x00000008	/* OPB Non-Fullword Error Interrupt */
-#define MALESR_OTEI		0x00000004	/* OPB Timeout Error Interrupt */
-#define MALESR_OSEI		0x00000002	/* OPB Slace Error Interrupt */
-#define MALESR_PBEI		0x00000001	/* PLB Bus Error Interrupt */
-/* DCRN_MALIER */
-#define MALIER_DE		0x00000010	/* Descriptor Error Interrupt Enable */
-#define MALIER_NE		0x00000008	/* OPB Non-word Transfer Int Enable */
-#define MALIER_TE		0x00000004	/* OPB Time Out Error Interrupt Enable */
-#define MALIER_OPBE		0x00000002	/* OPB Slave Error Interrupt Enable */
-#define MALIER_PLBE		0x00000001	/* PLB Error Interrupt Enable */
-/* DCRN_MALTXEOBISR */
-#define MALOBISR_CH0		0x80000000	/* EOB channel 1 bit */
-#define MALOBISR_CH2		0x40000000	/* EOB channel 2 bit */
-
-#ifdef DCRN_PLB0_BASE
-#define DCRN_PLB0_BESR	(DCRN_PLB0_BASE + 0x0)
-#define DCRN_PLB0_BEAR	(DCRN_PLB0_BASE + 0x2)
-/* doesn't exist on stb03xxx? */
-#define DCRN_PLB0_ACR	(DCRN_PLB0_BASE + 0x3)
-#endif
-
-#ifdef DCRN_PLB1_BASE
-#define DCRN_PLB1_BESR	(DCRN_PLB1_BASE + 0x0)
-#define DCRN_PLB1_BEAR	(DCRN_PLB1_BASE + 0x1)
-/* doesn't exist on stb03xxx? */
-#define DCRN_PLB1_ACR	(DCRN_PLB1_BASE + 0x2)
-#endif
-
-#ifdef DCRN_PLLMR_BASE
-#define DCRN_PLLMR	(DCRN_PLLMR_BASE + 0x0)	/* PL1 Mode */
-#endif
-
-#ifdef DCRN_POB0_BASE
-#define DCRN_POB0_BESR0	(DCRN_POB0_BASE + 0x0)
-#define DCRN_POB0_BEAR	(DCRN_POB0_BASE + 0x2)
-#define DCRN_POB0_BESR1	(DCRN_POB0_BASE + 0x4)
-#endif
-
-#define DCRN_UIC_SR(base)	(base + 0x0)
-#define DCRN_UIC_ER(base)	(base + 0x2)
-#define DCRN_UIC_CR(base)	(base + 0x3)
-#define DCRN_UIC_PR(base)	(base + 0x4)
-#define DCRN_UIC_TR(base)	(base + 0x5)
-#define DCRN_UIC_MSR(base)	(base + 0x6)
-#define DCRN_UIC_VR(base)	(base + 0x7)
-#define DCRN_UIC_VCR(base)	(base + 0x8)
-
-#ifdef DCRN_SDRAM0_BASE
-#define DCRN_SDRAM0_CFGADDR	(DCRN_SDRAM0_BASE + 0x0)	/* Memory Controller Address */
-#define DCRN_SDRAM0_CFGDATA	(DCRN_SDRAM0_BASE + 0x1)	/* Memory Controller Data */
-#endif
-
-#ifdef DCRN_OCM0_BASE
-#define DCRN_OCMISARC	(DCRN_OCM0_BASE + 0x0)	/* OCM Instr Side Addr Range Compare */
-#define DCRN_OCMISCR	(DCRN_OCM0_BASE + 0x1)	/* OCM Instr Side Control */
-#define DCRN_OCMDSARC	(DCRN_OCM0_BASE + 0x2)	/* OCM Data Side Addr Range Compare */
-#define DCRN_OCMDSCR	(DCRN_OCM0_BASE + 0x3)	/* OCM Data Side Control */
-#endif
-
-#endif				/* __ASM_IBM405_H__ */
-#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibm405gp.c b/arch/ppc/platforms/ibm405gp.c
--- a/arch/ppc/platforms/ibm405gp.c	Fri Oct 11 21:23:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,63 +0,0 @@
-/*
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *	Current maintainer
- *      Armin Kuster akuster@mvista.com
- *
- *    Module name: ibm405gp.c
- *
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *      History: 12/26/2001 - armin
- *		initial release
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <platforms/ibm405gp.h>
-
-const struct pcil0_regs *PCIL_ADDR[] = {
-	(struct pcil0_regs *) PCIL0_BASE,
-};
-
-const struct NS16550 *COM_PORTS[] = {
-	(struct NS16550 *) UART0_IO_BASE,
-	(struct NS16550 *) UART1_IO_BASE,
-};
-
-struct iic_regs *IIC_ADDR[] = {
-	(struct iic_regs *) IIC0_BASE,
-};
-
-const struct gpio_regs *GPIO_ADDR[] = {
-	(struct gpio_regs *) GPIO0_BASE,
-};
-
-const struct emac_regs *EMAC_ADDR[] = {
-	(struct emac_regs *) EMAC0_BASE,
-};
diff -Nru a/arch/ppc/platforms/ibm405gp.h b/arch/ppc/platforms/ibm405gp.h
--- a/arch/ppc/platforms/ibm405gp.h	Fri Oct 11 21:22:50 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,195 +0,0 @@
-/*
- * ibm405gp.h
- *
- *	This was derived from the ppc4xx.h and all 405GP specific
- *	definition and board inclusions were moved here.
- *
- *      Armin Kuster akuster@mvista.com
- *      Oct, 2001
- *
- *
- * Copyright 2001 MontaVista Softare Inc.
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 (01/10/10) - A. Kuster
- *	Initial version	 - moved 40GP  specific out of ppc4xx.h
- *			- moved emac reg from ppc405_enet.h
- *
- *	Version 1.1 02/01/17 - A. Kuster
- *	Moved offsets to ibm405.h
- *
- *	Version 1.2 05/01/02 - Armin
- *	 added IIC_PORT_DFNS
- *
- *	Version 1.3 - armin
- *	  removed iic & uart num defines
- *	  and IIC_PORT_DFNS
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IBM405GP_H__
-#define __ASM_IBM405GP_H__
-
-#include <linux/config.h>
-#include <platforms/ibm_ocp.h>
-
-/* ibm405.h at bottom of this file */
-
-/* PCI
- * PCI Bridge config reg definitions
- * see 17-19 of manual
- */
-
-#define PPC405_PCI_CONFIG_ADDR	0xeec00000
-#define PPC405_PCI_CONFIG_DATA	0xeec00004
-
-#define PPC405_PCI_PHY_MEM_BASE	0x80000000	/* hose_a->pci_mem_offset */
-						/* setbat */
-#define PPC405_PCI_MEM_BASE	PPC405_PCI_PHY_MEM_BASE	/* setbat */
-#define PPC405_PCI_PHY_IO_BASE	0xe8000000	/* setbat */
-#define PPC405_PCI_IO_BASE	PPC405_PCI_PHY_IO_BASE	/* setbat */
-
-#define PPC405_PCI_LOWER_MEM	0x80000000	/* hose_a->mem_space.start */
-#define PPC405_PCI_UPPER_MEM	0xBfffffff	/* hose_a->mem_space.end */
-#define PPC405_PCI_LOWER_IO	0x00000000	/* hose_a->io_space.start */
-#define PPC405_PCI_UPPER_IO	0x0000ffff	/* hose_a->io_space.end */
-
-#define PPC405_ISA_IO_BASE	PPC405_PCI_IO_BASE
-
-#define PPC4xx_PCI_IO_PADDR	((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_VADDR	PPC4xx_PCI_IO_PADDR
-#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
-#define PPC4xx_PCI_CFG_PADDR	((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_VADDR	PPC4xx_PCI_CFG_PADDR
-#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
-#define PPC4xx_PCI_LCFG_PADDR	((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_VADDR	PPC4xx_PCI_LCFG_PADDR
-#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
-#define PPC4xx_ONB_IO_PADDR	((uint)0xef600000)
-#define PPC4xx_ONB_IO_VADDR	PPC4xx_ONB_IO_PADDR
-#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
-
-/* serial port defines */
-#define RS_TABLE_SIZE	2
-
-#define UART0_INT	0
-#define UART1_INT	1
-
-#define PCIL0_BASE	0xEF400000
-#define UART0_IO_BASE	0xEF600300
-#define UART1_IO_BASE	0xEF600400
-#define IIC0_BASE	0xEF600500
-#define OPB0_BASE	0xEF600600
-#define GPIO0_BASE	0xEF600700
-#define EMAC0_BASE	0xEF600800
-
-#define EMAC_NUMS	1
-#define IIC0_IRQ	2
-#define IIC1_IRQ	0
-
-#define IIC_OWN		0x55
-#define IIC_CLOCK	50
-#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
-
-#define STD_UART_OP(num)					\
-	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
-		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
-		iomem_base: (u8 *)UART##num##_IO_BASE,		\
-		io_type: SERIAL_IO_MEM},
-
-#if defined(CONFIG_UART0_TTYS0)
-#define SERIAL_DEBUG_IO_BASE	UART0_IO_BASE
-#define SERIAL_PORT_DFNS	\
-	STD_UART_OP(0)		\
-	STD_UART_OP(1)
-#endif
-
-#if defined(CONFIG_UART0_TTYS1)
-#define SERIAL_DEBUG_IO_BASE	UART1_IO_BASE
-#define SERIAL_PORT_DFNS	\
-	STD_UART_OP(1)		\
-	STD_UART_OP(0)
-#endif
-
-/* DCR defines */
-#define DCRN_CHCR_BASE		0x0B1
-#define DCRN_CHPSR_BASE		0x0B4
-#define DCRN_CPMSR_BASE		0x0B8
-#define DCRN_CPMFR_BASE		0x0BA
-
-#define CHR0_U0EC	0x00000080	/* Select external clock for UART0 */
-#define CHR0_U1EC	0x00000040	/* Select external clock for UART1 */
-#define CHR0_UDIV	0x0000003E	/* UART internal clock divisor */
-#define CHR1_CETE	0x00800000	/* CPU external timer enable */
-
-#define DCRN_CHPSR_BASE         0x0B4
-#define  PSR_PLL_FWD_MASK        0xC0000000
-#define  PSR_PLL_FDBACK_MASK     0x30000000
-#define  PSR_PLL_TUNING_MASK     0x0E000000
-#define  PSR_PLB_CPU_MASK        0x01800000
-#define  PSR_OPB_PLB_MASK        0x00600000
-#define  PSR_PCI_PLB_MASK        0x00180000
-#define  PSR_EB_PLB_MASK         0x00060000
-#define  PSR_ROM_WIDTH_MASK      0x00018000
-#define  PSR_ROM_LOC             0x00004000
-#define  PSR_PCI_ASYNC_EN        0x00001000
-#define  PSR_PCI_ARBIT_EN        0x00000400
-
-#define CPM_IIC0		0x80000000	/* IIC interface */
-#define CPM_PCI			0x40000000	/* PCI bridge */
-#define CPM_CPU			0x20000000	/* processor core */
-#define CPM_DMA			0x10000000	/* DMA controller */
-#define CPM_BRG			0x08000000	/* PLB to OPB bridge */
-#define CPM_DCP			0x04000000	/* CodePack */
-#define CPM_EBC			0x02000000	/* ROM/SRAM peripheral controller */
-#define CPM_SDRAM0		0x01000000	/* SDRAM memory controller */
-#define CPM_PLB			0x00800000	/* PLB bus arbiter */
-#define CPM_GPIO0		0x00400000	/* General Purpose IO (??) */
-#define CPM_UART0		0x00200000	/* serial port 0 */
-#define CPM_UART1		0x00100000	/* serial port 1 */
-#define CPM_UIC			0x00080000	/* Universal Interrupt Controller */
-#define CPM_TMRCLK		0x00040000	/* CPU timers */
-#define CPM_EMAC_MM		0x00020000	/* on-chip ethernet MM unit */
-#define CPM_EMAC_RM		0x00010000	/* on-chip ethernet RM unit */
-#define CPM_EMAC_TM		0x00008000	/* on-chip ethernet TM unit */
-
-#define DCRN_DMA0_BASE		0x100
-#define DCRN_DMA1_BASE		0x108
-#define DCRN_DMA2_BASE		0x110
-#define DCRN_DMA3_BASE		0x118
-#define DCRNCAP_DMA_SG		1	/* have DMA scatter/gather capability */
-#define DCRN_DMASR_BASE		0x120
-#define DCRN_EBC_BASE		0x012
-#define DCRN_DCP0_BASE		0x014
-#define DCRN_MAL_BASE		0x180
-#define DCRN_OCM0_BASE		0x018
-#define DCRN_PLB0_BASE		0x084
-#define DCRN_PLLMR_BASE		0x0B0
-#define DCRN_POB0_BASE		0x0A0
-#define DCRN_SDRAM0_BASE	0x010
-#define DCRN_UIC0_BASE		0x0C0
-#define UIC0 DCRN_UIC0_BASE
-
-#include <platforms/ibm405.h>
-
-#endif				/* __ASM_IBM405GP_H__ */
-#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibm_ocp.h b/arch/ppc/platforms/ibm_ocp.h
--- a/arch/ppc/platforms/ibm_ocp.h	Fri Oct 11 21:23:04 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,192 +0,0 @@
-/*
- * ibm_ocp.h
- *
- *	This was dirived from the ppc4xx.h and all 405GP specific definition and board
- *	inclusions where moved here.
- *
- * 	Current Maintainer
- *      Armin Kuster akuster@mvista.com
- *      Nov, 2001
- *
- *
- * Copyright 2001 MontaVista Softare Inc.
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 (01/11/26) - A. Kuster
- *	Initial version	 -
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IBM_OCP_H__
-#define __ASM_IBM_OCP_H__
-
-#ifndef __ASSEMBLY__
-#include <linux/types.h>
-
- /* PCI 32 */
-
-struct pmm_regs {
-	u32 la;
-	u32 ma;
-	u32 pcila;
-	u32 pciha;
-};
-
-typedef struct pcil0_regs {
-	struct pmm_regs pmm[3];
-	u32 ptm1ms;
-	u32 ptm1la;
-	u32 ptm2ms;
-	u32 ptm2la;
-} pci0_t;
-
-/* Serial Ports */
-
-#define thr rbr
-#define iir fcr
-#define dll rbr
-#define dlm ier
-
-typedef struct NS16550 {
-	u8 rbr;			/* 0 */
-	u8 ier;			/* 1 */
-	u8 fcr;			/* 2 */
-	u8 lcr;			/* 3 */
-	u8 mcr;			/* 4 */
-	u8 lsr;			/* 5 */
-	u8 msr;			/* 6 */
-	u8 scr;			/* 7 */
-} uart_t;
-
-/* I2c */
-typedef struct iic_regs {
-	u16 mdbuf;
-	u16 sbbuf;
-	u8 lmadr;
-	u8 hmadr;
-	u8 cntl;
-	u8 mdcntl;
-	u8 sts;
-	u8 extsts;
-	u8 lsadr;
-	u8 hsadr;
-	u8 clkdiv;
-	u8 intmsk;
-	u8 xfrcnt;
-	u8 xtcntlss;
-	u8 directcntl;
-} iic_t;
-
-/* OPB arbiter */
-typedef struct opb {
-	u8 pr;
-	u8 cr;
-} opb_t;
-
-/* General purpose i/o */
-
-typedef struct gpio_regs {
-	u32 or;
-	u32 tcr;
-	u32 pad[4];
-	u32 odr;
-	u32 ir;
-} gpio_t;
-
-/* Emac */
-typedef struct emac_regs {
-	volatile u32 em0mr0;
-	volatile u32 em0mr1;
-	volatile u32 em0tmr0;
-	volatile u32 em0tmr1;
-	volatile u32 em0rmr;
-	volatile u32 em0isr;
-	volatile u32 em0iser;
-	volatile u32 em0iahr;
-	volatile u32 em0ialr;
-	volatile u32 em0vtpid;
-	volatile u32 em0vtci;
-	volatile u32 em0ptr;
-	volatile u32 em0iaht1;
-	volatile u32 em0iaht2;
-	volatile u32 em0iaht3;
-	volatile u32 em0iaht4;
-	volatile u32 em0gaht1;
-	volatile u32 em0gaht2;
-	volatile u32 em0gaht3;
-	volatile u32 em0gaht4;
-	volatile u32 em0lsal;
-	volatile u32 em0lsah;
-	volatile u32 em0ipgvr;
-	volatile u32 em0stacr;
-	volatile u32 em0trtr;
-	volatile u32 em0rwmr;
-} emac_t;
-
-/* ZMII bridge */
-typedef struct zmii_regs {
-	u32 fer;		/* Function enable reg */
-	u32 ssr;		/* Spedd select reg */
-	u32 smiirs;		/* SMII status reg */
-} zmii_t;
-
-/* Structure of the memory mapped IDE control.
-*/
-typedef struct ide_regs {
-	unsigned int si_stat;	/* IDE status */
-	unsigned int si_intenable;	/* IDE interrupt enable */
-	unsigned int si_control;	/* IDE control */
-	unsigned int pad0[0x3d];
-	unsigned int si_c0rt;	/* Chan 0 Register transfer timing */
-	unsigned int si_c0fpt;	/* Chan 0 Fast PIO transfer timing */
-	unsigned int si_c0timo;	/* Chan 0 timeout */
-	unsigned int pad1[2];
-	unsigned int si_c0d0u;	/* Chan 0 UDMA transfer timing */
-#define si_c0d0m si_c0d0u	/* Chan 0 Multiword DMA timing */
-	unsigned int pad2;
-	unsigned int si_c0d1u;	/* Chan 0 dev 1 UDMA timing */
-#define si_c0d1m si_c0d1u	/* Chan 0 dev 1 Multiword DMA timing */
-	unsigned int si_c0c;	/* Chan 0 Control */
-	unsigned int si_c0s0;	/* Chan 0 Status 0 */
-	unsigned int si_c0ie;	/* Chan 0 Interrupt Enable */
-	unsigned int si_c0s1;	/* Chan 0 Status 0 */
-	unsigned int pad4[4];
-	unsigned int si_c0dcm;	/* Chan 0 DMA Command */
-	unsigned int si_c0tb;	/* Chan 0 PRD Table base address */
-	unsigned int si_c0dct;	/* Chan 0 DMA Count */
-	unsigned int si_c0da;	/* Chan 0 DMA Address */
-	unsigned int si_c0sr;	/* Chan 0 Slew Rate Output Control */
-	unsigned char pad5[0xa2];
-	unsigned short si_c0adc;	/* Chan 0 Alt status/control */
-	unsigned char si_c0d;	/* Chan 0 data */
-	unsigned char si_c0ef;	/* Chan 0 error/features */
-	unsigned char si_c0sct;	/* Chan 0 sector count */
-	unsigned char si_c0sn;	/* Chan 0 sector number */
-	unsigned char si_c0cl;	/* Chan 0 cylinder low */
-	unsigned char si_c0ch;	/* Chan 0 cylinder high */
-	unsigned char si_c0dh;	/* Chan 0 device/head */
-	unsigned char si_c0scm;	/* Chan 0 status/command */
-} ide_t;
-
-#endif				/* __ASSEMBLY__ */
-#endif				/* __ASM_IBM_OCP_H__ */
-#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibmnp405h.c b/arch/ppc/platforms/ibmnp405h.c
--- a/arch/ppc/platforms/ibmnp405h.c	Fri Oct 11 21:23:04 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,78 +0,0 @@
-/*
- *
- *    Copyright 2000-2002 MontaVista Software Inc.
- *      Completed implementation.
- *	Current maintainer
- *      Armin Kuster akuster@mvista.com
- *
- *    Module name: ibmnp405h.c
- *
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *      History: 01/02/2002 - armin
- *		initial release
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <platforms/ibmnp405h.h>
-
-const struct NS16550* COM_PORTS[] =
-{
-  (struct NS16550*) UART0_IO_BASE,
-  (struct NS16550*) UART1_IO_BASE,
-};
-
-const struct pcil0_regs* PCIL0[]=
-{
-	(struct pcil0_regs*)	PCIL0_BASE,
-};
-
-
-const struct iic_regs* IIC_ADDR[]=
-{
-	(struct iic_regs*) IIC0_BASE,
-};
-
-
-const struct gpio_regs* GPIO_ADDR[] =
-{
-	(struct gpio_regs*)	GPIO0_BASE,
-};
-
-const struct emac_regs* EMAC_ADDR[]=
-{
-	(struct emac_regs*) EMAC0_BASE,
-	(struct emac_regs*) EMAC1_BASE,
-	(struct emac_regs*) EMAC2_BASE,
-	(struct emac_regs*) EMAC3_BASE
-};
-
-const struct zmii_regs* ZMII_ADDR[]=
-{
-	(zmii_t*)	ZMII0_BASE,
-};
diff -Nru a/arch/ppc/platforms/ibmnp405h.h b/arch/ppc/platforms/ibmnp405h.h
--- a/arch/ppc/platforms/ibmnp405h.h	Fri Oct 11 21:22:59 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,172 +0,0 @@
-/*
- * ibmnp405h.h
- *
- *	This was dirived from the ibm405gp.h and other previus works in ppc4xx.h
- *
- *      Current maintainer
- *      Armin Kuster akuster@mvista.com
- *      Jan, 2002
- *
- *
- * Copyright 2002 MontaVista Softare Inc.
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 (02/01/03) - A. Kuster
- *	Initial version
- *
- *	Version 1.1 02/01/17 - A. Kuster
- *	moved common ofsets to ibm405.h
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IBMNP405H_H__
-#define __ASM_IBMNP405H_H__
-
-#include <linux/config.h>
-#include <platforms/ibm_ocp.h>
-
-/* ibm405.h at bottom of this file */
-
-#define PPC405_PCI_CONFIG_ADDR	0xeec00000
-#define PPC405_PCI_CONFIG_DATA	0xeec00004
-#define PPC405_PCI_PHY_MEM_BASE	0x80000000	/* hose_a->pci_mem_offset */
-						/* setbat */
-#define PPC405_PCI_MEM_BASE	PPC405_PCI_PHY_MEM_BASE	/* setbat */
-#define PPC405_PCI_PHY_IO_BASE	0xe8000000	/* setbat */
-#define PPC405_PCI_IO_BASE	PPC405_PCI_PHY_IO_BASE	/* setbat */
-
-#define PPC405_PCI_LOWER_MEM	0x00000000	/* hose_a->mem_space.start */
-#define PPC405_PCI_UPPER_MEM	0xBfffffff	/* hose_a->mem_space.end */
-#define PPC405_PCI_LOWER_IO	0x00000000	/* hose_a->io_space.start */
-#define PPC405_PCI_UPPER_IO	0x0000ffff	/* hose_a->io_space.end */
-
-#define PPC405_ISA_IO_BASE	PPC405_PCI_IO_BASE
-
-#define PPC4xx_PCI_IO_ADDR	((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
-#define PPC4xx_PCI_CFG_ADDR	((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
-#define PPC4xx_PCI_LCFG_ADDR	((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
-#define PPC4xx_ONB_IO_ADDR	((uint)0xef600000)
-#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
-
-/* serial port defines */
-#define RS_TABLE_SIZE	4
-
-#define UART0_INT	0
-#define UART1_INT	1
-#define PCIL0_BASE	0xEF400000
-#define UART0_IO_BASE	0xEF600300
-#define UART1_IO_BASE	0xEF600400
-#define IIC0_BASE	0xEF600500
-#define OPB0_BASE	0xEF600600
-#define GPIO0_BASE	0xEF600700
-#define EMAC0_BASE	0xEF600800
-#define EMAC1_BASE	0xEF600900
-#define EMAC2_BASE	0xEF600900
-#define EMAC3_BASE	0xEF600900
-#define ZMII0_BASE	0xEF600C10
-
-#define EMAC_NUMS	4
-#define UART_NUMS	2
-#define ZMII_NUMS	1
-#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
-
-#define STD_UART_OP(num)					\
-	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
-		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
-		iomem_base: UART##num##_IO_BASE,		\
-		io_type: SERIAL_IO_MEM},
-
-#if defined(CONFIG_UART0_TTYS0)
-#define SERIAL_PORT_DFNS        \
-        STD_UART_OP(0)          \
-        STD_UART_OP(1)
-#endif
-
-#if defined(CONFIG_UART0_TTYS1)
-#define SERIAL_PORT_DFNS        \
-        STD_UART_OP(1)          \
-        STD_UART_OP(0)
-#endif
-
-/* DCR defines */
-/* ------------------------------------------------------------------------- */
-
-#define DCRN_CHCR_BASE	0x0B1
-#define DCRN_CHPSR_BASE	0x0B4
-#define DCRN_CPMSR_BASE	0x0B8
-#define DCRN_CPMFR_BASE	0x0BA
-
-#define CPM_IIC0	0x80000000	/* IIC interface */
-#define CPM_PCI		0x40000000	/* PCI bridge */
-#define CPM_CPU		0x20000000	/* processor core */
-#define CPM_DMA		0x10000000	/* DMA controller */
-#define CPM_BRG		0x08000000	/* PLB to OPB bridge */
-#define CPM_DCP		0x04000000	/* CodePack */
-#define CPM_EBC		0x02000000	/* ROM/SRAM peripheral controller */
-#define CPM_SDRAM0	0x01000000	/* SDRAM memory controller */
-#define CPM_PLB		0x00800000	/* PLB bus arbiter */
-#define CPM_GPIO0	0x00400000	/* General Purpose IO (??) */
-#define CPM_UART0	0x00200000	/* serial port 0 */
-#define CPM_UART1	0x00100000	/* serial port 1 */
-#define CPM_UIC	=	0x00080000	/* Universal Interrupt Controller */
-#define CPM_TMRCLK	0x00040000	/* CPU timers */
-#define CPM_EMAC_MM	0x00020000	/* on-chip ethernet MM unit */
-#define CPM_EMAC_RM	0x00010000	/* on-chip ethernet RM unit */
-#define CPM_EMAC_TM	0x00008000	/* on-chip ethernet TM unit */
-
-#define DCRN_DMA0_BASE	0x100
-#define DCRN_DMA1_BASE	0x108
-#define DCRN_DMA2_BASE	0x110
-#define DCRN_DMA3_BASE	0x118
-#define DCRNCAP_DMA_SG	1	/* have DMA scatter/gather capability */
-#define DCRN_DMASR_BASE	0x120
-#define DCRN_EBC_BASE	0x012
-#define DCRN_DCP0_BASE	0x014
-#define DCRN_MAL_BASE	0x180
-#define DCRN_OCM0_BASE	0x018
-#define DCRN_PLB0_BASE	0x084
-#define DCRN_PLLMR_BASE	0x0B0
-#define DCRN_POB0_BASE	0x0A0
-#define DCRN_SDRAM0_BASE 0x010
-#define DCRN_UIC0_BASE	0x0C0
-
-/* unique H offsets */
-
-#ifdef DCRN_UIC1_BASE
-#define DCRN_UIC1_SR	(DCRN_UIC1_BASE + 0x0)
-#define DCRN_UIC1_SRS	(DCRN_UIC1_BASE + 0x1)
-#define DCRN_UIC1_ER	(DCRN_UIC1_BASE + 0x2)
-#define DCRN_UIC1_CR	(DCRN_UIC1_BASE + 0x3)
-#define DCRN_UIC1_PR	(DCRN_UIC1_BASE + 0x4)
-#define DCRN_UIC1_TR	(DCRN_UIC1_BASE + 0x5)
-#define DCRN_UIC1_MSR	(DCRN_UIC1_BASE + 0x6)
-#define DCRN_UIC1_VR	(DCRN_UIC1_BASE + 0x7)
-#define DCRN_UIC1_VCR	(DCRN_UIC1_BASE + 0x8)
-#endif
-
-#include <platforms/ibm405.h>
-
-#endif				/* __ASM_IBMNP405H_H__ */
-#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibmnp405l.c b/arch/ppc/platforms/ibmnp405l.c
--- a/arch/ppc/platforms/ibmnp405l.c	Fri Oct 11 21:22:54 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-/*
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *	Current maintainer
- *      Armin Kuster akuster@mvista.com
- *
- *    Module name: ibmnp405l.c
- *
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *      History: 12/26/2001 - armin
- *		initial release
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <platforms/ibmnp405l.h>
-
-const struct NS16550* COM_PORTS[] =
-{
-  (struct NS16550*) UART0_IO_BASE,
-  (struct NS16550*) UART1_IO_BASE,
-};
-
-const struct iic_regs* IIC_ADDR[]=
-{
-	(struct iic_regs*) IIC0_BASE,
-};
-
-
-const struct gpio_regs* GPIO_ADDR[] =
-{
-	(struct gpio_regs*)	GPIO0_BASE,
-};
-
-const struct emac_regs* EMAC_ADDR[]=
-{
-	(struct emac_regs*) EMAC0_BASE,
-	(struct emac_regs*) EMAC1_BASE
-};
-
-const struct zmii_regs* ZMII_ADDR[]=
-{
-	(zmii_t*)	ZMII0_BASE,
-};
diff -Nru a/arch/ppc/platforms/ibmnp405l.h b/arch/ppc/platforms/ibmnp405l.h
--- a/arch/ppc/platforms/ibmnp405l.h	Fri Oct 11 21:22:55 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,156 +0,0 @@
-/*
- * ibmnp405l.h
- *
- *	This was dirived from the ibm405gp.h and other previus works in ppc4xx.h
- *
- *      Current maintainer
- *      Armin Kuster akuster@mvista.com
- *      Oct, 2001
- *
- *
- * Copyright 2001 MontaVista Softare Inc.
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 (01/10/10) - A. Kuster
- *	Initial version
- *
- *	Version 1.1 (02/01/16) - A. Kuster
- *	Cleaned out common 405B3 core stuff
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IBMNP405L_H__
-#define __ASM_IBMNP405L_H__
-
-#include <linux/config.h>
-#include <platforms/ibm_ocp.h>
-
-/* ibm405.h at bottom of this file */
-
-#define PPC4xx_PCI_IO_ADDR	((uint)PPC405_PCI_PHY_IO_BASE)
-#define PPC4xx_PCI_IO_SIZE	((uint)64*1024)
-#define PPC4xx_PCI_CFG_ADDR	((uint)PPC405_PCI_CONFIG_ADDR)
-#define PPC4xx_PCI_CFG_SIZE	((uint)4*1024)
-#define PPC4xx_PCI_LCFG_ADDR	((uint)0xef400000)
-#define PPC4xx_PCI_LCFG_SIZE	((uint)4*1024)
-#define PPC4xx_ONB_IO_ADDR	((uint)0xef600000)
-#define PPC4xx_ONB_IO_SIZE	((uint)4*1024)
-
-/* serial port defines */
-#define RS_TABLE_SIZE	2
-
-#define UART0_INT	0
-#define UART1_INT	1
-
-#define UART0_IO_BASE	(u8 *)0xEF600300
-#define UART1_IO_BASE	(u8 *)0xEF600400
-#define IIC0_BASE	0xEF600500
-#define OPB0_BASE	0xEF600600
-#define GPIO0_BASE	0xEF600700
-#define EMAC0_BASE	0xEF600800
-#define EMAC1_BASE	0xEF600900
-#define ZMII0_BASE	0xEF600C10
-
-#define EMAC_NUMS	2
-#define UART_NUMS	2
-#define ZMII_NUMS	1
-#define BD_EMAC_ADDR(e,i) bi_enetaddr[e][i]
-
-#define STD_UART_OP(num)					\
-	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
-		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
-		iomem_base: UART##num##_IO_BASE,		\
-		io_type: SERIAL_IO_MEM},
-
-#if defined(CONFIG_UART0_TTYS0)
-#define SERIAL_PORT_DFNS        \
-        STD_UART_OP(0)          \
-        STD_UART_OP(1)
-#endif
-
-#if defined(CONFIG_UART0_TTYS1)
-#define SERIAL_PORT_DFNS        \
-        STD_UART_OP(1)          \
-        STD_UART_OP(0)
-#endif
-
-/* DCR defines */
-/* ------------------------------------------------------------------------- */
-
-#define DCRN_CHCR_BASE	0x0B1
-#define DCRN_CHPSR_BASE	0x0B4
-#define DCRN_CPMSR_BASE	0x0B8
-#define DCRN_CPMFR_BASE	0x0BA
-
-#define CPM_IIC0	0x80000000	/* IIC interface */
-#define CPM_PCI		0x40000000	/* PCI bridge */
-#define CPM_CPU		0x20000000	/* processor core */
-#define CPM_DMA		0x10000000	/* DMA controller */
-#define CPM_BRG		0x08000000	/* PLB to OPB bridge */
-#define CPM_DCP		0x04000000	/* CodePack */
-#define CPM_EBC		0x02000000	/* ROM/SRAM peripheral controller */
-#define CPM_SDRAM0	0x01000000	/* SDRAM memory controller */
-#define CPM_PLB		0x00800000	/* PLB bus arbiter */
-#define CPM_GPIO0	0x00400000	/* General Purpose IO (??) */
-#define CPM_UART0	0x00200000	/* serial port 0 */
-#define CPM_UART1	0x00100000	/* serial port 1 */
-#define CPM_UIC		0x00080000	/* Universal Interrupt Controller */
-#define CPM_TMRCLK	0x00040000	/* CPU timers */
-#define CPM_EMAC_MM	0x00020000	/* on-chip ethernet MM unit */
-#define CPM_EMAC_RM	0x00010000	/* on-chip ethernet RM unit */
-#define CPM_EMAC_TM	0x00008000	/* on-chip ethernet TM unit */
-
-#define DCRN_DMA0_BASE	0x100
-#define DCRN_DMA1_BASE	0x108
-#define DCRN_DMA2_BASE	0x110
-#define DCRN_DMA3_BASE	0x118
-#define DCRNCAP_DMA_SG	1	/* have DMA scatter/gather capability */
-#define DCRN_DMASR_BASE	0x120
-#define DCRN_EBC_BASE	0x012
-#define DCRN_DCP0_BASE	0x014
-#define DCRN_MAL_BASE	0x180
-#define DCRN_OCM0_BASE	0x018
-#define DCRN_PLB0_BASE	0x084
-#define DCRN_PLLMR_BASE	0x0B0
-#define DCRN_POB0_BASE	0x0A0
-#define DCRN_SDRAM0_BASE 0x010
-#define DCRN_UIC0_BASE	0x0C0
-#define DCRN_UIC1_BASE	0x0C0
-
-/* need to clean this up - armin */
-
-#ifdef DCRN_UIC1_BASE
-#define DCRN_UIC1_SR	(DCRN_UIC1_BASE + 0x0)
-#define DCRN_UIC1_SRS	(DCRN_UIC1_BASE + 0x1)
-#define DCRN_UIC1_ER	(DCRN_UIC1_BASE + 0x2)
-#define DCRN_UIC1_CR	(DCRN_UIC1_BASE + 0x3)
-#define DCRN_UIC1_PR	(DCRN_UIC1_BASE + 0x4)
-#define DCRN_UIC1_TR	(DCRN_UIC1_BASE + 0x5)
-#define DCRN_UIC1_MSR	(DCRN_UIC1_BASE + 0x6)
-#define DCRN_UIC1_VR	(DCRN_UIC1_BASE + 0x7)
-#define DCRN_UIC1_VCR	(DCRN_UIC1_BASE + 0x8)
-#endif
-
-#include <platforms/ibm405.h>
-
-#endif				/* __ASM_IBMNP405L_H__ */
-#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibmstb3.c b/arch/ppc/platforms/ibmstb3.c
--- a/arch/ppc/platforms/ibmstb3.c	Fri Oct 11 21:22:50 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-/*
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *	Current maintainer
- *      Armin Kuster akuster@mvista.com
- *
- *    Module name: ibmstb3.c
- *
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *      History: 01/08/2002 - armin
- *		initial release
- *
- */
-
-#include <linux/config.h>
-#include <platforms/ibmstb3.h>
-
-const struct NS16550* COM_PORTS[] =
-{
-  (struct NS16550*) UART0_IO_BASE,
-};
-
-const struct iic_regs* IIC_ADDR[]=
-{
-	(struct iic_regs*) IIC0_BASE,
-};
-
-const struct gpio_regs* GPIO_ADDR[] =
-{
-	(struct gpio_regs*)	GPIO0_BASE,
-};
-
diff -Nru a/arch/ppc/platforms/ibmstb3.h b/arch/ppc/platforms/ibmstb3.h
--- a/arch/ppc/platforms/ibmstb3.h	Fri Oct 11 21:23:04 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,288 +0,0 @@
-/*
- * ibmstbx.h
- *
- *	This was dirived from the ppc4xx.h and all stbx specific definitions
- *	are located here.
- *
- *      Armin Kuster <akuster@mvista.com>
- *      Tom Rini <trini@mvista.com>
- *      Oct, 2001
- *
- *
- *
- * Copyright 2001 MontaVista Softare Inc.
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 Oct 10, 2001 - A. Kuster
- *	Initial version	 - moved stbx  specific out of ibm4xx.h
- *
- *	Version 1.1 Oct 25, 2001 - T. Rini
- *	Lots of cleanups, and we get included by the board-specific file.
- *
- *	Version 1.2 Jan 16, 2002 - A. Kuster
- *	Removed common dcr offests that are now in ibm405.h 
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IBMSTBX_H__
-#define __ASM_IBMSTBX_H__
-
-#include <linux/config.h>
-#include <platforms/ibm_ocp.h>
-
-/* ibm405.h at bottom of this file */
-
-/*
- * Memory map for the IBM "Redwood-4" STB03xxx evaluation board.
- *
- * The  STB03xxx internal i/o addresses don't work for us 1:1,
- * so we need to map them at a well know virtual address.
- *
- * 4000 000x   uart1           -> 0xe000 000x
- * 4001 00xx   ppu
- * 4002 00xx   smart card
- * 4003 000x   iic
- * 4004 000x   uart0
- * 4005 0xxx   timer
- * 4006 00xx   gpio
- * 4007 00xx   smart card
- * 400b 000x   iic
- * 400c 000x   scp
- * 400d 000x   modem
- */
-
-#define STB03xxx_IO_BASE	((uint)0xe0000000)
-#define PPC4xx_ONB_IO_PADDR	((uint)0x40000000)
-#define PPC4xx_ONB_IO_VADDR	STB03xxx_IO_BASE
-#define PPC4xx_ONB_IO_SIZE	((uint)14*64*1024)
-
-/* Since we're into address mapping hacks, at least try to hide
- * it under a macro.....
- */
-#define STB03xxx_MAP_IO_ADDR(a)	(((uint)(a) & 0x000fffff) + PPC4xx_ONB_IO_VADDR)
-
-#define RS_TABLE_SIZE		1
-#define UART0_INT		20
-#ifdef __BOOTER__
-#define UART0_IO_BASE		(u8 *)0x40040000
-#else
-#define UART0_IO_BASE		(u8 *)STB03xxx_MAP_IO_ADDR(0x40040000)
-#endif
-
- /* UART 0 is duped here so when the SICC is the default console
-  * then ttys1 is configured properly - armin 
-  */
-
-#define UART1_INT		20
-#ifdef __BOOTER__
-#define UART1_IO_BASE		(u8 *)0x40040000
-#else
-#define UART1_IO_BASE		(u8 *)STB03xxx_MAP_IO_ADDR(0x40040000)
-#endif
-
-/* need to make this work in scheme - armin */
-
-#define SICC0_INTRX		21
-#define SICC0_INTTX		22
-#define SICC0_IO_BASE		((uint* )0x40000000)
-
-#define IIC0_BASE	0x40030000
-#define IIC1_BASE	0x400b0000
-#define OPB0_BASE	0x40010000
-#define GPIO0_BASE	0x40060000
-
-#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
-
-#define STD_UART_OP(num)					\
-	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
-		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
-		iomem_base: UART##num##_IO_BASE,		\
-		io_type: SERIAL_IO_MEM},
-
-#if defined(CONFIG_UART0_TTYS0)
-#define SERIAL_PORT_DFNS	\
-	STD_UART_OP(0)
-#endif
-
-#if defined(CONFIG_UART0_TTYS1)
-#define SERIAL_PORT_DFNS	\
-	STD_UART_OP(1)
-#endif
-
-/* ------------------------------------------------------------------------- */
-
-#define DCRN_DCRX_BASE		0x020
-#define DCRN_CIC_BASE 		0x030
-#define DCRN_UIC0_BASE		0x040
-#define DCRN_PLB0_BASE		0x054
-#define DCRN_PLB1_BASE		0x064
-#define DCRN_EBIMC_BASE		0x070
-#define DCRN_POB0_BASE		0x0B0
-
-#define DCRN_BE_BASE		0x090
-#define DCRN_DMA0_BASE		0x0C0
-#define DCRN_DMA1_BASE		0x0C8
-#define DCRN_DMA2_BASE		0x0D0
-#define DCRN_DMA3_BASE		0x0D8
-#define DCRNCAP_DMA_CC		1	/* have DMA chained count capability */
-#define DCRN_DMASR_BASE		0x0E0
-
-#define DCRN_CPMFR_BASE		0x102
-#define DCRN_SCCR_BASE		0x120
-
-#define CPM_IIC0	0x80000000	/* IIC 0 interface */
-#define CPM_I1284	0x40000000	/* IEEE-1284 */
-#define CPM_IIC1	0x20000000	/* IIC 1 interface */
-#define CPM_CPU		0x10000000	/* PPC405B3 clock control */
-#define CPM_AUD		0x08000000	/* Audio Decoder */
-#define CPM_EBIU	0x04000000	/* External Bus Interface Unit */
-#define CPM_SDRAM1	0x02000000	/* SDRAM 1 memory controller */
-#define CPM_DMA		0x01000000	/* DMA controller */
-#define CPM_RES_1	0x00800000	/* reserved */
-#define CPM_RES_2	0x00400000	/* reserved */
-#define CPM_RES_3	0x00200000	/* reserved */
-#define CPM_UART1	0x00100000	/* Serial 1 / Infrared */
-#define CPM_UART0	0x00080000	/* Serial 0 / 16550 */
-#define CPM_DCRX	0x00040000	/* DCR Extension */
-#define CPM_SC0		0x00020000	/* Smart Card 0 */
-#define CPM_RES_4	0x00010000	/* reserved */
-#define CPM_SC1		0x00008000	/* Smart Card 1 */
-#define CPM_SDRAM0	0x00004000	/* SDRAM 0 memory controller */
-#define CPM_XPT54	0x00002000	/* Transport - 54 Mhz */
-#define CPM_CBS		0x00001000	/* Cross Bar Switch */
-#define CPM_GPT		0x00000800	/* GPTPWM */
-#define CPM_GPIO0	0x00000400	/* General Purpose IO 0 */
-#define CPM_DENC	0x00000200	/* Digital video Encoder */
-#define CPM_TMRCLK	0x00000100	/* CPU timers */
-#define CPM_XPT27	0x00000080	/* Transport - 27 Mhz */
-#define CPM_UIC		0x00000040	/* Universal Interrupt Controller */
-#define CPM_RES_5	0x00000020	/* reserved */
-#define CPM_MSI		0x00000010	/* Modem Serial Interface (SSP) */
-#define CPM_UART2	0x00000008	/* Serial Control Port */
-#define CPM_DSCR	0x00000004	/* Descrambler */
-#define CPM_VID2	0x00000002	/* Video Decoder clock domain 2 */
-#define CPM_RES_6	0x00000001	/* reserved */
-
-/*			0x80000000 */
-#define UIC_XPORT	0x40000000	/* 1 Transport */
-#define UIC_AUDIO	0x20000000	/* 2 Audio Decoder */
-#define UIC_VIDEO	0x10000000	/* 3 Video Decoder */
-#define UIC_D0		0x08000000	/* 4 DMA Channel 0 */
-#define UIC_D1		0x04000000	/* 5 DMA Channel 1 */
-#define UIC_D2		0x02000000	/* 6 DMA Channel 2 */
-#define UIC_D3		0x01000000	/* 7 DMA Channel 3 */
-#define UIC_SC0		0x00800000	/* 8 SmartCard 0 Controller */
-#define UIC_IIC0	0x00400000	/* 9 IIC 0 */
-#define UIC_IIC1	0x00200000	/* 10 IIC 1 */
-#define UIC_PWM0	0x00100000	/* 11 GPT_PWM 0: Capture Timers */
-#define UIC_PWM1	0x00080000	/* 12 GPT_PWM 1: Compare Timers */
-#define UIC_SCP		0x00040000	/* 13 Serial Control Port */
-#define UIC_SSP		0x00020000	/* 14 Soft Modem/Synchronous Serial Port */
-#define UIC_PWM2	0x00010000	/* 15 GPT_PWM 2: Down Counters */
-#define UIC_SC1		0x00008000	/* 16 SmartCard 1 Controller */
-#define UIC_EIR7	0x00004000	/* 17 External IRQ 7 */
-#define UIC_EIR8	0x00002000	/* 18 External IRQ 8 */
-#define UIC_EIR9	0x00001000	/* 19 External IRQ 9 */
-#define UIC_U0		0x00000800	/* 20 UART0 */
-#define UIC_IR_RCV	0x00000400	/* 21 Serial 1 / Infrared UART Receive */
-#define UIC_IR_XMIT	0x00000200	/* 22 Serial 1 / Infrared UART Transmit */
-#define UIC_IEEE1284	0x00000100	/* 23 IEEE-1284 / PPU */
-#define UIC_DCRX	0x00000080	/* 24 DCRX */
-#define UIC_EIR0	0x00000040	/* 25 External IRQ 0 */
-#define UIC_EIR1	0x00000020	/* 26 External IRQ 1 */
-#define UIC_EIR2	0x00000010	/* 27 External IRQ 2 */
-#define UIC_EIR3	0x00000008	/* 28 External IRQ 3 */
-#define UIC_EIR4	0x00000004	/* 29 External IRQ 4 */
-#define UIC_EIR5	0x00000002	/* 30 External IRQ 5 */
-#define UIC_EIR6	0x00000001	/* 31 External IRQ 6 */
-
-#ifdef DCRN_CIC_BASE
-#define DCRN_CICCR	(DCRN_CIC_BASE + 0x0)	/* CIC Control Register */
-#define DCRN_DMAS1	(DCRN_CIC_BASE + 0x1)	/* DMA Select1 Register */
-#define DCRN_DMAS2	(DCRN_CIC_BASE + 0x2)	/* DMA Select2 Register */
-#define DCRN_CICVCR	(DCRN_CIC_BASE + 0x3)	/* CIC Video COntro Register */
-#define DCRN_CICSEL3	(DCRN_CIC_BASE + 0x5)	/* CIC Select 3 Register */
-#define DCRN_SGPO	(DCRN_CIC_BASE + 0x6)	/* CIC GPIO Output Register */
-#define DCRN_SGPOD	(DCRN_CIC_BASE + 0x7)	/* CIC GPIO OD Register */
-#define DCRN_SGPTC	(DCRN_CIC_BASE + 0x8)	/* CIC GPIO Tristate Ctrl Reg */
-#define DCRN_SGPI	(DCRN_CIC_BASE + 0x9)	/* CIC GPIO Input Reg */
-#endif
-
-#ifdef DCRN_DCRX_BASE
-#define DCRN_DCRXICR	(DCRN_DCRX_BASE + 0x0)	/* Internal Control Register */
-#define DCRN_DCRXISR	(DCRN_DCRX_BASE + 0x1)	/* Internal Status Register */
-#define DCRN_DCRXECR	(DCRN_DCRX_BASE + 0x2)	/* External Control Register */
-#define DCRN_DCRXESR	(DCRN_DCRX_BASE + 0x3)	/* External Status Register */
-#define DCRN_DCRXTAR	(DCRN_DCRX_BASE + 0x4)	/* Target Address Register */
-#define DCRN_DCRXTDR	(DCRN_DCRX_BASE + 0x5)	/* Target Data Register */
-#define DCRN_DCRXIGR	(DCRN_DCRX_BASE + 0x6)	/* Interrupt Generation Register */
-#define DCRN_DCRXBCR	(DCRN_DCRX_BASE + 0x7)	/* Line Buffer Control Register */
-#endif
-
-#ifdef DCRN_EBC_BASE
-#define DCRN_EBCCFGADR	(DCRN_EBC_BASE + 0x0)	/* Peripheral Controller Address */
-#define DCRN_EBCCFGDATA	(DCRN_EBC_BASE + 0x1)	/* Peripheral Controller Data */
-#endif
-
-#ifdef DCRN_EBIMC_BASE
-#define DCRN_BRCRH0	(DCRN_EBIMC_BASE + 0x0)	/* Bus Region Config High 0 */
-#define DCRN_BRCRH1	(DCRN_EBIMC_BASE + 0x1)	/* Bus Region Config High 1 */
-#define DCRN_BRCRH2	(DCRN_EBIMC_BASE + 0x2)	/* Bus Region Config High 2 */
-#define DCRN_BRCRH3	(DCRN_EBIMC_BASE + 0x3)	/* Bus Region Config High 3 */
-#define DCRN_BRCRH4	(DCRN_EBIMC_BASE + 0x4)	/* Bus Region Config High 4 */
-#define DCRN_BRCRH5	(DCRN_EBIMC_BASE + 0x5)	/* Bus Region Config High 5 */
-#define DCRN_BRCRH6	(DCRN_EBIMC_BASE + 0x6)	/* Bus Region Config High 6 */
-#define DCRN_BRCRH7	(DCRN_EBIMC_BASE + 0x7)	/* Bus Region Config High 7 */
-#define DCRN_BRCR0	(DCRN_EBIMC_BASE + 0x10)	/* BRC 0 */
-#define DCRN_BRCR1	(DCRN_EBIMC_BASE + 0x11)	/* BRC 1 */
-#define DCRN_BRCR2	(DCRN_EBIMC_BASE + 0x12)	/* BRC 2 */
-#define DCRN_BRCR3	(DCRN_EBIMC_BASE + 0x13)	/* BRC 3 */
-#define DCRN_BRCR4	(DCRN_EBIMC_BASE + 0x14)	/* BRC 4 */
-#define DCRN_BRCR5	(DCRN_EBIMC_BASE + 0x15)	/* BRC 5 */
-#define DCRN_BRCR6	(DCRN_EBIMC_BASE + 0x16)	/* BRC 6 */
-#define DCRN_BRCR7	(DCRN_EBIMC_BASE + 0x17)	/* BRC 7 */
-#define DCRN_BEAR0	(DCRN_EBIMC_BASE + 0x20)	/* Bus Error Address Register */
-#define DCRN_BESR0	(DCRN_EBIMC_BASE + 0x21)	/* Bus Error Status Register */
-#define DCRN_BIUCR	(DCRN_EBIMC_BASE + 0x2A)	/* Bus Interfac Unit Ctrl Reg */
-#endif
-
-#ifdef DCRN_SCCR_BASE
-#define DCRN_SCCR	(DCRN_SCCR_BASE + 0x0)
-#endif
-
-#ifdef DCRN_SDRAM0_BASE
-#define DCRN_SDRAM0_CFGADDR	(DCRN_SDRAM0_BASE + 0x0)	/* Memory Controller Address */
-#define DCRN_SDRAM0_CFGDATA	(DCRN_SDRAM0_BASE + 0x1)	/* Memory Controller Data */
-#endif
-
-#ifdef DCRN_OCM0_BASE
-#define DCRN_OCMISARC	(DCRN_OCM0_BASE + 0x0)	/* OCM Instr Side Addr Range Compare */
-#define DCRN_OCMISCR	(DCRN_OCM0_BASE + 0x1)	/* OCM Instr Side Control */
-#define DCRN_OCMDSARC	(DCRN_OCM0_BASE + 0x2)	/* OCM Data Side Addr Range Compare */
-#define DCRN_OCMDSCR	(DCRN_OCM0_BASE + 0x3)	/* OCM Data Side Control */
-#endif
-
-#include <platforms/ibm405.h>
-
-#endif				/* __ASM_IBMSTBX_H__ */
-#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/ibmstb4.c b/arch/ppc/platforms/ibmstb4.c
--- a/arch/ppc/platforms/ibmstb4.c	Fri Oct 11 21:22:54 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,61 +0,0 @@
-/*
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *	Current maintainer
- *      Armin Kuster akuster@mvista.com
- *
- *    Module name: ibmstb4.c
- *
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *      History: 12/26/2001 - armin
- *		initial release
- *
- */
-
-#include <linux/config.h>
-#include <platforms/ibmstb4.h>
-
-const struct NS16550* COM_PORTS[] =
-{
-  (struct NS16550*) UART0_IO_BASE,
-  (struct NS16550*) UART1_IO_BASE,
-  (struct NS16550*) UART2_IO_BASE,
-};
-
-const struct iic_regs* IIC_ADDR[]=
-{
-	(struct iic_regs*) IIC0_BASE,
-};
-
-
-const struct gpio_regs* GPIO_ADDR[] =
-{
-	(struct gpio_regs*)	GPIO0_BASE,
-};
-
-const struct ide_regs* IDE_ADDR[] =
-{
-	(struct ide_regs*) IDE0_IO_ADDR,
-
-};
diff -Nru a/arch/ppc/platforms/ibmstb4.h b/arch/ppc/platforms/ibmstb4.h
--- a/arch/ppc/platforms/ibmstb4.h	Fri Oct 11 21:23:04 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,268 +0,0 @@
-/*
- * ibmstb4.h
- *
- *	This was dirived from the ibm405gp.h and other previus works in ppc4xx.h
- *
- *      Current maintainer
- *      Armin Kuster akuster@mvista.com
- *      DEC, 2001
- *
- *
- * Copyright 2001 MontaVista Softare Inc.
- *
- * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 (01/10/10) - A. Kuster
- *	Initial version	
- *
- *	Version 1.1 02/01/17 - A. Kuster
- *	moved common offsets to ibm405.h
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_IBMSTB4_H__
-#define __ASM_IBMSTB4_H__
-
-#include <linux/config.h>
-#include <platforms/ibm_ocp.h>
-
-/* serial port defines */
-#define STB04xxx_IO_BASE	((uint)0xe0000000)
-#define PPC4xx_PCI_IO_ADDR	STB04xxx_IO_BASE
-#define PPC4xx_ONB_IO_PADDR	STB04xxx_IO_BASE
-#define PPC4xx_ONB_IO_VADDR	((uint)0xe0000000)
-#define PPC4xx_ONB_IO_SIZE	((uint)14*64*1024)
-
-/*
- * map STB04xxx internal i/o address (0x400x00xx) to an address
- * which is below the 2GB limit...
- *
- * 4000 000x	uart1		-> 0xe000 000x
- * 4001 00xx	ppu
- * 4002 00xx	smart card
- * 4003 000x	iic
- * 4004 000x	uart0
- * 4005 0xxx	timer
- * 4006 00xx	gpio
- * 4007 00xx	smart card
- * 400b 000x	iic
- * 400c 000x	scp
- * 400d 000x	modem
- * 400e 000x	uart2
-*/
-#define STB04xxx_MAP_IO_ADDR(a)	(((uint)(a)) + (STB04xxx_IO_BASE - 0x40000000))
-
-#define RS_TABLE_SIZE		3
-#define UART0_INT		20
-#define UART0_IO_BASE		(u8 *)0x40040000
-#define UART1_INT		21
-#define UART1_IO_BASE		(u8 *)0x40000000
-#define UART2_INT		31
-#define UART2_IO_BASE		(u8 *)0x400e0000
-
-#define IDE0_IO_ADDR	0x400F0000
-#define IDE0_IO_SIZE	0x200
-
-#define IIC0_BASE	0x40030000
-#define IIC1_BASE	0x400b0000
-#define OPB0_BASE	0x40000000
-#define GPIO0_BASE	0x40060000
-
-#define UART_NUMS	3
-
-#define BD_EMAC_ADDR(e,i) bi_enetaddr[i]
-
-#define STD_UART_OP(num)					\
-	{ 0, BASE_BAUD, 0, UART##num##_INT,			\
-		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
-		iomem_base: UART##num##_IO_BASE,		\
-		io_type: SERIAL_IO_MEM},
-
-#if defined(CONFIG_UART0_TTYS0)
-#define SERIAL_PORT_DFNS	\
-	STD_UART_OP(0)		\
-	STD_UART_OP(1)		\
-	STD_UART_OP(2)
-#endif
-
-#if defined(CONFIG_UART0_TTYS1)
-#define SERIAL_PORT_DFNS	\
-	STD_UART_OP(1)		\
-	STD_UART_OP(0)		\
-	STD_UART_OP(2)
-#endif
-
-#if defined(CONFIG_UART0_TTYS2)
-#define SERIAL_PORT_DFNS	\
-	STD_UART_OP(2)		\
-	STD_UART_OP(0)		\
-	STD_UART_OP(1)
-#endif
-
-#define DCRN_BE_BASE		0x090
-#define DCRN_DMA0_BASE		0x0C0
-#define DCRN_DMA1_BASE		0x0C8
-#define DCRN_DMA2_BASE		0x0D0
-#define DCRN_DMA3_BASE		0x0D8
-#define DCRNCAP_DMA_CC		1	/* have DMA chained count capability */
-#define DCRN_DMASR_BASE		0x0E0
-#define DCRN_PLB0_BASE		0x054
-#define DCRN_PLB1_BASE		0x064
-#define DCRN_POB0_BASE		0x0B0
-#define DCRN_SCCR_BASE		0x120
-#define DCRN_UIC0_BASE		0x040
-#define DCRN_BE_BASE		0x090
-#define DCRN_DMA0_BASE		0x0C0
-#define DCRN_DMA1_BASE		0x0C8
-#define DCRN_DMA2_BASE		0x0D0
-#define DCRN_DMA3_BASE		0x0D8
-#define DCRN_CIC_BASE 		0x030
-#define DCRN_DMASR_BASE		0x0E0
-#define DCRN_EBIMC_BASE		0x070
-#define DCRN_DCRX_BASE		0x020
-#define DCRN_CPMFR_BASE		0x102
-#define DCRN_SCCR_BASE		0x120
-
-#define CPM_IIC0	0x80000000	/* IIC 0 interface */
-#define CPM_I1284	0x40000000	/* IEEE-1284 */
-#define CPM_IIC1	0x20000000	/* IIC 1 interface */
-#define CPM_CPU		0x10000000	/* PPC405B3 clock control */
-#define CPM_AUD		0x08000000	/* Audio Decoder */
-#define CPM_EBIU	0x04000000	/* External Bus Interface Unit */
-#define CPM_SDRAM1	0x02000000	/* SDRAM 1 memory controller */
-#define CPM_DMA		0x01000000	/* DMA controller */
-#define CPM_RES_1	0x00800000	/* reserved */
-#define CPM_RES_2	0x00400000	/* reserved */
-#define CPM_RES_3	0x00200000	/* reserved */
-#define CPM_UART1	0x00100000	/* Serial 1 / Infrared */
-#define CPM_UART0	0x00080000	/* Serial 0 / 16550 */
-#define CPM_DCRX	0x00040000	/* DCR Extension */
-#define CPM_SC0		0x00020000	/* Smart Card 0 */
-#define CPM_RES_4	0x00010000	/* reserved */
-#define CPM_SC1		0x00008000	/* Smart Card 1 */
-#define CPM_SDRAM0	0x00004000	/* SDRAM 0 memory controller */
-#define CPM_XPT54	0x00002000	/* Transport - 54 Mhz */
-#define CPM_CBS		0x00001000	/* Cross Bar Switch */
-#define CPM_GPT		0x00000800	/* GPTPWM */
-#define CPM_GPIO0	0x00000400	/* General Purpose IO 0 */
-#define CPM_DENC	0x00000200	/* Digital video Encoder */
-#define CPM_TMRCLK	0x00000100	/* CPU timers */
-#define CPM_XPT27	0x00000080	/* Transport - 27 Mhz */
-#define CPM_UIC		0x00000040	/* Universal Interrupt Controller */
-#define CPM_RES_5	0x00000020	/* reserved */
-#define CPM_MSI		0x00000010	/* Modem Serial Interface (SSP) */
-#define CPM_UART2	0x00000008	/* Serial Control Port */
-#define CPM_DSCR	0x00000004	/* Descrambler */
-#define CPM_VID2	0x00000002	/* Video Decoder clock domain 2 */
-#define CPM_RES_6	0x00000001	/* reserved */
-
-/*			0x80000000 */
-#define UIC_XPORT	0x40000000	/* 1 Transport */
-#define UIC_AUDIO	0x20000000	/* 2 Audio Decoder */
-#define UIC_VIDEO	0x10000000	/* 3 Video Decoder */
-#define UIC_D0		0x08000000	/* 4 DMA Channel 0 */
-#define UIC_D1		0x04000000	/* 5 DMA Channel 1 */
-#define UIC_D2		0x02000000	/* 6 DMA Channel 2 */
-#define UIC_D3		0x01000000	/* 7 DMA Channel 3 */
-#define UIC_SC0		0x00800000	/* 8 SmartCard 0 Controller */
-#define UIC_IIC0	0x00400000	/* 9 IIC 0 */
-#define UIC_IIC1	0x00200000	/* 10 IIC 1 */
-#define UIC_PWM0	0x00100000	/* 11 GPT_PWM 0: Capture Timers */
-#define UIC_PWM1	0x00080000	/* 12 GPT_PWM 1: Compare Timers */
-#define UIC_SCP		0x00040000	/* 13 Serial Control Port */
-#define UIC_SSP		0x00020000	/* 14 Soft Modem/Synchronous Serial Port */
-#define UIC_PWM2	0x00010000	/* 15 GPT_PWM 2: Down Counters */
-#define UIC_SC1		0x00008000	/* 16 SmartCard 1 Controller */
-#define UIC_EIR7	0x00004000	/* 17 External IRQ 7 */
-#define UIC_EIR8	0x00002000	/* 18 External IRQ 8 */
-#define UIC_EIR9	0x00001000	/* 19 External IRQ 9 */
-#define UIC_U0		0x00000800	/* 20 UART0 */
-#define UIC_IR_RCV	0x00000400	/* 21 Serial 1 / Infrared UART Receive */
-#define UIC_IR_XMIT	0x00000200	/* 22 Serial 1 / Infrared UART Transmit */
-#define UIC_IEEE1284	0x00000100	/* 23 IEEE-1284 / PPU */
-#define UIC_DCRX	0x00000080	/* 24 DCRX */
-#define UIC_EIR0	0x00000040	/* 25 External IRQ 0 */
-#define UIC_EIR1	0x00000020	/* 26 External IRQ 1 */
-#define UIC_EIR2	0x00000010	/* 27 External IRQ 2 */
-#define UIC_EIR3	0x00000008	/* 28 External IRQ 3 */
-#define UIC_EIR4	0x00000004	/* 29 External IRQ 4 */
-#define UIC_EIR5	0x00000002	/* 30 External IRQ 5 */
-#define UIC_EIR6	0x00000001	/* 31 External IRQ 6 */
-
-#define DCRN_BEAR	(DCRN_BE_BASE + 0x0)	/* Bus Error Address Register */
-#define DCRN_BESR	(DCRN_BE_BASE + 0x1)	/* Bus Error Syndrome Register */
-/* DCRN_BESR */
-#define BESR_DSES	0x80000000	/* Data-Side Error Status */
-#define BESR_DMES	0x40000000	/* DMA Error Status */
-#define BESR_RWS	0x20000000	/* Read/Write Status */
-#define BESR_ETMASK	0x1C000000	/* Error Type */
-#define ET_PROT		0
-#define ET_PARITY	1
-#define ET_NCFG		2
-#define ET_BUSERR	4
-#define ET_BUSTO	6
-
-#define CHR1_CETE	0x00800000	/* CPU external timer enable */
-#define CHR1_PCIPW	0x00008000	/* PCI Int enable/Peripheral Write enable */
-
-#define DCRN_CICCR	(DCRN_CIC_BASE + 0x0)	/* CIC Control Register */
-#define DCRN_DMAS1	(DCRN_CIC_BASE + 0x1)	/* DMA Select1 Register */
-#define DCRN_DMAS2	(DCRN_CIC_BASE + 0x2)	/* DMA Select2 Register */
-#define DCRN_CICVCR	(DCRN_CIC_BASE + 0x3)	/* CIC Video COntro Register */
-#define DCRN_CICSEL3	(DCRN_CIC_BASE + 0x5)	/* CIC Select 3 Register */
-#define DCRN_SGPO	(DCRN_CIC_BASE + 0x6)	/* CIC GPIO Output Register */
-#define DCRN_SGPOD	(DCRN_CIC_BASE + 0x7)	/* CIC GPIO OD Register */
-#define DCRN_SGPTC	(DCRN_CIC_BASE + 0x8)	/* CIC GPIO Tristate Ctrl Reg */
-#define DCRN_SGPI	(DCRN_CIC_BASE + 0x9)	/* CIC GPIO Input Reg */
-
-#define DCRN_DCRXICR	(DCRN_DCRX_BASE + 0x0)	/* Internal Control Register */
-#define DCRN_DCRXISR	(DCRN_DCRX_BASE + 0x1)	/* Internal Status Register */
-#define DCRN_DCRXECR	(DCRN_DCRX_BASE + 0x2)	/* External Control Register */
-#define DCRN_DCRXESR	(DCRN_DCRX_BASE + 0x3)	/* External Status Register */
-#define DCRN_DCRXTAR	(DCRN_DCRX_BASE + 0x4)	/* Target Address Register */
-#define DCRN_DCRXTDR	(DCRN_DCRX_BASE + 0x5)	/* Target Data Register */
-#define DCRN_DCRXIGR	(DCRN_DCRX_BASE + 0x6)	/* Interrupt Generation Register */
-#define DCRN_DCRXBCR	(DCRN_DCRX_BASE + 0x7)	/* Line Buffer Control Register */
-
-#define DCRN_BRCRH0	(DCRN_EBIMC_BASE + 0x0)	/* Bus Region Config High 0 */
-#define DCRN_BRCRH1	(DCRN_EBIMC_BASE + 0x1)	/* Bus Region Config High 1 */
-#define DCRN_BRCRH2	(DCRN_EBIMC_BASE + 0x2)	/* Bus Region Config High 2 */
-#define DCRN_BRCRH3	(DCRN_EBIMC_BASE + 0x3)	/* Bus Region Config High 3 */
-#define DCRN_BRCRH4	(DCRN_EBIMC_BASE + 0x4)	/* Bus Region Config High 4 */
-#define DCRN_BRCRH5	(DCRN_EBIMC_BASE + 0x5)	/* Bus Region Config High 5 */
-#define DCRN_BRCRH6	(DCRN_EBIMC_BASE + 0x6)	/* Bus Region Config High 6 */
-#define DCRN_BRCRH7	(DCRN_EBIMC_BASE + 0x7)	/* Bus Region Config High 7 */
-#define DCRN_BRCR0	(DCRN_EBIMC_BASE + 0x10)	/* BRC 0 */
-#define DCRN_BRCR1	(DCRN_EBIMC_BASE + 0x11)	/* BRC 1 */
-#define DCRN_BRCR2	(DCRN_EBIMC_BASE + 0x12)	/* BRC 2 */
-#define DCRN_BRCR3	(DCRN_EBIMC_BASE + 0x13)	/* BRC 3 */
-#define DCRN_BRCR4	(DCRN_EBIMC_BASE + 0x14)	/* BRC 4 */
-#define DCRN_BRCR5	(DCRN_EBIMC_BASE + 0x15)	/* BRC 5 */
-#define DCRN_BRCR6	(DCRN_EBIMC_BASE + 0x16)	/* BRC 6 */
-#define DCRN_BRCR7	(DCRN_EBIMC_BASE + 0x17)	/* BRC 7 */
-#define DCRN_BEAR0	(DCRN_EBIMC_BASE + 0x20)	/* Bus Error Address Register */
-#define DCRN_BESR0	(DCRN_EBIMC_BASE + 0x21)	/* Bus Error Status Register */
-#define DCRN_BIUCR	(DCRN_EBIMC_BASE + 0x2A)	/* Bus Interfac Unit Ctrl Reg */
-
-#include <platforms/ibm405.h>
-
-#endif				/* __ASM_IBMSTB4_H__ */
-#endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/redwood.c b/arch/ppc/platforms/redwood.c
--- a/arch/ppc/platforms/redwood.c	Fri Oct 11 21:23:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-/*
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *      Author: MontaVista Software, Inc.  <source@mvista.com>
- *              Frank Rowand <frank_rowand@mvista.com>
- *
- *    Module name: redwood.c
- *
- *    Description:
- *
- *      History:  11/09/2001 - Armin
- *      added board_init to add in additional instuctions needed during platfrom_init
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <asm/pgtable.h>
-#include <asm/ibm4xx.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-
-void __init
-board_setup_arch(void)
-{
-}
-
-void __init
-board_io_mapping(void)
-{
-	int i;
-
-	io_block_mapping(OAKNET_IO_VADDR,
-			 OAKNET_IO_PADDR, OAKNET_IO_SIZE, _PAGE_IO);
-
-}
-
-void __init
-board_setup_irq(void)
-{
-}
-
-void __init
-board_init(void)
-{
-}
diff -Nru a/arch/ppc/platforms/redwood.h b/arch/ppc/platforms/redwood.h
--- a/arch/ppc/platforms/redwood.h	Fri Oct 11 21:23:06 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,51 +0,0 @@
-/*
- *    Copyright 2001 MontaVista Software Inc.
- *	PPC405 modifications
- * 	Author: MontaVista Software, Inc.
- *         	frank_rowand@mvista.com or source@mvista.com
- *
- *    Module name: redwood.h
- *
- *    Description:
- *      Macros, definitions, and data structures specific to the IBM PowerPC
- *      STB03xxx "Redwood" evaluation board.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_REDWOOD_H__
-#define __ASM_REDWOOD_H__
-
-/* Redwoods have an STB03xxx or STB04xxx core */
-#include <platforms/ibmstb3.h>
-
-#ifndef __ASSEMBLY__
-typedef struct board_info {
-	unsigned char	bi_s_version[4];	/* Version of this structure */
-	unsigned char	bi_r_version[30];	/* Version of the IBM ROM */
-	unsigned int	bi_memsize;		/* DRAM installed, in bytes */
-	unsigned int	bi_dummy;		/* field shouldn't exist */
-	unsigned char	bi_enetaddr[6];		/* Ethernet MAC address */
-	unsigned int	bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	bi_busfreq;		/* Bus speed, in Hz */
-	unsigned int	bi_tbfreq;		/* Software timebase freq */
-} bd_t;
-#endif /* !__ASSEMBLY__ */
-
-#define OAKNET_IO_PADDR		((uint)0xf2000000)
-#define OAKNET_IO_VADDR		OAKNET_IO_PADDR
-#define OAKNET_IO_BASE		OAKNET_IO_VADDR
-
-/* ftr revisit- io size was 0xffff in old-line, is 0x40 in oak.h */
-#define OAKNET_IO_SIZE		0xffff
-#define OAKNET_INT		26	/* EXTINT1 */
-
-#define _IO_BASE	0
-#define _ISA_MEM_BASE	0
-#define PCI_DRAM_OFFSET	0
-
-#define BASE_BAUD		1312500
-
-#define PPC4xx_MACHINE_NAME	"IBM Redwood"
-
-#endif /* __ASM_REDWOOD_H__ */
-#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/redwood5.c b/arch/ppc/platforms/redwood5.c
--- a/arch/ppc/platforms/redwood5.c	Fri Oct 11 21:22:55 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,82 +0,0 @@
-/*
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *      Author: Armin Kuster
- *
- *    Module name: redwood5.c
- *
- *    Description:
- *    	IBM redwood5 eval board file
- *
- *      History:  12/29/2001 - Armin
- *    	initail release
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-
-void __init
-board_setup_arch(void)
-{
-
-	bd_t *bip = (bd_t *)__res;
-
-#define CONFIG_DEBUG_BRINGUP
-#ifdef CONFIG_DEBUG_BRINGUP
-	printk("\n");
-	printk("machine\t: %s\n", PPC4xx_MACHINE_NAME);
-	printk("\n");
-	printk("bi_s_version\t %s\n",      bip->bi_s_version);
-	printk("bi_r_version\t %s\n",      bip->bi_r_version);
-	printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000));
-	printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0,
-	bip->bi_enetaddr[0], bip->bi_enetaddr[1],
-	bip->bi_enetaddr[2], bip->bi_enetaddr[3],
-	bip->bi_enetaddr[4], bip->bi_enetaddr[5]);
-
-	printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n",
-	       bip->bi_intfreq, bip->bi_intfreq/ 1000000);
-
-	printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n",
-		bip->bi_busfreq, bip->bi_busfreq / 1000000 );
-	printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n",
-	       bip->bi_tbfreq, bip->bi_tbfreq/1000000);
-
-	printk("\n");
-#endif
-
-}
-
-void __init
-board_io_mapping(void)
-{
-	int i;
-
-	for (i = 0; i < 16; i++) {
-	 unsigned long v, p;
-
-	/* 0x400x0000 -> 0xe00x0000 */
-	p = 0x40000000 | (i << 16);
-	v = STB04xxx_IO_BASE | (i << 16);
-
-	io_block_mapping(v, p, PAGE_SIZE,
-		 _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) | _PAGE_GUARDED);
-	}
-
-
-}
-
-void __init
-board_setup_irq(void)
-{
-}
-
-void __init
-board_init(void)
-{
-}
diff -Nru a/arch/ppc/platforms/redwood5.h b/arch/ppc/platforms/redwood5.h
--- a/arch/ppc/platforms/redwood5.h	Fri Oct 11 21:22:52 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,54 +0,0 @@
-/*
- *    Copyright 2001 MontaVista Software Inc.
- *	PPC405 modifications
- * 	Author: MontaVista Software, Inc.
- *          Armin Kuster
- *
- *    Module name: redwood5.h
- *
- *    Description:
- *      Macros, definitions, and data structures specific to the IBM PowerPC
- *      STB03xxx "Redwood" evaluation board.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_REDWOOD5_H__
-#define __ASM_REDWOOD5_H__
-
-/* Redwood5 has an STB04xxx core */
-#include <platforms/ibmstb4.h>
-
-#ifndef __ASSEMBLY__
-typedef struct board_info {
-	unsigned char	bi_s_version[4];	/* Version of this structure */
-	unsigned char	bi_r_version[30];	/* Version of the IBM ROM */
-	unsigned int	bi_memsize;		/* DRAM installed, in bytes */
-	unsigned int	bi_dummy;		/* field shouldn't exist */
-	unsigned char	bi_enetaddr[6];		/* Ethernet MAC address */
-	unsigned int	bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	bi_busfreq;		/* Bus speed, in Hz */
-	unsigned int	bi_tbfreq;		/* Software timebase freq */
-} bd_t;
-#endif /* !__ASSEMBLY__ */
-
-
-#define SMC91111_BASE_ADDR	0xf2000300
-#define SMC91111_IRQ		28
-
-#ifdef MAX_HWIFS
-#undef MAX_HWIFS
-#endif
-#define MAX_HWIFS		1
-
-#define _IO_BASE	0
-#define _ISA_MEM_BASE	0
-#define PCI_DRAM_OFFSET	0
-
-/* serail defines moved from ppc4xx_serial.h *
- */
-#define BASE_BAUD		1267200
-
-#define PPC4xx_MACHINE_NAME	"IBM Redwood5"
-
-#endif /* __ASM_REDWOOD5_H__ */
-#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/walnut.c b/arch/ppc/platforms/walnut.c
--- a/arch/ppc/platforms/walnut.c	Fri Oct 11 21:23:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,260 +0,0 @@
-/*
- *
- *    Copyrigh t(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *      Author: MontaVista Software, Inc.  <source@mvista.com>
- *
- *    Module name: walnut.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      IBM PowerPC 4xx based boards. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.com>.
- *
- *      History: 11/09/2001 - armin
- *      added board_init to add in additional instuctions needed during platfrom_init
- *
- *      01/22/2002 - Armin
- *      converted pci to ocp
- *
- *
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/blk.h>
-#include <linux/pci.h>
-#include <linux/rtc.h>
-
-#include <asm/system.h>
-#include <asm/pci-bridge.h>
-#include <asm/processor.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/time.h>
-#include <asm/io.h>
-#include <platforms/ibm_ocp.h>
-
-#ifdef CONFIG_PPC_RTC
-#include <asm/todc.h>
-#endif
-
-#include "walnut.h"
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-void *kb_cs;
-void *kb_data;
-void *walnut_rtc_base;
-
-/* Some IRQs unique to Walnut.
- * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
- */
-int __init
-ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	    /*
-	     *      PCI IDSEL/INTPIN->INTLINE
-	     *      A       B       C       D
-	     */
-	{
-		{28, 28, 28, 28},	/* IDSEL 1 - PCI slot 1 */
-		{29, 29, 29, 29},	/* IDSEL 2 - PCI slot 2 */
-		{30, 30, 30, 30},	/* IDSEL 3 - PCI slot 3 */
-		{31, 31, 31, 31},	/* IDSEL 4 - PCI slot 4 */
-	};
-
-	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-};
-
-void __init
-board_setup_arch(void)
-{
-	void *fpga_brdc;
-	unsigned char fpga_brdc_data;
-	void *fpga_enable;
-	void *fpga_polarity;
-	void *fpga_status;
-	void *fpga_trigger;
-
-	kb_data = ioremap(WALNUT_PS2_BASE, 8);
-	if (!kb_data) {
-		printk(KERN_CRIT
-		       "walnut_setup_arch() kb_data ioremap failed\n");
-		return;
-	}
-
-	kb_cs = kb_data + 1;
-
-	fpga_status = ioremap(WALNUT_FPGA_BASE, 8);
-	if (!fpga_status) {
-		printk(KERN_CRIT
-		       "walnut_setup_arch() fpga_status ioremap failed\n");
-		return;
-	}
-
-	fpga_enable = fpga_status + 1;
-	fpga_polarity = fpga_status + 2;
-	fpga_trigger = fpga_status + 3;
-	fpga_brdc = fpga_status + 4;
-
-	/* split the keyboard and mouse interrupts */
-	fpga_brdc_data = readb(fpga_brdc);
-	fpga_brdc_data |= 0x80;
-	writeb(fpga_brdc_data, fpga_brdc);
-
-	writeb(0x3, fpga_enable);
-
-	writeb(0x3, fpga_polarity);
-
-	writeb(0x3, fpga_trigger);
-
-#ifdef CONFIG_PPC_RTC
-	/* RTC step for the walnut */
-	walnut_rtc_base = (void *) WALNUT_RTC_VADDR;
-	TODC_INIT(TODC_TYPE_DS1743, walnut_rtc_base, walnut_rtc_base,
-		  walnut_rtc_base, 8);
-#endif				/* CONFIG_PPC_RTC */
-}
-
-void __init
-bios_fixup(struct pci_controller *hose, void *pcil0_base)
-{
-
-	unsigned int bar_response, bar;
-	struct pcil0_regs *pcip;
-	/*
-	 * Expected PCI mapping:
-	 *
-	 *  PLB addr             PCI memory addr
-	 *  ---------------------       ---------------------
-	 *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
-	 *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
-	 *
-	 *  PLB addr             PCI io addr
-	 *  ---------------------       ---------------------
-	 *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
-	 *
-	 * The following code is simplified by assuming that the bootrom
-	 * has been well behaved in following this mapping.
-	 */
-
-#ifdef DEBUG
-	int i;
-	pcip = (struct pcil0_regs *) pcil0_base;
-
-	printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
-	printk("PCI bridge regs before fixup \n");
-	for (i = 0; i <= 3; i++) {
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
-	}
-	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-
-#else
-	pcip = (struct pcil0_regs *) pcil0_base;
-#endif
-
-	/* added for IBM boot rom version 1.15 bios bar changes  -AK */
-
-	/* Disable region first */
-	out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
-	/* PLB starting addr, PCI: 0x80000000 */
-	out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
-	/* PCI start addr, 0x80000000 */
-	out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
-	/* 512MB range of PLB to PCI */
-	out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
-	/* Enable no pre-fetch, enable region */
-	out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
-						(PPC405_PCI_UPPER_MEM -
-						 PPC405_PCI_MEM_BASE)) | 0x01));
-
-	/* Disable region one */
-	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
-	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
-	out_le32((void *) &(pcip->ptm1ms), 0x00000000);
-
-	/* Disable region two */
-	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
-	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
-	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
-
-	/* Zero config bars */
-	for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
-		early_write_config_dword(hose, hose->first_busno,
-					 PCI_FUNC(hose->first_busno), bar,
-					 0x00000000);
-		early_read_config_dword(hose, hose->first_busno,
-					PCI_FUNC(hose->first_busno), bar,
-					&bar_response);
-		DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
-		    hose->first_busno, PCI_SLOT(hose->first_busno),
-		    PCI_FUNC(hose->first_busno), bar, bar_response);
-	}
-	/* end work arround */
-
-#ifdef DEBUG
-	printk("PCI bridge regs after fixup \n");
-	for (i = 0; i <= 3; i++) {
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
-		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
-	}
-	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
-	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
-	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
-	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
-
-#endif
-}
-
-void __init
-board_io_mapping(void)
-{
-	io_block_mapping(WALNUT_RTC_VADDR,
-			 WALNUT_RTC_PADDR, WALNUT_RTC_SIZE, _PAGE_IO);
-}
-
-void __init
-board_setup_irq(void)
-{
-}
-
-void __init
-board_init(void)
-{
-#ifdef CONFIG_PPC_RTC
-	ppc_md.time_init = todc_time_init;
-	ppc_md.set_rtc_time = todc_set_rtc_time;
-	ppc_md.get_rtc_time = todc_get_rtc_time;
-	ppc_md.nvram_read_val = todc_direct_read_val;
-	ppc_md.nvram_write_val = todc_direct_write_val;
-#endif
-}
diff -Nru a/arch/ppc/platforms/walnut.h b/arch/ppc/platforms/walnut.h
--- a/arch/ppc/platforms/walnut.h	Fri Oct 11 21:22:58 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,80 +0,0 @@
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Copyright 2000 MontaVista Software Inc.
- *	PPC405 modifications
- * 	Author: MontaVista Software, Inc.
- *         	frank_rowand@mvista.com or source@mvista.com
- * 	   	debbie_chu@mvista.com
- *
- *    Module name: ppc405.h
- *
- *    Description:
- *      Macros, definitions, and data structures specific to the IBM PowerPC
- *      based boards.
- *
- *      This includes:
- *
- *         405GP "Walnut" evaluation board
- *
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_WALNUT_H__
-#define __ASM_WALNUT_H__
-
-/* We have a 405GP core */
-#include <platforms/ibm405gp.h>
-
-#ifndef __ASSEMBLY__
-/*
- * Data structure defining board information maintained by the boot
- * ROM on IBM's "Walnut" evaluation board. An effort has been made to
- * keep the field names consistent with the 8xx 'bd_t' board info
- * structures.
- */
-
-typedef struct board_info {
-	unsigned char	 bi_s_version[4];	/* Version of this structure */
-	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
-	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
-	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
-	unsigned char	 bi_pci_enetaddr[6];	/* PCI Ethernet MAC address */
-	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
-	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
-	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-
-/* Memory map for the IBM "Walnut" 405GP evaluation board.
- * Generic 4xx plus RTC.
- */
-
-extern void *walnut_rtc_base;
-#define WALNUT_RTC_PADDR	((uint)0xf0000000)
-#define WALNUT_RTC_VADDR	WALNUT_RTC_PADDR
-#define WALNUT_RTC_SIZE		((uint)8*1024)
-
-/* ps2 keyboard and mouse */
-#define KEYBOARD_IRQ		25
-#define AUX_IRQ			26
-
-#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
-#define BASE_BAUD		201600
-#else
-#define BASE_BAUD		691200
-#endif
-
-#define WALNUT_PS2_BASE		0xF0100000
-#define WALNUT_FPGA_BASE	0xF0300000
-
-#define PPC4xx_MACHINE_NAME	"IBM Walnut"
-
-#endif /* !__ASSEMBLY__ */
-#endif /* __ASM_WALNUT_H__ */
-#endif /* __KERNEL__ */
diff -Nru a/arch/ppc/vmlinux.lds.S b/arch/ppc/vmlinux.lds.S
--- a/arch/ppc/vmlinux.lds.S	Fri Oct 11 21:23:06 2002
+++ b/arch/ppc/vmlinux.lds.S	Fri Oct 11 21:23:06 2002
@@ -147,6 +147,10 @@
   . = ALIGN(4096);
   __openfirmware_end = .;
 
+  __start___kallsyms = .;     /* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
   __bss_start = .;
   .bss       :
   {
@@ -155,6 +159,8 @@
    *(.bss)
    *(COMMON)
   }
+  __bss_stop = .;
+
   _end = . ;
   PROVIDE (end = .);
 }
diff -Nru a/arch/ppc64/config.in b/arch/ppc64/config.in
--- a/arch/ppc64/config.in	Fri Oct 11 21:22:54 2002
+++ b/arch/ppc64/config.in	Fri Oct 11 21:22:54 2002
@@ -21,6 +21,7 @@
 bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_SMP" = "y" ]; then
   bool '  Distribute interrupts on all CPUs by default' CONFIG_IRQ_ALL_CPUS
+  int  'Maximum number of CPUs (2-64)' CONFIG_NR_CPUS 64
   if [ "$CONFIG_PPC_PSERIES" = "y" ]; then
     bool '  Hardware multithreading' CONFIG_HMT
     bool '  Discontiguous Memory Support' CONFIG_DISCONTIGMEM
diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig
--- a/arch/ppc64/defconfig	Fri Oct 11 21:22:55 2002
+++ b/arch/ppc64/defconfig	Fri Oct 11 21:22:55 2002
@@ -40,6 +40,7 @@
 # CONFIG_DISCONTIGMEM is not set
 # CONFIG_PREEMPT is not set
 # CONFIG_RTAS_FLASH is not set
+CONFIG_NR_CPUS=64
 
 #
 # General setup
diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c	Fri Oct 11 21:23:05 2002
+++ b/arch/ppc64/kernel/ioctl32.c	Fri Oct 11 21:23:05 2002
@@ -555,7 +555,7 @@
 	
 	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 		return -EFAULT;
-	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
 	if (!ifr.ifr_data)
 		return -EAGAIN;
 
@@ -620,7 +620,7 @@
 	
 	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 		return -EFAULT;
-	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
 	if (!ifr.ifr_data)
 		return -EAGAIN;
 
diff -Nru a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c
--- a/arch/ppc64/kernel/rtas_flash.c	Fri Oct 11 21:23:04 2002
+++ b/arch/ppc64/kernel/rtas_flash.c	Fri Oct 11 21:23:04 2002
@@ -43,7 +43,7 @@
 	if ((file->f_mode & FMODE_WRITE) && flash_possible) {
 		if (flist)
 			return -EBUSY;
-		flist = (struct flash_block_list *)get_free_page(GFP_KERNEL);
+		flist = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL);
 		if (!flist)
 			return -ENOMEM;
 	}
@@ -175,7 +175,7 @@
 	next_free = fl->num_blocks;
 	if (next_free == FLASH_BLOCKS_PER_NODE) {
 		/* Need to allocate another block_list */
-		fl->next = (struct flash_block_list *)get_free_page(GFP_KERNEL);
+		fl->next = (struct flash_block_list *)get_zeroed_page(GFP_KERNEL);
 		if (!fl->next)
 			return -ENOMEM;
 		fl = fl->next;
@@ -184,7 +184,7 @@
 
 	if (len > PAGE_SIZE)
 		len = PAGE_SIZE;
-	p = (char *)get_free_page(GFP_KERNEL);
+	p = (char *)get_zeroed_page(GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 	if(copy_from_user(p, buffer, len)) {
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Fri Oct 11 21:23:02 2002
+++ b/arch/ppc64/kernel/sys_ppc32.c	Fri Oct 11 21:23:02 2002
@@ -1575,7 +1575,7 @@
 	memset(karg, 0, sizeof(*karg));
 	if(__get_user(karg->ca_version, &arg32->ca32_version))
 		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+	karg->ca_umap.ug_ident = (char *)get_zeroed_page(GFP_USER);
 	if(!karg->ca_umap.ug_ident)
 		return -ENOMEM;
 	err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident);
diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile
--- a/arch/s390/Makefile	Fri Oct 11 21:22:54 2002
+++ b/arch/s390/Makefile	Fri Oct 11 21:22:54 2002
@@ -17,9 +17,7 @@
 OBJCOPYFLAGS	:= -O binary
 LDFLAGS_vmlinux := -e start
 
-CFLAGS_PIPE := -pipe
-CFLAGS_NSR  := -fno-strength-reduce
-CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR)
+CFLAGS += -pipe -fno-strength-reduce
 
 HEAD := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
 
@@ -38,11 +36,24 @@
 image: vmlinux 
 	@$(MAKEBOOT) image
 
+install: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=image install
+
 archclean:
-	@$(MAKEBOOT) clean
-	$(MAKE) -C arch/$(ARCH)/kernel clean
 
 archmrproper:
 
-install: vmlinux
-	@$(MAKEBOOT) BOOTIMAGE=image install
+prepare: include/asm-$(ARCH)/offsets.h
+
+arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
+				   include/config/MARKER
+
+include/asm-$(ARCH)/offsets.h.tmp: arch/$(ARCH)/kernel/asm-offsets.s
+	@$(generate-asm-offsets.h) < $< > $@
+
+include/asm-$(ARCH)/offsets.h: include/asm-$(ARCH)/offsets.h.tmp
+	@echo -n '  Generating $@'
+	@$(update-if-changed)
+
+CLEAN_FILES += include/asm-$(ARCH)/offsets.h.tmp \
+	       include/asm-$(ARCH)/offsets.h
diff -Nru a/arch/s390/config.in b/arch/s390/config.in
--- a/arch/s390/config.in	Fri Oct 11 21:23:03 2002
+++ b/arch/s390/config.in	Fri Oct 11 21:23:03 2002
@@ -21,6 +21,9 @@
 comment 'Processor type and features'
 bool 'Symmetric multi-processing support' CONFIG_SMP
 bool 'IEEE FPU emulation' CONFIG_MATHEMU
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
 
 comment 'I/O subsystem configuration'
 bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig
--- a/arch/s390/defconfig	Fri Oct 11 21:23:03 2002
+++ b/arch/s390/defconfig	Fri Oct 11 21:23:03 2002
@@ -39,6 +39,7 @@
 #
 CONFIG_SMP=y
 CONFIG_MATHEMU=y
+CONFIG_NR_CPUS=64
 
 #
 # I/O subsystem configuration
@@ -91,6 +92,7 @@
 #
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -121,6 +123,7 @@
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
diff -Nru a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
--- a/arch/s390/kernel/Makefile	Fri Oct 11 21:23:04 2002
+++ b/arch/s390/kernel/Makefile	Fri Oct 11 21:23:04 2002
@@ -19,26 +19,3 @@
 obj-$(CONFIG_REMOTE_DEBUG)	+= gdb-stub.o #gdb-low.o 
 
 include $(TOPDIR)/Rules.make
-
-.PHONY: asm-offsets.h
-
-entry.S: asm-offsets.h
-
-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
-
-
diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
--- a/arch/s390/kernel/entry.S	Fri Oct 11 21:22:54 2002
+++ b/arch/s390/kernel/entry.S	Fri Oct 11 21:22:54 2002
@@ -17,8 +17,7 @@
 #include <asm/errno.h>
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
-
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 
 /*
  * Stack layout for the system_call stack entry.
@@ -178,11 +177,11 @@
 system_call:
 	SAVE_ALL_BASE
         SAVE_ALL __LC_SVC_OLD_PSW,1
-	lh	%r8,0x8a	  # get svc number from lowcore
-        sll     %r8,2
+	lh	%r7,0x8a	  # get svc number from lowcore
         GET_THREAD_INFO           # load pointer to task_struct to R9
+	sll	%r7,2
         stosm   24(%r15),0x03     # reenable interrupts
-        l       %r8,sys_call_table-entry_base(%r8,%r13) # get system call addr.
+        l       %r8,sys_call_table-entry_base(%r7,%r13) # get system call addr.
 	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
         bo      BASED(sysc_tracesys)
         basr    %r14,%r8          # call sys_xxxx
@@ -242,13 +241,13 @@
 #
 sysc_tracesys:
         l       %r1,BASED(.Ltrace)
-	mvc	SP_R2(4,%r15),BASED(.Lc_ENOSYS)
+	srl	%r7,2
+	st	%r7,SP_R2(4,%r15)
 	basr	%r14,%r1
-	clc	SP_R2(4,%r15),BASED(.Lc256)
-	bnl	BASED(sysc_tracego)
-	l	%r8,SP_R2(%r15)   # strace changed the syscall
-	sll     %r8,2
-	l	%r8,sys_call_table-entry_base(%r8,%r13)
+	l	%r7,SP_R2(4,%r15)      # strace might have changed the 
+	n	%r7,BASED(.Lc256)      #  system call
+	sll	%r7,2
+	l	%r8,sys_call_table-entry_base(%r7,%r13)
 sysc_tracego:
 	lm	%r3,%r6,SP_R3(%r15)
 	l	%r2,SP_ORIG_R2(%r15)
diff -Nru a/arch/s390/vmlinux.lds.S b/arch/s390/vmlinux.lds.S
--- a/arch/s390/vmlinux.lds.S	Fri Oct 11 21:22:55 2002
+++ b/arch/s390/vmlinux.lds.S	Fri Oct 11 21:22:55 2002
@@ -66,7 +66,7 @@
   __initcall_end = .;
   . = ALIGN(256);
   __per_cpu_start = .;
-  .date.percpu  : { *(.data.percpu) }
+  .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -Nru a/arch/s390x/Makefile b/arch/s390x/Makefile
--- a/arch/s390x/Makefile	Fri Oct 11 21:22:58 2002
+++ b/arch/s390x/Makefile	Fri Oct 11 21:22:58 2002
@@ -18,9 +18,7 @@
 LDFLAGS_vmlinux := -e start
 MODFLAGS += -fpic
 
-CFLAGS_PIPE := -pipe
-CFLAGS_NSR  := -fno-strength-reduce
-CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR)
+CFLAGS += -pipe -fno-strength-reduce
 
 HEAD := arch/s390x/kernel/head.o arch/s390x/kernel/init_task.o
 
@@ -42,7 +40,20 @@
 	@$(MAKEBOOT) BOOTIMAGE=image install
 
 archclean:
-	@$(MAKEBOOT) clean
-	$(MAKE) -C arch/$(ARCH)/kernel clean
 
 archmrproper:
+
+prepare: include/asm-$(ARCH)/offsets.h
+
+arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
+				   include/config/MARKER
+
+include/asm-$(ARCH)/offsets.h.tmp: arch/$(ARCH)/kernel/asm-offsets.s
+	@$(generate-asm-offsets.h) < $< > $@
+
+include/asm-$(ARCH)/offsets.h: include/asm-$(ARCH)/offsets.h.tmp
+	@echo -n '  Generating $@'
+	@$(update-if-changed)
+
+CLEAN_FILES += include/asm-$(ARCH)/offsets.h.tmp \
+	       include/asm-$(ARCH)/offsets.h
diff -Nru a/arch/s390x/config.in b/arch/s390x/config.in
--- a/arch/s390x/config.in	Fri Oct 11 21:22:53 2002
+++ b/arch/s390x/config.in	Fri Oct 11 21:22:53 2002
@@ -20,6 +20,9 @@
 comment 'Base setup'
 comment 'Processor type and features'
 bool 'Symmetric multi-processing support' CONFIG_SMP
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-64)' CONFIG_NR_CPUS 64
+fi
 bool 'Kernel support for 31 bit emulation' CONFIG_S390_SUPPORT
 if [ "$CONFIG_S390_SUPPORT" = "y" ]; then
   tristate 'Kernel support for 31 bit ELF binaries' CONFIG_BINFMT_ELF32 
diff -Nru a/arch/s390x/defconfig b/arch/s390x/defconfig
--- a/arch/s390x/defconfig	Fri Oct 11 21:22:50 2002
+++ b/arch/s390x/defconfig	Fri Oct 11 21:22:50 2002
@@ -40,6 +40,7 @@
 CONFIG_SMP=y
 CONFIG_S390_SUPPORT=y
 CONFIG_BINFMT_ELF32=y
+CONFIG_NR_CPUS=64
 
 #
 # I/O subsystem configuration
@@ -92,6 +93,7 @@
 #
 # CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_DPT_I2O is not set
@@ -122,6 +124,7 @@
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
diff -Nru a/arch/s390x/kernel/Makefile b/arch/s390x/kernel/Makefile
--- a/arch/s390x/kernel/Makefile	Fri Oct 11 21:22:55 2002
+++ b/arch/s390x/kernel/Makefile	Fri Oct 11 21:22:55 2002
@@ -30,28 +30,3 @@
 # This is just to get the dependencies...
 #
 binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
-
-.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
-
diff -Nru a/arch/s390x/kernel/entry.S b/arch/s390x/kernel/entry.S
--- a/arch/s390x/kernel/entry.S	Fri Oct 11 21:22:54 2002
+++ b/arch/s390x/kernel/entry.S	Fri Oct 11 21:22:54 2002
@@ -17,8 +17,7 @@
 #include <asm/errno.h>
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
-
-#include "asm-offsets.h"
+#include <asm/offsets.h>
 
 /*
  * Stack layout for the system_call stack entry.
@@ -159,16 +158,16 @@
 	.globl  system_call
 system_call:
         SAVE_ALL __LC_SVC_OLD_PSW,1
-	llgh    %r8,__LC_SVC_INT_CODE # get svc number from lowcore
+	llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
         GET_THREAD_INFO           # load pointer to task_struct to R9
 	stosm   48(%r15),0x03     # reenable interrupts
-	larl    %r7,sys_call_table
-        sll     %r8,3
+	larl    %r10,sys_call_table
+        sll     %r7,3
         tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
         jo      sysc_noemu
-	la      %r7,4(%r7)        # use 31 bit emulation system calls
+	la      %r10,4(%r10)      # use 31 bit emulation system calls
 sysc_noemu:
-        lgf     %r8,0(%r8,%r7)    # load address of system call routine
+        lgf     %r8,0(%r7,%r10)   # load address of system call routine
 	tm	__TI_flags+7(%r9),_TIF_SYSCALL_TRACE
         jo      sysc_tracesys
         basr    %r14,%r8          # call sys_xxxx
@@ -226,15 +225,13 @@
 # special linkage: %r12 contains the return address for trace_svc
 #
 sysc_tracesys:
-	lghi    %r0,-ENOSYS
-	stg     %r0,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
+	srl	%r7,3
+	stg     %r7,SP_R2(%r15)
         brasl   %r14,syscall_trace
-	larl	%r6,.Lc256
-	clc	SP_R2(8,%r15),0(%r6)
-	jnl	sysc_tracego
-	lg      %r2,SP_R2(%r15)
-	sllg    %r2,%r2,3           # strace wants to change the syscall
-	lgf	%r8,0(%r2,%r7)
+	lghi	%r7,255           # strace might have changed the
+	ng	%r7,SP_R2(%r15)   #  the system call
+	sll     %r7,3
+	lgf	%r8,0(%r7,%r10)
 sysc_tracego:
 	lmg     %r3,%r6,SP_R3(%r15)
 	lg      %r2,SP_ORIG_R2(%r15)
diff -Nru a/arch/s390x/kernel/ioctl32.c b/arch/s390x/kernel/ioctl32.c
--- a/arch/s390x/kernel/ioctl32.c	Fri Oct 11 21:23:04 2002
+++ b/arch/s390x/kernel/ioctl32.c	Fri Oct 11 21:23:04 2002
@@ -25,9 +25,9 @@
 #include <linux/ext2_fs.h>
 #include <linux/hdreg.h>
 #include <linux/if_bonding.h>
-#include <linux/loop.h>
 #include <linux/blkpg.h>
 #include <linux/blk.h>
+#include <linux/loop.h>
 #include <linux/elevator.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
@@ -214,7 +214,7 @@
 	
 	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 		return -EFAULT;
-	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
 	if (!ifr.ifr_data)
 		return -EAGAIN;
 
diff -Nru a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c
--- a/arch/s390x/kernel/linux32.c	Fri Oct 11 21:22:54 2002
+++ b/arch/s390x/kernel/linux32.c	Fri Oct 11 21:22:54 2002
@@ -1953,9 +1953,7 @@
 	}
 
 	spin_lock_irq(&current->sig->siglock);
-	sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
-	if (!sig)
-		sig = dequeue_signal(&current->pending, &these, &info);
+	sig = dequeue_signal(&these, &info);
 	if (!sig) {
 		/* None ready -- temporarily unblock those we're interested
 		   in so that we'll be awakened when they arrive.  */
@@ -1973,9 +1971,7 @@
 		timeout = schedule_timeout(timeout);
 
 		spin_lock_irq(&current->sig->siglock);
-		sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
-		if (!sig)
-			sig = dequeue_signal(&current->pending, &these, &info);
+		sig = dequeue_signal(&these, &info);
 		current->blocked = current->real_blocked;
 		siginitset(&current->real_blocked, 0);
 		recalc_sigpending();
@@ -3680,7 +3676,7 @@
 	memset(karg, 0, sizeof(*karg));
 	if(__get_user(karg->ca_version, &arg32->ca32_version))
 		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+	karg->ca_umap.ug_ident = (char *)get_zeroed_page(GFP_USER);
 	if(!karg->ca_umap.ug_ident)
 		return -ENOMEM;
 	err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident);
diff -Nru a/arch/s390x/vmlinux.lds.S b/arch/s390x/vmlinux.lds.S
--- a/arch/s390x/vmlinux.lds.S	Fri Oct 11 21:22:55 2002
+++ b/arch/s390x/vmlinux.lds.S	Fri Oct 11 21:22:55 2002
@@ -66,7 +66,7 @@
   __initcall_end = .;
   . = ALIGN(256);
   __per_cpu_start = .;
-  .date.percpu  : { *(.data.percpu) }
+  .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in
--- a/arch/sparc/config.in	Fri Oct 11 21:22:52 2002
+++ b/arch/sparc/config.in	Fri Oct 11 21:22:52 2002
@@ -19,6 +19,10 @@
 
 bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP
 
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
+
 # Identify this as a Sparc32 build
 define_bool CONFIG_SPARC32 y
 
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Fri Oct 11 21:22:59 2002
+++ b/arch/sparc/mm/srmmu.c	Fri Oct 11 21:22:59 2002
@@ -1340,8 +1340,9 @@
 		zones_size[ZONE_HIGHMEM] = npages;
 		zholes_size[ZONE_HIGHMEM] = npages - calc_highpages();
 
-		free_area_init_node(0, NULL, NULL, zones_size,
+		free_area_init_node(0, &contig_page_data, NULL, zones_size,
 				    phys_base >> PAGE_SHIFT, zholes_size);
+		mem_map = contig_page_data.node_mem_map;
 	}
 
 /* P3: easy to fix, todo. Current code is utterly broken, though. */
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Fri Oct 11 21:22:54 2002
+++ b/arch/sparc/mm/sun4c.c	Fri Oct 11 21:22:54 2002
@@ -2066,8 +2066,9 @@
 		zones_size[ZONE_HIGHMEM] = npages;
 		zholes_size[ZONE_HIGHMEM] = npages - calc_highpages();
 
-		free_area_init_node(0, NULL, NULL, zones_size,
+		free_area_init_node(0, &contig_page_data, NULL, zones_size,
 				    phys_base >> PAGE_SHIFT, zholes_size);
+		mem_map = contig_page_data.node_mem_map;
 	}
 
 	cnt = 0;
diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in
--- a/arch/sparc64/config.in	Fri Oct 11 21:22:55 2002
+++ b/arch/sparc64/config.in	Fri Oct 11 21:22:55 2002
@@ -20,6 +20,10 @@
 bool 'Symmetric multi-processing support' CONFIG_SMP
 bool 'Preemptible Kernel' CONFIG_PREEMPT
 
+if [ "$CONFIG_SMP" = "y" ]; then
+   int  'Maximum number of CPUs (2-64)' CONFIG_NR_CPUS 64
+fi
+
 # Identify this as a Sparc64 build
 define_bool CONFIG_SPARC64 y
 
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Fri Oct 11 21:22:55 2002
+++ b/arch/sparc64/defconfig	Fri Oct 11 21:22:55 2002
@@ -59,6 +59,7 @@
 CONFIG_BINFMT_MISC=m
 # CONFIG_SUNOS_EMUL is not set
 CONFIG_SOLARIS_EMUL=m
+CONFIG_NR_CPUS=64
 
 #
 # Parallel port support
diff -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c	Fri Oct 11 21:23:03 2002
+++ b/arch/sparc64/kernel/ioctl32.c	Fri Oct 11 21:23:03 2002
@@ -561,7 +561,7 @@
 	
 	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 		return -EFAULT;
-	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
 	if (!ifr.ifr_data)
 		return -EAGAIN;
 
@@ -626,7 +626,7 @@
 	
 	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 		return -EFAULT;
-	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
 	if (!ifr.ifr_data)
 		return -EAGAIN;
 
@@ -4216,6 +4216,39 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32	_IOR(0x12,106,int)
+#define BLKELVSET_32	_IOW(0x12,107,int)
+#define BLKBSZGET_32	_IOR(0x12,112,int)
+#define BLKBSZSET_32	_IOW(0x12,113,int)
+#define BLKGETSIZE64_32	_IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+			   unsigned long arg)
+{
+	return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
 struct ioctl_trans {
 	unsigned int cmd;
 	unsigned int handler;
@@ -4338,10 +4371,6 @@
 COMPATIBLE_IOCTL(BLKFLSBUF)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
-COMPATIBLE_IOCTL(BLKBSZGET)
-COMPATIBLE_IOCTL(BLKBSZSET)
-COMPATIBLE_IOCTL(BLKGETSIZE64)
-
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
 COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -4881,9 +4910,6 @@
 COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
 COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
 #endif /* DRM */
-/* elevator */
-COMPATIBLE_IOCTL(BLKELVGET)
-COMPATIBLE_IOCTL(BLKELVSET)
 /* Big W */
 /* WIOC_GETSUPPORT not yet implemented -E */
 COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
@@ -5140,6 +5166,14 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget)
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset)
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
 IOCTL_TABLE_END
 
 unsigned int ioctl32_hash_table[1024];
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Fri Oct 11 21:23:00 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Fri Oct 11 21:23:00 2002
@@ -3609,7 +3609,7 @@
 	memset(karg, 0, sizeof(*karg));
 	if(__get_user(karg->ca_version, &arg32->ca32_version))
 		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+	karg->ca_umap.ug_ident = (char *)get_zeroed_page(GFP_USER);
 	if(!karg->ca_umap.ug_ident)
 		return -ENOMEM;
 	err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident);
diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Fri Oct 11 21:22:55 2002
+++ b/arch/sparc64/mm/init.c	Fri Oct 11 21:22:55 2002
@@ -1552,8 +1552,9 @@
 		zones_size[ZONE_DMA] = npages;
 		zholes_size[ZONE_DMA] = npages - pages_avail;
 
-		free_area_init_node(0, NULL, NULL, zones_size,
+		free_area_init_node(0, &contig_page_data, NULL, zones_size,
 				    phys_base >> PAGE_SHIFT, zholes_size);
+		mem_map = contig_page_data.node_mem_map;
 	}
 
 	device_scan();
diff -Nru a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
--- a/arch/sparc64/solaris/misc.c	Fri Oct 11 21:23:04 2002
+++ b/arch/sparc64/solaris/misc.c	Fri Oct 11 21:23:04 2002
@@ -724,6 +724,7 @@
 
 MODULE_AUTHOR("Jakub Jelinek (jj@ultra.linux.cz), Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)");
 MODULE_DESCRIPTION("Solaris binary emulation module");
+MODULE_LICENSE("GPL");
 
 #ifdef __sparc_v9__
 extern u32 tl0_solaris[8];
diff -Nru a/arch/um/Makefile b/arch/um/Makefile
--- a/arch/um/Makefile	Fri Oct 11 21:22:52 2002
+++ b/arch/um/Makefile	Fri Oct 11 21:22:52 2002
@@ -30,16 +30,11 @@
 LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup
 endif
 
-ARCH_SUBDIRS = $(ARCH_DIR)/drivers $(ARCH_DIR)/kernel \
-	$(ARCH_DIR)/sys-$(SUBARCH) $(ARCH_DIR)/os-$(OS)
-
-SUBDIRS += $(ARCH_SUBDIRS)
-
 core-y			+= $(ARCH_DIR)/kernel/		 \
 			   $(ARCH_DIR)/drivers/          \
 			   $(ARCH_DIR)/sys-$(SUBARCH)/
 
-libs-$(CONFIG_PT_PROXY)	+= $(ARCH_DIR)/ptproxy/
+core-$(CONFIG_PT_PROXY)	+= $(ARCH_DIR)/ptproxy/
 
 ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include
 
diff -Nru a/arch/um/config_net.in b/arch/um/config_net.in
--- a/arch/um/config_net.in	Fri Oct 11 21:22:55 2002
+++ b/arch/um/config_net.in	Fri Oct 11 21:22:55 2002
@@ -9,6 +9,7 @@
 dep_bool '  SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET
 dep_bool '  Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET
 dep_bool '  Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET
+dep_bool '  pcap transport' CONFIG_UML_NET_PCAP $CONFIG_UML_NET
 
 # Below are hardware-independent drivers mirrored from
 # drivers/net/Config.in. It would be nice if Linux
diff -Nru a/arch/um/defconfig b/arch/um/defconfig
--- a/arch/um/defconfig	Fri Oct 11 21:23:00 2002
+++ b/arch/um/defconfig	Fri Oct 11 21:23:00 2002
@@ -86,6 +86,7 @@
 CONFIG_UML_NET_SLIP=y
 CONFIG_UML_NET_DAEMON=y
 CONFIG_UML_NET_MCAST=y
+# CONFIG_UML_NET_PCAP is not set
 CONFIG_DUMMY=y
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
diff -Nru a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
--- a/arch/um/drivers/Makefile	Fri Oct 11 21:22:59 2002
+++ b/arch/um/drivers/Makefile	Fri Oct 11 21:22:59 2002
@@ -5,9 +5,23 @@
 
 CHAN_OBJS := chan_kern.o chan_user.o line.o 
 
+# This nonsense is due to kbuild.  In the 2.4 build, I stick -lpcap in 
+# pcap-objs, and that is just included in the link command.  The 2.5 kbuild
+# filters out everything from pcap-objs which are not in the built-in.o
+# dependencies, which are $(obj-y).  So, -lpcap must be in $(obj-y), too.
+# However, make magically expands -lfoo prerequisites into /usr/lib/libfoo.a
+# file names.  This causes the kbuild filtering to filter the -lpcap from
+# pcap-objs, causing the link to fail.
+# So, what this does is figure out by hand (crudely) what file -lpcap really 
+# is and just use it.
+
+PCAP = $(shell for f in echo {/lib,/usr/lib}/libpcap.{a,so}; do \
+       [ -f $$f ] && echo $$f ; done | head -1)
+
 slip-objs := slip_kern.o slip_user.o
 daemon-objs := daemon_kern.o daemon_user.o
 mcast-objs := mcast_kern.o mcast_user.o
+pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
 net-objs := net_kern.o net_user.o
 mconsole-objs := mconsole_kern.o mconsole_user.o
 hostaudio-objs := hostaudio_kern.o hostaudio_user.o
@@ -22,6 +36,7 @@
 obj-$(CONFIG_UML_NET_SLIP) += slip.o
 obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
 obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
+obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
 obj-$(CONFIG_UML_NET) += net.o 
 obj-$(CONFIG_MCONSOLE) += mconsole.o
 obj-$(CONFIG_MMAPPER) += mmapper_kern.o 
@@ -35,12 +50,15 @@
 obj-$(CONFIG_XTERM_CHAN) += xterm.o
 obj-$(CONFIG_UML_WATCHDOG) += harddog.o
 
+CFLAGS_pcap_user.o = -I/usr/include/pcap
+
 obj-y += stdio_console.o $(CHAN_OBJS)
 
 USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
 
-USER_OBJS = $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
+USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
 	null.o pty.o tty.o xterm.o
+USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file))
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
--- a/arch/um/drivers/chan_kern.c	Fri Oct 11 21:22:57 2002
+++ b/arch/um/drivers/chan_kern.c	Fri Oct 11 21:22:57 2002
@@ -395,7 +395,7 @@
 	return(-1);
 }
 
-void chan_interrupt(struct list_head *chans, struct tq_struct *task,
+void chan_interrupt(struct list_head *chans, struct work_struct *task,
 		    struct tty_struct *tty, int irq, void *dev)
 {
 	struct list_head *ele, *next;
@@ -409,7 +409,7 @@
 		do {
 			if((tty != NULL) && 
 			   (tty->flip.count >= TTY_FLIPBUF_SIZE)){
-				queue_task(task, &tq_timer);
+				schedule_work(task);
 				goto out;
 			}
 			err = chan->ops->read(chan->fd, &c, chan->data);
diff -Nru a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
--- a/arch/um/drivers/daemon_kern.c	Fri Oct 11 21:22:51 2002
+++ b/arch/um/drivers/daemon_kern.c	Fri Oct 11 21:22:51 2002
@@ -12,41 +12,36 @@
 #include "net_kern.h"
 #include "net_user.h"
 #include "daemon.h"
-#include "daemon_kern.h"
 
-struct daemon_data daemon_priv[MAX_UML_NETDEV] = {
-	[ 0 ... MAX_UML_NETDEV - 1 ] =
-	{
-		sock_type :	"unix",
-		ctl_sock :	"/tmp/uml.ctl",
-		ctl_addr :	NULL,
-		data_addr :	NULL,
-		local_addr :	NULL,
-		fd :		-1,
-		control :	-1,
-		dev :		NULL,
-	}
+struct daemon_init {
+	char *sock_type;
+	char *ctl_sock;
 };
 
-void daemon_init(struct net_device *dev, int index)
+void daemon_init(struct net_device *dev, void *data)
 {
 	struct uml_net_private *pri;
 	struct daemon_data *dpri;
+	struct daemon_init *init = data;
 
 	init_etherdev(dev, 0);
 	pri = dev->priv;
 	dpri = (struct daemon_data *) pri->user;
-	*dpri = daemon_priv[index];
+	*dpri = ((struct daemon_data)
+		{ sock_type :		init->sock_type,
+		  ctl_sock :		init->ctl_sock,
+		  ctl_addr :		NULL,
+		  data_addr :		NULL,
+		  local_addr :		NULL,
+		  fd :			-1,
+		  control :		-1,
+		  dev :			dev });
+
 	printk("daemon backend (uml_switch version %d) - %s:%s", 
 	       SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
 	printk("\n");
 }
 
-static unsigned short daemon_protocol(struct sk_buff *skb)
-{
-	return(eth_type_trans(skb, skb->dev));
-}
-
 static int daemon_read(int fd, struct sk_buff **skb, 
 		       struct uml_net_private *lp)
 {
@@ -65,47 +60,37 @@
 
 static struct net_kern_info daemon_kern_info = {
 	init:			daemon_init,
-	protocol:		daemon_protocol,
+	protocol:		eth_protocol,
 	read:			daemon_read,
 	write:			daemon_write,
 };
 
-static int daemon_count = 0;
-
-int daemon_setup(char *str, struct uml_net *dev)
+int daemon_setup(char *str, char **mac_out, void *data)
 {
-	int err, n = daemon_count;
+	struct daemon_init *init = data;
+	char *remain;
 
-	dev->user = &daemon_user_info;
-	dev->kern = &daemon_kern_info;
-	dev->private_size = sizeof(struct daemon_data);
-	dev->transport_index = daemon_count++;
-	if(*str != ',') return(0);
-	str++;
- 	if(*str != ','){
- 		err = setup_etheraddr(str, dev->mac);
- 		if(!err) dev->have_mac = 1;
- 	}
-	str = strchr(str, ',');
-	if(str == NULL) return(0);
-	*str++ = '\0';
-	if(*str != ',') daemon_priv[n].sock_type = str;
-	str = strchr(str, ',');
-	if(str == NULL) return(0);
-	*str++ = '\0';
-	if(*str != ',') daemon_priv[n].ctl_sock = str;
-	str = strchr(str, ',');
-	if(str == NULL) return(0);
-	*str = '\0';
-	printk(KERN_WARNING "daemon_setup : Ignoring data socket "
-	       "specification\n");
-	return(0);
+	*init = ((struct daemon_init)
+		{ sock_type :		"unix",
+		  ctl_sock :		"/tmp/uml.ctl" });
+	
+	remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock,
+			       NULL);
+	if(remain != NULL)
+		printk(KERN_WARNING "daemon_setup : Ignoring data socket "
+		       "specification\n");
+	
+	return(1);
 }
 
 static struct transport daemon_transport = {
-	list :	LIST_HEAD_INIT(daemon_transport.list),
-	name :	"daemon",
-	setup : daemon_setup
+	list :		LIST_HEAD_INIT(daemon_transport.list),
+	name :		"daemon",
+	setup : 	daemon_setup,
+	user :		&daemon_user_info,
+	kern :		&daemon_kern_info,
+	private_size :	sizeof(struct daemon_data),
+	setup_size :	sizeof(struct daemon_init),
 };
 
 static int register_daemon(void)
@@ -115,6 +100,7 @@
 }
 
 __initcall(register_daemon);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -Nru a/arch/um/drivers/daemon_kern.h b/arch/um/drivers/daemon_kern.h
--- a/arch/um/drivers/daemon_kern.h	Fri Oct 11 21:23:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-#ifndef __UM_DAEMON_KERN_H
-#define __UM_DAEMON_KERN_H
-
-#include "net_kern.h"
-
-extern int daemon_setup(char *arg, struct uml_net *dev);
-
-#endif
diff -Nru a/arch/um/drivers/line.c b/arch/um/drivers/line.c
--- a/arch/um/drivers/line.c	Fri Oct 11 21:23:03 2002
+++ b/arch/um/drivers/line.c	Fri Oct 11 21:23:03 2002
@@ -215,7 +215,7 @@
 			if(err) goto out;
 		}
 		enable_chan(&line->chan_list, line);
-		INIT_TQUEUE(&line->task, line_timer_cb, line);
+		INIT_WORK(&line->task, line_timer_cb, line);
 	}
 
 	if(!line->sigio){
diff -Nru a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
--- a/arch/um/drivers/mcast.h	Fri Oct 11 21:22:56 2002
+++ b/arch/um/drivers/mcast.h	Fri Oct 11 21:22:56 2002
@@ -10,8 +10,6 @@
 	unsigned short port;
 	void *mcast_addr;
 	int ttl;
-	unsigned char hwaddr[ETH_ADDR_LEN];
-	int hw_setup;
 	void *dev;
 };
 
diff -Nru a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
--- a/arch/um/drivers/mcast_kern.c	Fri Oct 11 21:22:51 2002
+++ b/arch/um/drivers/mcast_kern.c	Fri Oct 11 21:22:51 2002
@@ -19,26 +19,28 @@
 #include "net_kern.h"
 #include "net_user.h"
 #include "mcast.h"
-#include "mcast_kern.h"
 
-struct mcast_data mcast_priv[MAX_UML_NETDEV] = {
-	[ 0 ... MAX_UML_NETDEV - 1 ] =
-	{
-		addr:		"239.192.168.1",
-		port:		1102,
-		ttl:		1,
-	}
+struct mcast_init {
+	char *addr;
+	int port;
+	int ttl;
 };
 
-void mcast_init(struct net_device *dev, int index)
+void mcast_init(struct net_device *dev, void *data)
 {
 	struct uml_net_private *pri;
 	struct mcast_data *dpri;
+	struct mcast_init *init = data;
 
 	init_etherdev(dev, 0);
 	pri = dev->priv;
 	dpri = (struct mcast_data *) pri->user;
-	*dpri = mcast_priv[index];
+	*dpri = ((struct mcast_data)
+		{ addr :	init->addr,
+		  port :	init->port,
+		  ttl :		init->ttl,
+		  mcast_addr :	NULL,
+		  dev :		dev });
 	printk("mcast backend ");
 	printk("multicast adddress: %s:%u, TTL:%u ",
 	       dpri->addr, dpri->port, dpri->ttl);
@@ -46,11 +48,6 @@
 	printk("\n");
 }
 
-static unsigned short mcast_protocol(struct sk_buff *skb)
-{
-	return eth_type_trans(skb, skb->dev);
-}
-
 static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
 {
 	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
@@ -68,71 +65,64 @@
 
 static struct net_kern_info mcast_kern_info = {
 	init:			mcast_init,
-	protocol:		mcast_protocol,
+	protocol:		eth_protocol,
 	read:			mcast_read,
 	write:			mcast_write,
 };
 
-static int mcast_count = 0;
-
-int mcast_setup(char *str, struct uml_net *dev)
+int mcast_setup(char *str, char **mac_out, void *data)
 {
-	int err, n = mcast_count;
-	int num = 0;
-	char *p1, *p2;
-
-	dev->user = &mcast_user_info;
-	dev->kern = &mcast_kern_info;
-	dev->private_size = sizeof(struct mcast_data);
-	dev->transport_index = mcast_count++;
-
-	/* somewhat more sophisticated parser, needed for in_aton */
-
-	p1 = str;
-	if (*str == ',')
-		p1++;
-	while (p1 && *p1) {
-		if ((p2 = strchr(p1, ',')))
-			*p2++ = '\0';
-		if (strlen(p1) > 0) {
-			switch (num) {
-			case 0:
-				/* First argument: Ethernet address */
-				err = setup_etheraddr(p1, dev->mac);
-				if (!err) 
-					dev->have_mac = 1;
-				break;
-			case 1:
-				/* Second argument: Multicast group */
-				mcast_priv[n].addr = p1;
-				break;
-			case 2:
-				/* Third argument: Port number */
-				mcast_priv[n].port = 
-					htons(simple_strtoul(p1, NULL, 10));
-				break;
-			case 3:
-				/* Fourth argument: TTL */
-				mcast_priv[n].ttl = 
-						simple_strtoul(p1, NULL, 10);
-				break;
-			}
+	struct mcast_init *init = data;
+	char *port_str = NULL, *ttl_str = NULL, *remain;
+	char *last;
+	int n;
+
+	*init = ((struct mcast_init)
+		{ addr :	"239.192.168.1",
+		  port :	1102,
+		  ttl :		1 });
+
+	remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
+			       NULL);
+	if(remain != NULL){
+		printk(KERN_ERR "mcast_setup - Extra garbage on "
+		       "specification : '%s'\n", remain);
+		return(0);
+	}
+	
+	if(port_str != NULL){
+		n = simple_strtoul(port_str, &last, 10);
+		if(*last != '\0'){
+			printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", 
+			       port_str);
+			return(0);
 		}
-		p1 = p2;
-		num++;
+		init->port = htons(n);
 	}
 
-	printk(KERN_INFO "Configured mcast device: %s:%u-%u\n",
-		mcast_priv[n].addr, mcast_priv[n].port,
-		mcast_priv[n].ttl);
+	if(ttl_str != NULL){
+		init->ttl = simple_strtoul(ttl_str, &last, 10);
+		if(*last != '\0'){
+			printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", 
+			       ttl_str);
+			return(0);
+		}
+	}
+
+	printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
+	       init->port, init->ttl);
 
-	return(0);
+	return(1);
 }
 
 static struct transport mcast_transport = {
-	list :	LIST_HEAD_INIT(mcast_transport.list),
-	name :	"mcast",
-	setup : mcast_setup
+	list :		LIST_HEAD_INIT(mcast_transport.list),
+	name :		"mcast",
+	setup : 	mcast_setup,
+	user :		&mcast_user_info,
+	kern :		&mcast_kern_info,
+	private_size :	sizeof(struct mcast_data),
+	setup_size :	sizeof(struct mcast_init),
 };
 
 static int register_mcast(void)
@@ -142,6 +132,7 @@
 }
 
 __initcall(register_mcast);
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -Nru a/arch/um/drivers/mcast_kern.h b/arch/um/drivers/mcast_kern.h
--- a/arch/um/drivers/mcast_kern.h	Fri Oct 11 21:23:04 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-#ifndef __UM_MCAST_KERN_H
-#define __UM_MCAST_KERN_H
-
-#include "net_kern.h"
-
-extern int mcast_setup(char *arg, struct uml_net *dev);
-
-#endif
diff -Nru a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
--- a/arch/um/drivers/mconsole_kern.c	Fri Oct 11 21:22:51 2002
+++ b/arch/um/drivers/mconsole_kern.c	Fri Oct 11 21:22:51 2002
@@ -13,7 +13,7 @@
 #include "linux/ctype.h"
 #include "linux/interrupt.h"
 #include "linux/sysrq.h"
-#include "linux/tqueue.h"
+#include "linux/workqueue.h"
 #include "linux/module.h"
 #include "linux/proc_fs.h"
 #include "asm/irq.h"
@@ -42,7 +42,7 @@
 
 LIST_HEAD(mc_requests);
 
-void mc_task_proc(void *unused)
+void mc_work_proc(void *unused)
 {
 	struct mconsole_entry *req;
 	unsigned long flags;
@@ -60,10 +60,7 @@
 	} while(!done);
 }
 
-struct tq_struct mconsole_task = {
-	routine:	mc_task_proc,
-	data: 		NULL
-};
+DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
 
 void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -84,7 +81,7 @@
 			}
 		}
 	}
-	if(!list_empty(&mc_requests)) schedule_task(&mconsole_task);
+	if(!list_empty(&mc_requests)) schedule_work(&mconsole_work);
 	reactivate_fd(fd, MCONSOLE_IRQ);
 }
 
diff -Nru a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
--- a/arch/um/drivers/net_kern.c	Fri Oct 11 21:22:58 2002
+++ b/arch/um/drivers/net_kern.c	Fri Oct 11 21:22:58 2002
@@ -29,16 +29,6 @@
 
 LIST_HEAD(opened);
 
-struct uml_net devices[MAX_UML_NETDEV] = {
-	[ 0 ... MAX_UML_NETDEV - 1 ] = 
-	{
-		dev:		NULL,
-		user:		NULL,
-		kern:		NULL,
-		private_size:	0,
-	}
-};
-
 static int uml_net_rx(struct net_device *dev)
 {
 	struct uml_net_private *lp = dev->priv;
@@ -255,22 +245,38 @@
 #endif
 }
 
-static int eth_configure(struct uml_net *device, int n)
+static struct list_head devices = LIST_HEAD_INIT(devices);
+
+static int eth_configure(int n, void *init, char *mac,
+			 struct transport *transport)
 {
+	struct uml_net *device;
 	struct net_device *dev;
 	struct uml_net_private *lp;
-	int save, err;
+	int save, err, size;
+
+	device = kmalloc(sizeof(*device), GFP_KERNEL);
+	if(device == NULL){
+		printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
+		return(1);
+	}
+
+	list_add(&device->list, &devices);
+	device->index = n;
 
-	device->private_size += sizeof(struct uml_net_private) + 
+	size = transport->private_size + sizeof(struct uml_net_private) + 
 		sizeof(((struct uml_net_private *) 0)->user);
 
+	if(setup_etheraddr(mac, device->mac))
+		device->have_mac = 1;
+
 	printk(KERN_INFO "Netdevice %d ", n);
 	if(device->have_mac) printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
 				    device->mac[0], device->mac[1], 
 				    device->mac[2], device->mac[3], 
 				    device->mac[4], device->mac[5]);
 	printk(": ");
-	dev = kmalloc(sizeof(*dev) + device->private_size, GFP_KERNEL);
+	dev = kmalloc(sizeof(*dev) + size, GFP_KERNEL);
 	if(dev == NULL){
 		printk(KERN_ERR "eth_configure: failed to allocate device\n");
 		return(1);
@@ -279,14 +285,9 @@
 	dev->priv = (void *) &dev[1];
 	device->dev = dev;
 
-	(*device->kern->init)(dev, device->transport_index);
-	rtnl_lock();
-	err = register_netdevice(dev);
-	rtnl_unlock();
-	if(err)
-		return(1);
+	(*transport->kern->init)(dev, init);
 
-	dev->mtu = device->user->max_packet;
+	dev->mtu = transport->user->max_packet;
 	dev->open = uml_net_open;
 	dev->hard_start_xmit = uml_net_start_xmit;
 	dev->stop = uml_net_close;
@@ -298,7 +299,38 @@
 	dev->do_ioctl = uml_net_ioctl;
 	dev->watchdog_timeo = (HZ >> 1);
 	dev->irq = UM_ETH_IRQ;
+	dev->init = NULL;
+	dev->master = NULL;
+	dev->neigh_setup = NULL;
+	dev->owner = NULL;
+	dev->state = 0;
+	dev->next_sched = 0;
+	dev->get_wireless_stats = 0;
+	dev->wireless_handlers = 0;
+	dev->gflags = 0;
+	dev->mc_list = NULL;
+	dev->mc_count = 0;
+	dev->promiscuity = 0;
+	dev->atalk_ptr = NULL;
+	dev->ip_ptr = NULL;
+	dev->dn_ptr = NULL;
+	dev->ip6_ptr = NULL;
+	dev->ec_ptr = NULL;
+	atomic_set(&dev->refcnt, 0);
+	dev->features = 0;
+	dev->uninit = NULL;
+	dev->destructor = NULL;
+	dev->set_config = NULL;
+	dev->accept_fastpath = 0;
+	dev->br_port = 0;
+ 	dev->mem_start = 0;
+ 	dev->mem_end = 0;
 
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if(err)
+		return(1);
 	lp = dev->priv;
 
 	/* lp.user is the first four bytes of the transport data, which
@@ -314,28 +346,41 @@
 		  fd :			-1,
 		  mac :			{ 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
 		  have_mac :		device->have_mac,
-		  protocol :		device->kern->protocol,
-		  open :		device->user->open,
-		  close :		device->user->close,
-		  remove :		device->user->remove,
-		  read :		device->kern->read,
-		  write :		device->kern->write,
-		  add_address :		device->user->add_address,
-		  delete_address : 	device->user->delete_address,
-		  set_mtu :		device->user->set_mtu,
+		  protocol :		transport->kern->protocol,
+		  open :		transport->user->open,
+		  close :		transport->user->close,
+		  remove :		transport->user->remove,
+		  read :		transport->kern->read,
+		  write :		transport->kern->write,
+		  add_address :		transport->user->add_address,
+		  delete_address : 	transport->user->delete_address,
+		  set_mtu :		transport->user->set_mtu,
 		  user : 		{ save } });
 	init_timer(&lp->tl);
 	lp->tl.function = uml_net_user_timer_expire;
 	memset(&lp->stats, 0, sizeof(lp->stats));
 	if(lp->have_mac) memcpy(lp->mac, device->mac, sizeof(lp->mac));
 
-	if(device->user->init) 
-		(*device->user->init)(&lp->user, dev);
+	if(transport->user->init) 
+		(*transport->user->init)(&lp->user, dev);
 	if(device->have_mac)
 		set_ether_mac(dev, device->mac);
 	return(0);
 }
 
+static struct uml_net *find_device(int n)
+{
+	struct uml_net *device;
+	struct list_head *ele;
+
+	list_for_each(ele, &devices){
+		device = list_entry(ele, struct uml_net, list);
+		if(device->index == n)
+			return(device);
+	}
+	return(NULL);
+}
+
 static int eth_parse(char *str, int *index_out, char **str_out)
 {
 	char *end;
@@ -346,8 +391,8 @@
 		printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
 		return(1);
 	}
-	if((n < 0) || (n > sizeof(devices)/sizeof(devices[0]))){
-		printk(KERN_ERR "eth_setup: device %d out of range\n", n);
+	if(n < 0){
+		printk(KERN_ERR "eth_setup: device %d is negative\n", n);
 		return(1);
 	}
 	str = end;
@@ -357,7 +402,7 @@
 		return(1);
 	}
 	str++;
-	if(devices[n].dev != NULL){
+	if(find_device(n)){
 		printk(KERN_ERR "eth_setup: Device %d already configured\n",
 		       n);
 		return(1);
@@ -377,24 +422,54 @@
 
 struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
 
+static int check_transport(struct transport *transport, char *eth, int n,
+			   void **init_out, char **mac_out)
+{
+	int len;
+
+	len = strlen(transport->name);
+	if(strncmp(eth, transport->name, len))
+		return(0);
+
+	eth += len;
+	if(*eth == ',')
+		eth++;
+	else if(*eth != '\0')
+		return(0);
+
+	*init_out = kmalloc(transport->setup_size, GFP_KERNEL);
+	if(*init_out == NULL)
+		return(1);
+
+	if(!transport->setup(eth, mac_out, *init_out)){
+		kfree(*init_out);
+		*init_out = NULL;
+	}
+	return(1);
+}
+
 void register_transport(struct transport *new)
 {
 	struct list_head *ele, *next;
 	struct eth_init *eth;
-	char *str;
-	int err;
+	void *init;
+	char *mac = NULL;
+	int match;
 
 	list_add(&new->list, &transports);
 
 	list_for_each_safe(ele, next, &eth_cmd_line){
 		eth = list_entry(ele, struct eth_init, list);
-		if(!strncmp(eth->init, new->name, strlen(new->name))){
-			str = eth->init + strlen(new->name);
-			err = new->setup(str, &devices[eth->index]);
-			if(!err) eth_configure(&devices[eth->index], 
-					       eth->index);
-			list_del(&eth->list);
+		match = check_transport(new, eth->init, eth->index, &init,
+					&mac);
+		if(!match)
+			continue;
+		else if(init != NULL){
+			eth_configure(eth->index, init, mac, new);
+			kfree(init);
 		}
+		list_del(&eth->list);
+		return;
 	}
 }
 
@@ -402,16 +477,20 @@
 {
 	struct list_head *ele;
 	struct transport *transport;
+	void *init;
+	char *mac = NULL;
 
 	list_for_each(ele, &transports){
 		transport = list_entry(ele, struct transport, list);
-		if(!strncmp(str, transport->name, strlen(transport->name))){
-			str += strlen(transport->name);
-			return(transport->setup(str, &devices[index]));
+	        if(!check_transport(transport, str, index, &init, &mac))
+			continue;
+		if(init != NULL){
+			eth_configure(index, init, mac, transport);
+			kfree(init);
 		}
+		return(1);
 	}
-
-	return(-1);
+	return(0);
 }
 
 static int eth_setup(char *str)
@@ -446,13 +525,12 @@
 {
 	struct list_head *ele, *next;
 	struct eth_init *eth;
-	int err;
 
 	list_for_each_safe(ele, next, &eth_cmd_line){
 		eth = list_entry(ele, struct eth_init, list);
-		err = eth_setup_common(eth->init, eth->index);
-		if(!err) eth_configure(&devices[eth->index], eth->index);
-		if(err >= 0) list_del(&eth->list);
+
+		if(eth_setup_common(eth->init, eth->index))
+			list_del(&eth->list);
 	}
 	
 	return(1);
@@ -462,7 +540,7 @@
 
 static int net_config(char *str)
 {
-	int err, n;
+	int n, err;
 
 	err = eth_parse(str, &n, &str);
 	if(err) return(err);
@@ -470,32 +548,38 @@
 	str = uml_strdup(str);
 	if(str == NULL){
 		printk(KERN_ERR "net_config failed to strdup string\n");
-		return(1);
+		return(-1);
 	}
-	err = eth_setup_common(str, n);
-	if(err){
+	err = !eth_setup_common(str, n);
+	if(err) 
 		kfree(str);
-		return(err);
-	}
-	err = eth_configure(&devices[n], n);
 	return(err);
 }
 
 static int net_remove(char *str)
 {
+	struct uml_net *device;
 	struct net_device *dev;
 	struct uml_net_private *lp;
+	char *end;
 	int n;
 
-	if(!isdigit(*str)) return(-1);
-	n = *str - '0';
-	if(devices[n].dev == NULL) return(0);
-	dev = devices[n].dev;
+	n = simple_strtoul(str, &end, 0);
+	if(*end != '\0')
+		return(-1);
+
+	device = find_device(n);
+	if(device == NULL)
+		return(0);
+
+	dev = device->dev;
 	lp = dev->priv;
 	if(lp->fd > 0) return(-1);
 	if(lp->remove != NULL) (*lp->remove)(&lp->user);
 	unregister_netdev(dev);
-	devices[n].dev = NULL;
+
+	list_del(&device->list);
+	kfree(device);
 	return(0);
 }
 
@@ -596,6 +680,8 @@
 	char *end;
 	int i;
 
+	if(str == NULL)
+		return(0);
 	for(i=0;i<6;i++){
 		addr[i] = simple_strtoul(str, &end, 16);
 		if((end == str) ||
@@ -603,7 +689,7 @@
 			printk(KERN_ERR 
 			       "setup_etheraddr: failed to parse '%s' "
 			       "as an ethernet address\n", str);
-			return(-1);
+			return(0);
 		}
 		str = end + 1;
 	}
@@ -611,9 +697,9 @@
 		printk(KERN_ERR 
 		       "Attempt to assign a broadcast ethernet address to a "
 		       "device disallowed\n");
-		return(-1);
+		return(0);
 	}
-	return(0);
+	return(1);
 }
 
 void dev_ip_addr(void *d, char *buf, char *bin_buf)
@@ -684,6 +770,24 @@
 	}
 }
 
+int dev_netmask(void *d, void *m)
+{
+	struct net_device *dev = d;
+	struct in_device *ip = dev->ip_ptr;
+	struct in_ifaddr *in;
+	__u32 *mask_out = m;
+
+	if(ip == NULL) 
+		return(1);
+
+	in = ip->ifa_list;
+	if(in == NULL) 
+		return(1);
+
+	*mask_out = in->ifa_mask;
+	return(0);
+}
+
 void *get_output_buffer(int *len_out)
 {
 	void *ret;
@@ -699,30 +803,24 @@
 	free_pages((unsigned long) buffer, 0);
 }
 
-int tap_setup_common(char *str, char *type, char **dev_name, char *mac, 
-		     int *have_mac, char **gate_addr)
+int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, 
+		     char **gate_addr)
 {
-	int err;
+	char *remain;
 
-	if(*str != ','){
-		printk(KERN_ERR 
-		       "ethertap_setup: expected ',' after '%s'\n", type);
+	remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL);
+	if(remain != NULL){
+		printk("tap_setup_common - Extra garbage on specification : "
+		       "'%s'\n", remain);
 		return(1);
 	}
-	str++;
-	if(*str != ',') *dev_name = str;
-	str = strchr(str, ',');
-	if(str == NULL) return(0);
-	*str++ = '\0';
-	if(*str != ','){
-		err = setup_etheraddr(str, mac);
-		if(!err) *have_mac = 1;
-	}
-	str = strchr(str, ',');
-	if(str == NULL) return(0);
-	*str++ = '\0';
-	if(*str != '\0') *gate_addr = str;
+
 	return(0);
+}
+
+unsigned short eth_protocol(struct sk_buff *skb)
+{
+	return(eth_type_trans(skb, skb->dev));
 }
 
 /*
diff -Nru a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
--- a/arch/um/drivers/net_user.c	Fri Oct 11 21:22:54 2002
+++ b/arch/um/drivers/net_user.c	Fri Oct 11 21:22:54 2002
@@ -4,6 +4,7 @@
  */
 
 #include <stddef.h>
+#include <stdarg.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <errno.h>
@@ -218,6 +219,27 @@
 void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
 {
 	change(arg, "del", addr, netmask);
+}
+
+char *split_if_spec(char *str, ...)
+{
+	char **arg, *end;
+	va_list ap;
+
+	va_start(ap, str);
+	while((arg = va_arg(ap, char **)) != NULL){
+		if(*str == '\0')
+			return(NULL);
+		end = strchr(str, ',');
+		if(end != str)
+			*arg = str;
+		if(end == NULL)
+			return(NULL);
+		*end++ = '\0';
+		str = end;
+	}
+	va_end(ap);
+	return(str);
 }
 
 /*
diff -Nru a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/pcap_kern.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
+ * Licensed under the GPL.
+ */
+
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "pcap_user.h"
+
+struct pcap_init {
+	char *host_if;
+	int promisc;
+	int optimize;
+	char *filter;
+};
+
+void pcap_init(struct net_device *dev, void *data)
+{
+	struct uml_net_private *pri;
+	struct pcap_data *ppri;
+	struct pcap_init *init = data;
+
+	init_etherdev(dev, 0);
+	pri = dev->priv;
+	ppri = (struct pcap_data *) pri->user;
+	*ppri = ((struct pcap_data)
+		{ host_if :	init->host_if,
+		  promisc :	init->promisc,
+		  optimize :	init->optimize,
+		  filter :	init->filter,
+		  compiled :	NULL,
+		  pcap :	NULL });
+}
+
+static int pcap_read(int fd, struct sk_buff **skb, 
+		       struct uml_net_private *lp)
+{
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+	if(*skb == NULL) return(-ENOMEM);
+	return(pcap_user_read(fd, (*skb)->mac.raw, 
+			      (*skb)->dev->mtu + ETH_HEADER_OTHER,
+			      (struct pcap_data *) &lp->user));
+}
+
+static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+	return(-EPERM);
+}
+
+static struct net_kern_info pcap_kern_info = {
+	init:			pcap_init,
+	protocol:		eth_protocol,
+	read:			pcap_read,
+	write:			pcap_write,
+};
+
+int pcap_setup(char *str, char **mac_out, void *data)
+{
+	struct pcap_init *init = data;
+	char *remain, *host_if = NULL, *options[2] = { NULL, NULL };
+	int i;
+
+	*init = ((struct pcap_init)
+		{ host_if :	"eth0",
+		  promisc :	1,
+		  optimize :	0,
+		  filter :	NULL });
+
+	remain = split_if_spec(str, &host_if, &init->filter, 
+			       &options[0], &options[1], NULL);
+	if(remain != NULL){
+		printk(KERN_ERR "pcap_setup - Extra garbage on "
+		       "specification : '%s'\n", remain);
+		return(0);
+	}
+
+	if(host_if != NULL)
+		init->host_if = host_if;
+
+	for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){
+		if(options[i] == NULL)
+			continue;
+		if(!strcmp(options[i], "promisc"))
+			init->promisc = 1;
+		else if(!strcmp(options[i], "nopromisc"))
+			init->promisc = 0;
+		else if(!strcmp(options[i], "optimize"))
+			init->optimize = 1;
+		else if(!strcmp(options[i], "nooptimize"))
+			init->optimize = 0;
+		else printk("pcap_setup : bad option - '%s'\n", options[i]);
+	}
+
+	return(1);
+}
+
+static struct transport pcap_transport = {
+	list :		LIST_HEAD_INIT(pcap_transport.list),
+	name :		"pcap",
+	setup : 	pcap_setup,
+	user :		&pcap_user_info,
+	kern :		&pcap_kern_info,
+	private_size :	sizeof(struct pcap_data),
+	setup_size :	sizeof(struct pcap_init),
+};
+
+static int register_pcap(void)
+{
+	register_transport(&pcap_transport);
+	return(1);
+}
+
+__initcall(register_pcap);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/pcap_user.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2002 Jeff Dike <jdike@karaya.com>
+ * Licensed under the GPL.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pcap.h>
+#include <asm/types.h>
+#include "net_user.h"
+#include "pcap_user.h"
+#include "user.h"
+
+#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+#define PCAP_FD(p) (*(int *)(p))
+
+static void pcap_user_init(void *data, void *dev)
+{
+	struct pcap_data *pri = data;
+	pcap_t *p;
+	char errors[PCAP_ERRBUF_SIZE];
+
+	p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
+	if(p == NULL){
+		printk("pcap_user_init : pcap_open_live failed - '%s'\n", 
+		       errors);
+		return;
+	}
+
+	pri->dev = dev;
+	pri->pcap = p;
+}
+
+static int pcap_open(void *data)
+{
+	struct pcap_data *pri = data;
+	__u32 netmask;
+	int err;
+
+	if(pri->pcap == NULL)
+		return(-ENODEV);
+
+	if(pri->filter != NULL){
+		err = dev_netmask(pri->dev, &netmask);
+		if(err < 0){
+			printk("pcap_open : dev_netmask failed\n");
+			return(-EIO);
+		}
+
+		pri->compiled = um_kmalloc(sizeof(struct bpf_program));
+		if(pri->compiled == NULL){
+			printk("pcap_open : kmalloc failed\n");
+			return(-ENOMEM);
+		}
+		
+		err = pcap_compile(pri->pcap, 
+				   (struct bpf_program *) pri->compiled, 
+				   pri->filter, pri->optimize, netmask);
+		if(err < 0){
+			printk("pcap_open : pcap_compile failed - '%s'\n", 
+			       pcap_geterr(pri->pcap));
+			return(-EIO);
+		}
+
+		err = pcap_setfilter(pri->pcap, pri->compiled);
+		if(err < 0){
+			printk("pcap_open : pcap_setfilter failed - '%s'\n", 
+			       pcap_geterr(pri->pcap));
+			return(-EIO);
+		}
+	}
+	
+	return(PCAP_FD(pri->pcap));
+}
+
+static void pcap_remove(void *data)
+{
+	struct pcap_data *pri = data;
+
+	if(pri->compiled != NULL)
+		pcap_freecode(pri->compiled);
+
+	pcap_close(pri->pcap);
+}
+
+struct pcap_handler_data {
+	char *buffer;
+	int len;
+};
+
+static void handler(u_char *data, const struct pcap_pkthdr *header, 
+		    const u_char *packet)
+{
+	int len;
+
+	struct pcap_handler_data *hdata = (struct pcap_handler_data *) data;
+
+	len = hdata->len < header->caplen ? hdata->len : header->caplen;
+	memcpy(hdata->buffer, packet, len);
+	hdata->len = len;
+}
+
+int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
+{
+	struct pcap_handler_data hdata = ((struct pcap_handler_data)
+		                          { buffer : 	buffer,
+					    len :	len });
+	int n;
+
+	n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
+	if(n < 0){
+		printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
+		return(-EIO);
+	}
+	else if(n == 0) 
+		return(0);
+	return(hdata.len);
+}
+
+struct net_user_info pcap_user_info = {
+	init:		pcap_user_init,
+	open:		pcap_open,
+	close:	 	NULL,
+	remove:	 	pcap_remove,
+	set_mtu:	NULL,
+	add_address:	NULL,
+	delete_address: NULL,
+	max_packet:	MAX_PACKET - ETH_HEADER_OTHER
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/pcap_user.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,31 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+struct pcap_data {
+	char *host_if;
+	int promisc;
+	int optimize;
+	char *filter;
+	void *compiled;
+	void *pcap;
+	void *dev;
+};
+
+extern struct net_user_info pcap_user_info;
+
+extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
--- a/arch/um/drivers/port_kern.c	Fri Oct 11 21:22:52 2002
+++ b/arch/um/drivers/port_kern.c	Fri Oct 11 21:22:52 2002
@@ -53,7 +53,7 @@
 
  	fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
 	if(fd < 0){
-		printk("os_accept_connection returned %d\n", -fd);
+		printk("os_rcv_fd returned %d\n", -fd);
 		os_close_file(conn->fd);
 	}
 	conn->fd = fd;
diff -Nru a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
--- a/arch/um/drivers/port_user.c	Fri Oct 11 21:23:00 2002
+++ b/arch/um/drivers/port_user.c	Fri Oct 11 21:23:00 2002
@@ -118,7 +118,7 @@
 		goto out;
 	}
   
-	if(listen(fd, 1) < 0){
+	if((listen(fd, 1) < 0) || (os_set_fd_block(fd, 0))){
 		err = -errno;
 		goto out;
 	}
@@ -190,7 +190,8 @@
 			 "/usr/lib/uml/port-helper", NULL };
 	struct port_pre_exec_data data;
 
-	if((new = accept(fd, NULL, 0)) < 0) return(-errno);
+	if((new = os_accept_connection(fd)) < 0)
+		return(-errno);
 
 	err = os_pipe(socket, 0, 0);
 	if(err) goto out_close;
diff -Nru a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
--- a/arch/um/drivers/slip.h	Fri Oct 11 21:22:55 2002
+++ b/arch/um/drivers/slip.h	Fri Oct 11 21:22:55 2002
@@ -9,7 +9,10 @@
 	char *addr;
 	char *gate_addr;
 	int slave;
-	char buf[2 * BUF_SIZE];
+	/* two bytes each for a (pathological) max packet of escaped chars + 
+	 * terminating END char + inital END char
+	 */
+	char buf[2 * BUF_SIZE + 2];
 	int pos;
 	int esc;
 };
diff -Nru a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
--- a/arch/um/drivers/slip_kern.c	Fri Oct 11 21:22:55 2002
+++ b/arch/um/drivers/slip_kern.c	Fri Oct 11 21:22:55 2002
@@ -7,28 +7,29 @@
 #include "net_user.h"
 #include "kern.h"
 #include "slip.h"
-#include "slip_kern.h"
 
-struct slip_data slip_priv[MAX_UML_NETDEV] = {
-	[ 0 ... MAX_UML_NETDEV - 1 ] =
-	{
-		addr:		NULL,
-		gate_addr:	NULL,
-		slave:		-1,
-		buf: 		{ 0 },
-		pos:		0,
-		esc:		0,
-	}
+struct slip_init {
+	char *gate_addr;
 };
 
-void slip_init(struct net_device *dev, int index)
+void slip_init(struct net_device *dev, void *data)
 {
 	struct uml_net_private *private;
 	struct slip_data *spri;
+	struct slip_init *init = data;
 
 	private = dev->priv;
 	spri = (struct slip_data *) private->user;
-	*spri = slip_priv[index];
+	*spri = ((struct slip_data)
+		{ name :	{ '\0' },
+		  addr:		NULL,
+		  gate_addr :	init->gate_addr,
+		  slave : 	0,
+		  buf : 	{ '\0' },
+		  pos :		0,
+		  esc :		0,
+		  dev :		dev });
+
 	strncpy(dev->name, "umn", IFNAMSIZ);
 	dev->init = NULL;
 	dev->hard_header_len = 0;
@@ -67,26 +68,26 @@
 	write:			slip_write,
 };
 
-static int slip_count = 0;
-
-int slip_setup(char *str, struct uml_net *dev)
+static int slip_setup(char *str, char **mac_out, void *data)
 {
-	int n = slip_count;
+	struct slip_init *init = data;
+
+	*init = ((struct slip_init)
+		{ gate_addr :		NULL });
 
-	dev->user = &slip_user_info;
-	dev->kern = &slip_kern_info;
-	dev->private_size = sizeof(struct slip_data);
-	dev->transport_index = slip_count++;
-	if(*str != ',') return(0);
-	str++;
-	if(str[0] != '\0') slip_priv[n].gate_addr = str;
-	return(0);
+	if(str[0] != '\0') 
+		init->gate_addr = str;
+	return(1);
 }
 
 static struct transport slip_transport = {
-	list :	LIST_HEAD_INIT(slip_transport.list),
-	name :	"slip",
-	setup : slip_setup
+	list :		LIST_HEAD_INIT(slip_transport.list),
+	name :		"slip",
+	setup : 	slip_setup,
+	user :		&slip_user_info,
+	kern :		&slip_kern_info,
+	private_size :	sizeof(struct slip_data),
+	setup_size :	sizeof(struct slip_init),
 };
 
 static int register_slip(void)
diff -Nru a/arch/um/drivers/slip_kern.h b/arch/um/drivers/slip_kern.h
--- a/arch/um/drivers/slip_kern.h	Fri Oct 11 21:23:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-#ifndef __UM_SLIP_KERN_H
-#define __UM_SLIP_KERN_H
-
-#include "net_kern.h"
-
-extern int slip_setup(char *arg, struct uml_net *dev);
-
-#endif
diff -Nru a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
--- a/arch/um/drivers/ubd_kern.c	Fri Oct 11 21:22:58 2002
+++ b/arch/um/drivers/ubd_kern.c	Fri Oct 11 21:22:58 2002
@@ -56,10 +56,10 @@
 #define DEVICE_NR(n) (minor(n) >> UBD_SHIFT)
 
 static struct block_device_operations ubd_blops = {
-        open:		ubd_open,
-        release:	ubd_release,
-        ioctl:		ubd_ioctl,
-        revalidate:	ubd_revalidate,
+        .open =		ubd_open,
+        .release =	ubd_release,
+        .ioctl =	ubd_ioctl,
+        .revalidate =	ubd_revalidate,
 };
 
 static request_queue_t *ubd_queue;
@@ -69,9 +69,9 @@
 static struct gendisk *fake_gendisk[MAX_DEV];
  
 #ifdef CONFIG_BLK_DEV_UBD_SYNC
-#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 1, c : 0 })
+#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0 })
 #else
-#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 0, c : 0 })
+#define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0 })
 #endif
 
 static struct openflags global_openflags = OPEN_FLAGS;
@@ -99,24 +99,24 @@
 };
 
 #define DEFAULT_COW { \
-	file:			NULL, \
-        fd:			-1, \
-        bitmap:			NULL, \
-	bitmap_offset:		0, \
-        data_offset:		0, \
+	.file =			NULL, \
+        .fd =			-1, \
+        .bitmap =		NULL, \
+	.bitmap_offset =	0, \
+        .data_offset =		0, \
 }
 
 #define DEFAULT_UBD { \
-	file: 			NULL, \
-	is_dir:			0, \
-	count:			0, \
-	fd:			-1, \
-	size:			-1, \
-	boot_openflags:		OPEN_FLAGS, \
-	openflags:		OPEN_FLAGS, \
-	real:			NULL, \
-	fake:			NULL, \
-        cow:			DEFAULT_COW, \
+	.file = 		NULL, \
+	.is_dir =		0, \
+	.count =		0, \
+	.fd =			-1, \
+	.size =			-1, \
+	.boot_openflags =	OPEN_FLAGS, \
+	.openflags =		OPEN_FLAGS, \
+	.real =			NULL, \
+	.fake =			NULL, \
+        .cow =			DEFAULT_COW, \
 }
 
 struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
@@ -131,9 +131,9 @@
 __initcall(ubd0_init);
 
 static struct hd_driveid ubd_id = {
-        cyls:		0,
-	heads:		128,
-	sectors:	32,
+        .cyls =		0,
+	.heads =	128,
+	.sectors =	32,
 };
 
 static int fake_ide = 0;
@@ -199,7 +199,7 @@
 {
 	struct openflags flags = global_openflags;
 	char *backing_file;
-	int i, n;
+	int n;
 
 	if(index_out) *index_out = -1;
 	n = *str++;
@@ -398,7 +398,7 @@
  	devfs_handle_t real, fake;
 	char name[sizeof("nnnnnn\0")];
 	struct ubd *dev = &ubd_dev[n];
-	struct gendisk *disk, *fake_disk;
+	struct gendisk *disk, *fake_disk = NULL;
 	u64 size;
 
 	if (!dev->file)
@@ -410,7 +410,7 @@
 	disk->major = MAJOR_NR;
 	disk->first_minor = n << UBD_SHIFT;
 	disk->minor_shift = UBD_SHIFT;
-	disk->fops = &ubd_fops;
+	disk->fops = &ubd_blops;
 	if (fakehd_set)
 		sprintf(disk->disk_name, "hd%c", n + 'a');
 	else
@@ -425,7 +425,7 @@
 		fake_disk->major = fake_major;
 		fake_disk->first_minor = n << UBD_SHIFT;
 		fake_disk->minor_shift = UBD_SHIFT;
-		fake_disk->fops = &ubd_fops;
+		fake_disk->fops = &ubd_blops;
 		sprintf(fake_disk->disk_name, "ubd%d", n);
 		fake_gendisk[n] = fake_disk;
 	}
@@ -434,7 +434,8 @@
 
 	if (!dev->is_dir && ubd_file_size(dev, &size) == 0) {
 		set_capacity(disk, size/512);
-		set_capacity(fake_disk, size/512);
+		if (fake_major)
+			set_capacity(fake_disk, size/512);
 	}
  
 	sprintf(name, "%d", n);
@@ -541,7 +542,7 @@
 	}
 	ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
 	INIT_QUEUE(ubd_queue, do_ubd_request, &ubd_lock);
-	INIT_ELV(ubd_queue, &ubd_queue->elevator);
+	elevator_init(ubd_queue, &elevator_noop);
 	if(fake_major != 0){
 		char name[sizeof("ubd_nnn\0")];
 
@@ -880,12 +881,13 @@
 			return(-EFAULT);
 		return(0);
 	}
+	return(-EINVAL);
 }
 
 static int ubd_revalidate(kdev_t rdev)
 {
 	__u64 size;
-	int n, offset, err;
+	int n, err;
 	struct ubd *dev;
 
 	n = minor(rdev) >> UBD_SHIFT;
diff -Nru a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h
--- a/arch/um/include/2_5compat.h	Fri Oct 11 21:22:58 2002
+++ b/arch/um/include/2_5compat.h	Fri Oct 11 21:22:58 2002
@@ -22,9 +22,6 @@
 
 #define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request, lock)
 
-#define ELV_NOOP elevator_noop
-#define INIT_ELV(queue, elv) elevator_init(queue, elv, ELV_NOOP)
-
 #define INIT_HARDSECT(arr, maj, sizes)
 
 #define SET_PRI(task) do ; while(0)
diff -Nru a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
--- a/arch/um/include/chan_kern.h	Fri Oct 11 21:22:58 2002
+++ b/arch/um/include/chan_kern.h	Fri Oct 11 21:22:58 2002
@@ -22,7 +22,7 @@
 	void *data;
 };
 
-extern void chan_interrupt(struct list_head *chans, struct tq_struct *task,
+extern void chan_interrupt(struct list_head *chans, struct work_struct *task,
 			   struct tty_struct *tty, int irq, void *dev);
 extern int parse_chan_pair(char *str, struct list_head *chans, int pri, 
 			   int device, struct chan_opts *opts);
diff -Nru a/arch/um/include/kern.h b/arch/um/include/kern.h
--- a/arch/um/include/kern.h	Fri Oct 11 21:23:03 2002
+++ b/arch/um/include/kern.h	Fri Oct 11 21:23:03 2002
@@ -25,6 +25,7 @@
 extern void *malloc(int size);
 extern void perror(char *err);
 extern int kill(int pid, int sig);
+extern int getpid(void);
 extern int getuid(void);
 extern int pause(void);
 extern int write(int, const void *, int);
diff -Nru a/arch/um/include/line.h b/arch/um/include/line.h
--- a/arch/um/include/line.h	Fri Oct 11 21:23:02 2002
+++ b/arch/um/include/line.h	Fri Oct 11 21:23:02 2002
@@ -7,7 +7,7 @@
 #define __LINE_H__
 
 #include "linux/list.h"
-#include "linux/tqueue.h"
+#include "linux/workqueue.h"
 #include "linux/tty.h"
 #include "asm/semaphore.h"
 #include "chan_user.h"
@@ -39,7 +39,7 @@
 	char *head;
 	char *tail;
 	int sigio;
-	struct tq_struct task;
+	struct work_struct task;
 	struct line_driver *driver;
 	int have_irq;
 };
diff -Nru a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
--- a/arch/um/include/net_kern.h	Fri Oct 11 21:23:03 2002
+++ b/arch/um/include/net_kern.h	Fri Oct 11 21:23:03 2002
@@ -6,14 +6,10 @@
 #include "linux/socket.h"
 #include "linux/list.h"
 
-#define MAX_UML_NETDEV (16)
-
 struct uml_net {
+	struct list_head list;
 	struct net_device *dev;
-	struct net_user_info *user;
-	struct net_kern_info *kern;
-	int private_size;
-	int transport_index;
+	int index;
 	unsigned char mac[ETH_ALEN];
 	int have_mac;
 };
@@ -41,7 +37,7 @@
 };
 
 struct net_kern_info {
-	void (*init)(struct net_device *, int);
+	void (*init)(struct net_device *, void *);
 	unsigned short (*protocol)(struct sk_buff *);
 	int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
 	int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
@@ -50,7 +46,11 @@
 struct transport {
 	struct list_head list;
 	char *name;
-	int (*setup)(char *, struct uml_net *);
+	int (*setup)(char *, char **, void *);
+	struct net_user_info *user;
+	struct net_kern_info *kern;
+	int private_size;
+	int setup_size;
 };
 
 extern struct net_device *ether_init(int);
@@ -58,8 +58,9 @@
 extern int setup_etheraddr(char *str, unsigned char *addr);
 extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
 extern int tap_setup_common(char *str, char *type, char **dev_name, 
-			    char *hw_addr, int *hw_setup, char **gate_addr);
+			    char **mac_out, char **gate_addr);
 extern void register_transport(struct transport *new);
+extern unsigned short eth_protocol(struct sk_buff *skb);
 
 #endif
 
diff -Nru a/arch/um/include/net_user.h b/arch/um/include/net_user.h
--- a/arch/um/include/net_user.h	Fri Oct 11 21:23:05 2002
+++ b/arch/um/include/net_user.h	Fri Oct 11 21:23:05 2002
@@ -43,6 +43,10 @@
 extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
 extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
 
+extern char *split_if_spec(char *str, ...);
+
+extern int dev_netmask(void *d, void *m);
+
 #endif
 
 /*
diff -Nru a/arch/um/include/sysdep-ppc/sigcontext.h b/arch/um/include/sysdep-ppc/sigcontext.h
--- a/arch/um/include/sysdep-ppc/sigcontext.h	Fri Oct 11 21:23:03 2002
+++ b/arch/um/include/sysdep-ppc/sigcontext.h	Fri Oct 11 21:23:03 2002
@@ -9,7 +9,7 @@
 #define DSISR_WRITE 0x02000000
 
 #define SC_FAULT_ADDR(sc) ({ \
-		struct sigcontext_struct *_sc = (sc); \
+		struct sigcontext *_sc = (sc); \
 		long retval = -1; \
 		switch (_sc->regs->trap) { \
 		case 0x300: \
@@ -27,7 +27,7 @@
 	})
 
 #define SC_FAULT_WRITE(sc) ({ \
-		struct sigcontext_struct *_sc = (sc); \
+		struct sigcontext *_sc = (sc); \
 		long retval = -1; \
 		switch (_sc->regs->trap) { \
 		case 0x300: \
diff -Nru a/arch/um/include/time_user.h b/arch/um/include/time_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/time_user.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,17 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TIME_USER_H__
+#define __TIME_USER_H__
+
+extern void timer(void);
+extern void get_profile_timer(void);
+extern void disable_profile_timer(void);
+extern void switch_timers(int to_real);
+extern void user_time_init(void);
+extern void set_timers(int set_signal);
+extern void idle_sleep(int secs);
+
+#endif
diff -Nru a/arch/um/include/user_util.h b/arch/um/include/user_util.h
--- a/arch/um/include/user_util.h	Fri Oct 11 21:22:54 2002
+++ b/arch/um/include/user_util.h	Fri Oct 11 21:22:54 2002
@@ -64,10 +64,6 @@
 extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
 			    int clone_flags, int (*tramp)(void *));
 extern void trace_myself(void);
-extern void timer(void);
-extern void get_profile_timer(void);
-extern void disable_profile_timer(void);
-extern void set_timers(int set_signal);
 extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
 extern int input_loop(void);
 extern void continue_execing_proc(int pid);
@@ -81,7 +77,6 @@
 extern void *um_kmalloc(int size);
 extern int raw(int fd, int complain);
 extern int switcheroo(int fd, int prot, void *from, void *to, int size);
-extern void idle_sleep(int secs);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(void);
 extern void add_arg(char *cmd_line, char *arg);
@@ -109,7 +104,6 @@
 extern void write_sigio_workaround(void);
 extern void arch_check_bugs(void);
 extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
-extern void user_time_init(void);
 extern unsigned long pid_pc(int pid);
 extern int arch_fixup(unsigned long address, void *sc_ptr);
 extern void forward_pending_sigio(int target);
diff -Nru a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
--- a/arch/um/kernel/Makefile	Fri Oct 11 21:23:01 2002
+++ b/arch/um/kernel/Makefile	Fri Oct 11 21:23:01 2002
@@ -14,8 +14,9 @@
 # user_syms.o not included here because Rules.make has its own ideas about
 # building anything in export-objs
 
-USER_OBJS = $(filter %_user.o,$(obj-y)) config.o process.o time.o umid.o \
-	user_util.o user_syms.o helper.o tty_log.o
+USER_OBJS := $(filter %_user.o,$(obj-y)) config.o frame.o helper.o process.o \
+	time.o tty_log.o umid.o user_util.o user_syms.o
+USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file))
 
 export-objs := ksyms.o process_kern.o signal_kern.o gprof_syms.o gmon_syms.o
 
@@ -44,19 +45,18 @@
 $(USER_OBJS) : %.o: %.c
 	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
 
-unmap.o: unmap.c
+arch/um/kernel/unmap.o: arch/um/kernel/unmap.c
 	$(CC) $(UNMAP_CFLAGS) -c -o $@ $<
 
-frame.o: frame.c
-	$(CC) $(CFLAGS_$@) -c -o $@ $<
-
-unmap_fin.o : unmap.o
+arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o
 	ld -r -o $@ $< -lc -L/usr/lib
 
 QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
 
-config.c : config.c.in $(TOPDIR)/.config
-	$(PERL) -e $(QUOTE) < config.c.in > $@
+arch/um/kernel/config.c : arch/um/kernel/config.c.in $(TOPDIR)/.config
+	$(PERL) -e $(QUOTE) < arch/um/kernel/config.c.in > $@
+
+arch/um/kernel/config.o : arch/um/kernel/config.c
 
 clean:
 	rm -f config.c
diff -Nru a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
--- a/arch/um/kernel/irq_user.c	Fri Oct 11 21:22:56 2002
+++ b/arch/um/kernel/irq_user.c	Fri Oct 11 21:22:56 2002
@@ -61,7 +61,7 @@
 		for(i = 0; i < pollfds_num; i++){
 			if(pollfds[i].revents != 0){
 				irq_fd->current_events = pollfds[i].revents;
-				pollfds[i].events = 0;
+				pollfds[i].fd = -1;
 			}
 			irq_fd = irq_fd->next;
 		}
@@ -185,7 +185,8 @@
 	while(*prev != NULL){
 		if((*test)(*prev, arg)){
 			struct irq_fd *old_fd = *prev;
-			if(pollfds[i].fd != (*prev)->fd){
+			if((pollfds[i].fd != -1) && 
+			   (pollfds[i].fd != (*prev)->fd)){
 				printk("free_irq_by_cb - mismatch between "
 				       "active_fds and pollfds, fd %d vs %d\n",
 				       (*prev)->fd, pollfds[i].fd);
@@ -250,7 +251,7 @@
 		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
 		return(NULL);
 	}
-	if(pollfds[i].fd != fd){
+	if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
 		printk("find_irq_by_fd - mismatch between active_fds and "
 		       "pollfds, fd %d vs %d, need %d\n", irq->fd, 
 		       pollfds[i].fd, fd);
@@ -283,7 +284,7 @@
 
 	irq = find_irq_by_fd(fd, irqnum, &i);
 	if(irq == NULL) return;
-	pollfds[i].events = irq->events;
+	pollfds[i].fd = irq->fd;
 	maybe_sigio_broken(fd, irq->type);
 }
 
@@ -294,7 +295,7 @@
 
 	irq = find_irq_by_fd(fd, irqnum, &i);
 	if(irq == NULL) return;
-	pollfds[i].events = 0;
+	pollfds[i].fd = -1;
 }
 
 void forward_ipi(int fd, int pid)
diff -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
--- a/arch/um/kernel/mem.c	Fri Oct 11 21:22:55 2002
+++ b/arch/um/kernel/mem.c	Fri Oct 11 21:22:55 2002
@@ -49,7 +49,7 @@
 
 int kmalloc_ok = 0;
 
-#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0))
+#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1)
 struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL };
 #define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1)
 
diff -Nru a/arch/um/kernel/process.c b/arch/um/kernel/process.c
--- a/arch/um/kernel/process.c	Fri Oct 11 21:23:03 2002
+++ b/arch/um/kernel/process.c	Fri Oct 11 21:23:03 2002
@@ -35,6 +35,7 @@
 #include "irq_user.h"
 #include "syscall_user.h"
 #include "ptrace_user.h"
+#include "time_user.h"
 #include "init.h"
 #include "os.h"
 
diff -Nru a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
--- a/arch/um/kernel/process_kern.c	Fri Oct 11 21:22:59 2002
+++ b/arch/um/kernel/process_kern.c	Fri Oct 11 21:22:59 2002
@@ -34,6 +34,7 @@
 #include "init.h"
 #include "irq_user.h"
 #include "mem_user.h"
+#include "time_user.h"
 #include "tlb.h"
 #include "frame_kern.h"
 #include "sigcontext.h"
@@ -233,7 +234,8 @@
 		panic("write of switch_pipe failed, errno = %d", -err);
 
 	reading = 1;
-	if(from->state == TASK_ZOMBIE) os_kill_process(os_getpid());
+	if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD))
+		os_kill_process(os_getpid());
 
 	err = user_read(from->thread.switch_pipe[0], &c, sizeof(c));
 	if(err != sizeof(c))
diff -Nru a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
--- a/arch/um/kernel/signal_kern.c	Fri Oct 11 21:22:59 2002
+++ b/arch/um/kernel/signal_kern.c	Fri Oct 11 21:22:59 2002
@@ -101,12 +101,12 @@
 		ka->sa.sa_handler = SIG_DFL;
 
 	if (!(ka->sa.sa_flags & SA_NODEFER)) {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		sigorsets(&current->blocked, &current->blocked, 
 			  &ka->sa.sa_mask);
 		sigaddset(&current->blocked, signr);
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 	}
 
 	sp = PT_REGS_SP(regs);
@@ -188,11 +188,11 @@
 	sigset_t saveset;
 
 	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
@@ -214,11 +214,11 @@
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	current->blocked = newset;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
@@ -234,13 +234,13 @@
 	void *mask = sp_to_mask(PT_REGS_SP(&regs));
 	int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	copy_from_user(&current->blocked.sig[0], sc_sigmask(sc), 
 		       sizeof(current->blocked.sig[0]));
 	copy_from_user(&current->blocked.sig[1], mask, sig_size);
 	sigdelsetmask(&current->blocked, ~_BLOCKABLE);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	copy_sc_from_user(current->thread.regs.regs.sc, sc,
 			  &signal_frame_sc.arch);
 	return(PT_REGS_SYSCALL_RET(&current->thread.regs));
@@ -252,11 +252,11 @@
 	void *mask = sp_to_rt_mask(PT_REGS_SP(&regs));
 	int sig_size = _NSIG_WORDS * sizeof(unsigned long);
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	copy_from_user(&current->blocked, mask, sig_size);
 	sigdelsetmask(&current->blocked, ~_BLOCKABLE);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	copy_sc_from_user(current->thread.regs.regs.sc, sc,
 			  &signal_frame_sc.arch);
 	return(PT_REGS_SYSCALL_RET(&current->thread.regs));
diff -Nru a/arch/um/kernel/time.c b/arch/um/kernel/time.c
--- a/arch/um/kernel/time.c	Fri Oct 11 21:22:54 2002
+++ b/arch/um/kernel/time.c	Fri Oct 11 21:22:54 2002
@@ -53,6 +53,28 @@
 		panic("setitimer failed - errno = %d\n", errno);
 }
 
+void switch_timers(int to_real)
+{
+	struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+	struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
+							{ 0, 1000000/hz() }});
+	int old, new;
+
+	if(to_real){
+		old = ITIMER_VIRTUAL;
+		new = ITIMER_REAL;
+	}
+	else {
+		old = ITIMER_REAL;
+		new = ITIMER_VIRTUAL;
+	}
+
+	if((setitimer(old, &disable, NULL) < 0) ||
+	   (setitimer(new, &enable, NULL)))
+		printk("switch_timers - setitimer failed, errno = %d\n",
+		       errno);
+}
+
 void idle_timer(void)
 {
 	if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
diff -Nru a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
--- a/arch/um/kernel/time_kern.c	Fri Oct 11 21:23:00 2002
+++ b/arch/um/kernel/time_kern.c	Fri Oct 11 21:23:00 2002
@@ -16,6 +16,7 @@
 #include "asm/current.h"
 #include "kern_util.h"
 #include "user_util.h"
+#include "time_user.h"
 
 u64 jiffies_64;
 
diff -Nru a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
--- a/arch/um/kernel/tlb.c	Fri Oct 11 21:22:54 2002
+++ b/arch/um/kernel/tlb.c	Fri Oct 11 21:22:54 2002
@@ -6,9 +6,9 @@
 #include "linux/sched.h"
 #include "linux/slab.h"
 #include "linux/bootmem.h"
+#include "asm/pgalloc.h"
 #include "asm-generic/tlb.h"
 #include "asm/pgtable.h"
-#include "asm/pgalloc.h"
 #include "asm/a.out.h"
 #include "asm/processor.h"
 #include "asm/mmu_context.h"
@@ -99,7 +99,7 @@
 	int updated = 0, err;
 
 	mm = &init_mm;
-	for(addr = start_vm; addr < end_vm;){
+	for(addr = start; addr < end;){
 		pgd = pgd_offset(mm, addr);
 		pmd = pmd_offset(pgd, addr);
 		if(pmd_present(*pmd)){
diff -Nru a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
--- a/arch/um/kernel/trap_user.c	Fri Oct 11 21:22:58 2002
+++ b/arch/um/kernel/trap_user.c	Fri Oct 11 21:22:58 2002
@@ -34,6 +34,7 @@
 #include "frame_user.h"
 #include "syscall_user.h"
 #include "ptrace_user.h"
+#include "time_user.h"
 #include "task.h"
 #include "os.h"
 
@@ -416,7 +417,7 @@
 
 void segv_handler(int sig, struct uml_pt_regs *regs)
 {
-	struct sigcontext_struct *context = regs->sc;
+	struct sigcontext *context = regs->sc;
 	int index;
 
 	if(regs->is_user && !SEGV_IS_FIXABLE(context)){
@@ -517,7 +518,14 @@
 	user = user_context(SC_SP(&sc));
 	if(!user && !kern_timer_on) return;
 	if(!user && jail_timer_off) return;
+
+	if(sig == SIGALRM)
+		switch_timers(0);
+
 	sig_handler_common(sig, &sc);
+
+	if(sig == SIGALRM)
+		switch_timers(1);
 }
 
 void do_longjmp(void *p)
diff -Nru a/arch/um/os-Linux/drivers/etap_kern.h b/arch/um/os-Linux/drivers/etap_kern.h
--- a/arch/um/os-Linux/drivers/etap_kern.h	Fri Oct 11 21:22:52 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-/* 
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_ETHERTAP_KERN_H
-#define __UM_ETHERTAP_KERN_H
-
-#include "net_kern.h"
-
-extern int ethertap_setup(char *arg, struct uml_net *dev);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -Nru a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
--- a/arch/um/os-Linux/drivers/ethertap_kern.c	Fri Oct 11 21:22:52 2002
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c	Fri Oct 11 21:22:52 2002
@@ -12,42 +12,32 @@
 #include "net_kern.h"
 #include "net_user.h"
 #include "etap.h"
-#include "etap_kern.h"
 
-struct ethertap_setup {
+struct ethertap_init {
 	char *dev_name;
 	char *gate_addr;
 };
 
-struct ethertap_setup ethertap_priv[MAX_UML_NETDEV] = { 
-	[ 0 ... MAX_UML_NETDEV - 1 ] =
-	{
-		dev_name:	NULL,
-		gate_addr:	NULL,
-	}
-};
-
-static void etap_init(struct net_device *dev, int index)
+static void etap_init(struct net_device *dev, void *data)
 {
 	struct uml_net_private *pri;
 	struct ethertap_data *epri;
+	struct ethertap_init *init = data;
 
 	init_etherdev(dev, 0);
 	pri = dev->priv;
 	epri = (struct ethertap_data *) pri->user;
-	epri->dev_name = ethertap_priv[index].dev_name;
-	epri->gate_addr = ethertap_priv[index].gate_addr;
+	*epri = ((struct ethertap_data)
+		{ dev_name :		init->dev_name,
+		  gate_addr :		init->gate_addr,
+		  data_fd :		-1,
+		  control_fd :		-1,
+		  dev :			dev });
+
 	printk("ethertap backend - %s", epri->dev_name);
 	if(epri->gate_addr != NULL) 
 		printk(", IP = %s", epri->gate_addr);
 	printk("\n");
-	epri->data_fd = -1;
-	epri->control_fd = -1;
-}
-
-static unsigned short etap_protocol(struct sk_buff *skb)
-{
-	return(eth_type_trans(skb, skb->dev));
 }
 
 static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
@@ -80,38 +70,36 @@
 
 struct net_kern_info ethertap_kern_info = {
 	init:			etap_init,
-	protocol:		etap_protocol,
+	protocol:		eth_protocol,
 	read:			etap_read,
 	write: 			etap_write,
 };
 
-static int ethertap_count = 0;
-
-int ethertap_setup(char *str, struct uml_net *dev)
+int ethertap_setup(char *str, char **mac_out, void *data)
 {
-	struct ethertap_setup *pri;
-	int err;
+	struct ethertap_init *init = data;
 
-	pri = &ethertap_priv[ethertap_count];
-	err = tap_setup_common(str, "ethertap", &pri->dev_name, dev->mac,
-			       &dev->have_mac, &pri->gate_addr);
-	if(err) return(err);
-	if(pri->dev_name == NULL){
+	*init = ((struct ethertap_init)
+		{ dev_name :	NULL,
+		  gate_addr :	NULL });
+	if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
+			    &init->gate_addr))
+		return(0);
+	if(init->dev_name == NULL){
 		printk("ethertap_setup : Missing tap device name\n");
-		return(1);
+		return(0);
 	}
 
-	dev->user = &ethertap_user_info;
-	dev->kern = &ethertap_kern_info;
-	dev->private_size = sizeof(struct ethertap_data);
-	dev->transport_index = ethertap_count++;
-	return(0);
+	return(1);
 }
 
 static struct transport ethertap_transport = {
-	list :	LIST_HEAD_INIT(ethertap_transport.list),
-	name :	"ethertap",
-	setup : ethertap_setup
+	list :		LIST_HEAD_INIT(ethertap_transport.list),
+	name :		"ethertap",
+	setup : 	ethertap_setup,
+	user :		&ethertap_user_info,
+	kern :		&ethertap_kern_info,
+	private_size :	sizeof(struct ethertap_data),
 };
 
 static int register_ethertap(void)
diff -Nru a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h
--- a/arch/um/os-Linux/drivers/tuntap.h	Fri Oct 11 21:22:51 2002
+++ b/arch/um/os-Linux/drivers/tuntap.h	Fri Oct 11 21:22:51 2002
@@ -14,8 +14,6 @@
 	char *gate_addr;
 	int fd;
 	void *dev;
-	unsigned char hw_addr[ETH_ADDR_LEN];
-	int hw_setup;
 };
 
 extern struct net_user_info tuntap_user_info;
diff -Nru a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
--- a/arch/um/os-Linux/drivers/tuntap_kern.c	Fri Oct 11 21:23:00 2002
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c	Fri Oct 11 21:23:00 2002
@@ -13,40 +13,30 @@
 #include "net_user.h"
 #include "tuntap.h"
 
-struct tuntap_setup {
+struct tuntap_init {
 	char *dev_name;
 	char *gate_addr;
 };
 
-struct tuntap_setup tuntap_priv[MAX_UML_NETDEV] = { 
-	[ 0 ... MAX_UML_NETDEV - 1 ] =
-	{
-		dev_name:	NULL,
-		gate_addr:	NULL,
-	}
-};
-
-static void tuntap_init(struct net_device *dev, int index)
+static void tuntap_init(struct net_device *dev, void *data)
 {
 	struct uml_net_private *pri;
 	struct tuntap_data *tpri;
+	struct tuntap_init *init = data;
 
 	init_etherdev(dev, 0);
 	pri = dev->priv;
 	tpri = (struct tuntap_data *) pri->user;
-	tpri->dev_name = tuntap_priv[index].dev_name;
-	tpri->fixed_config = (tpri->dev_name != NULL);
-	tpri->gate_addr = tuntap_priv[index].gate_addr;
+	*tpri = ((struct tuntap_data)
+		{ dev_name :		init->dev_name,
+		  fixed_config :	(init->dev_name != NULL),
+		  gate_addr :		init->gate_addr,
+		  fd :			-1,
+		  dev :			dev });
 	printk("TUN/TAP backend - ");
 	if(tpri->gate_addr != NULL) 
 		printk("IP = %s", tpri->gate_addr);
 	printk("\n");
-	tpri->fd = -1;
-}
-
-static unsigned short tuntap_protocol(struct sk_buff *skb)
-{
-	return(eth_type_trans(skb, skb->dev));
 }
 
 static int tuntap_read(int fd, struct sk_buff **skb, 
@@ -66,34 +56,33 @@
 
 struct net_kern_info tuntap_kern_info = {
 	init:			tuntap_init,
-	protocol:		tuntap_protocol,
+	protocol:		eth_protocol,
 	read:			tuntap_read,
 	write: 			tuntap_write,
 };
 
-static int tuntap_count = 0;
-
-int tuntap_setup(char *str, struct uml_net *dev)
+int tuntap_setup(char *str, char **mac_out, void *data)
 {
-	struct tuntap_setup *pri;
-	int err;
+	struct tuntap_init *init = data;
+
+	*init = ((struct tuntap_init)
+		{ dev_name :	NULL,
+		  gate_addr :	NULL });
+	if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out,
+			    &init->gate_addr))
+		return(0);
 
-	pri = &tuntap_priv[tuntap_count];
-	err = tap_setup_common(str, "tuntap", &pri->dev_name, dev->mac,  
-			       &dev->have_mac, &pri->gate_addr);
-	if(err) return(err);
-
-	dev->user = &tuntap_user_info;
-	dev->kern = &tuntap_kern_info;
-	dev->private_size = sizeof(struct tuntap_data);
-	dev->transport_index = tuntap_count++;
-	return(0);
+	return(1);
 }
 
 static struct transport tuntap_transport = {
-	list :	LIST_HEAD_INIT(tuntap_transport.list),
-	name :	"tuntap",
-	setup : tuntap_setup
+	list :		LIST_HEAD_INIT(tuntap_transport.list),
+	name :		"tuntap",
+	setup : 	tuntap_setup,
+	user :		&tuntap_user_info,
+	kern :		&tuntap_kern_info,
+	private_size :	sizeof(struct tuntap_data),
+	setup_size :	sizeof(struct tuntap_init),
 };
 
 static int register_tuntap(void)
diff -Nru a/arch/um/os-Linux/drivers/tuntap_kern.h b/arch/um/os-Linux/drivers/tuntap_kern.h
--- a/arch/um/os-Linux/drivers/tuntap_kern.h	Fri Oct 11 21:22:52 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-/* 
- * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __UM_TUNTAP_KERN_H
-#define __UM_TUNTAP_KERN_H
-
-#include "net_kern.h"
-
-extern int tuntap_setup(char *arg, struct uml_net *dev);
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff -Nru a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
--- a/arch/um/os-Linux/file.c	Fri Oct 11 21:23:05 2002
+++ b/arch/um/os-Linux/file.c	Fri Oct 11 21:23:05 2002
@@ -227,12 +227,12 @@
 
 int os_accept_connection(int fd)
 {
-	int err;
+	int new;
 
-	err = accept(fd, NULL, 0);
-	if(err) 
+	new = accept(fd, NULL, 0);
+	if(new < 0) 
 		return(-errno);
-	return(0);
+	return(new);
 }
 
 #ifndef SHUT_RD
diff -Nru a/arch/um/ptproxy/Makefile b/arch/um/ptproxy/Makefile
--- a/arch/um/ptproxy/Makefile	Fri Oct 11 21:22:55 2002
+++ b/arch/um/ptproxy/Makefile	Fri Oct 11 21:22:55 2002
@@ -1,26 +1,12 @@
-LIB = lib.a
+obj-y = proxy.o ptrace.o sysdep.o wait.o
 
-OBJS = proxy.o ptrace.o sysdep.o wait.o
+USER_OBJS := $(foreach file,$(obj-y),arch/um/ptproxy/$(file))
 
-all: $(LIB)
-
-$(LIB): $(OBJS)
-	rm -f $@
-	ar cr $@ $^
-
-proxy.o: proxy.c
-	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
-
-ptrace.o: ptrace.c
-	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
-
-sysdep.o: sysdep.c
-	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+include $(TOPDIR)/Rules.make
 
-wait.o: wait.c
-	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
 
 clean:
 	rm -f *.o core child ptproxy
 
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
--- a/arch/um/sys-i386/Makefile	Fri Oct 11 21:22:54 2002
+++ b/arch/um/sys-i386/Makefile	Fri Oct 11 21:22:54 2002
@@ -1,10 +1,10 @@
-
 obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o old-checksum.o \
 	ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
 
 export-objs = ksyms.o
 
-USER_OBJS = bugs.o ptrace_user.o sigcontext.o fault.o
+USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
+USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/sys-i386/$(file))
 
 SYMLINKS = semaphore.c old-checksum.c checksum.S extable.c
 
@@ -13,17 +13,17 @@
 $(USER_OBJS) : %.o: %.c
 	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
 
-checksum.S old-checksum.c: 
+arch/um/sys-i386/checksum.S arch/um/sys-i386/old-checksum.c: 
 	-rm -f $@
-	-ln -s $(TOPDIR)/arch/i386/lib/$@ $@
+	-ln -s $(TOPDIR)/arch/i386/lib/$(notdir $@) $@
 
-semaphore.c:
+arch/um/sys-i386/semaphore.c:
 	-rm -f $@
-	-ln -s $(TOPDIR)/arch/i386/kernel/$@ $@
+	-ln -s $(TOPDIR)/arch/i386/kernel/$(notdir $@) $@
 
-extable.c:
+arch/um/sys-i386/extable.c:
 	-rm -f $@
-	-ln -s $(TOPDIR)/arch/i386/mm/$@ $@
+	-ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@
 
 clean:
 	$(MAKE) -C util clean
diff -Nru a/arch/um/util/Makefile b/arch/um/util/Makefile
--- a/arch/um/util/Makefile	Fri Oct 11 21:23:05 2002
+++ b/arch/um/util/Makefile	Fri Oct 11 21:23:05 2002
@@ -1,3 +1,5 @@
+include $(TOPDIR)/Rules.make
+
 all : mk_task
 
 mk_task : mk_task_user.o mk_task_kern.o
@@ -5,9 +7,6 @@
 
 mk_task_user.o : mk_task_user.c
 	$(CC) -c $< 
-
-mk_task_kern.o : mk_task_kern.c
-	$(CC) $(CFLAGS) -c $< 
 
 clean :
 	$(RM) mk_task *.o *~
diff -Nru a/arch/x86_64/config.in b/arch/x86_64/config.in
--- a/arch/x86_64/config.in	Fri Oct 11 21:22:54 2002
+++ b/arch/x86_64/config.in	Fri Oct 11 21:22:54 2002
@@ -54,6 +54,7 @@
 fi
 if [ "$CONFIG_SMP" = "y" ]; then
     define_bool CONFIG_HAVE_DEC_LOCK y
+    int  'Maximum number of CPUs (2-8)' CONFIG_NR_CPUS 8
 fi
 
 define_bool CONFIG_X86_MCE y
diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig
--- a/arch/x86_64/defconfig	Fri Oct 11 21:23:01 2002
+++ b/arch/x86_64/defconfig	Fri Oct 11 21:23:01 2002
@@ -51,6 +51,7 @@
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_X86_MCE=y
 # CONFIG_X86_MCE_NONFATAL is not set
+CONFIG_NR_CPUS=8
 
 #
 # Power management options
diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
--- a/arch/x86_64/ia32/ia32_ioctl.c	Fri Oct 11 21:22:59 2002
+++ b/arch/x86_64/ia32/ia32_ioctl.c	Fri Oct 11 21:22:59 2002
@@ -545,7 +545,7 @@
 	
 	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 		return -EFAULT;
-	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
 	if (!ifr.ifr_data)
 		return -EAGAIN;
 
@@ -608,7 +608,7 @@
 	case SIOCGPPPVER:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
-		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+		ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL);
 		if (!ifr.ifr_data)
 			return -EAGAIN;
 		break;
diff -Nru a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
--- a/arch/x86_64/ia32/sys_ia32.c	Fri Oct 11 21:22:56 2002
+++ b/arch/x86_64/ia32/sys_ia32.c	Fri Oct 11 21:22:56 2002
@@ -2467,7 +2467,7 @@
 	memset(karg, 0, sizeof(*karg));
 	if(get_user(karg->ca_version, &arg32->ca32_version))
 		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+	karg->ca_umap.ug_ident = (char *)get_zeroed_page(GFP_USER);
 	if(!karg->ca_umap.ug_ident)
 		return -ENOMEM;
 	err = get_user(uaddr, &arg32->ca32_umap.ug32_ident);
diff -Nru a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
--- a/arch/x86_64/mm/init.c	Fri Oct 11 21:22:54 2002
+++ b/arch/x86_64/mm/init.c	Fri Oct 11 21:22:54 2002
@@ -80,7 +80,7 @@
 { 
 	void *ptr;
 	if (after_bootmem)
-		ptr = (void *) get_free_page(GFP_ATOMIC); 
+		ptr = (void *) get_zeroed_page(GFP_ATOMIC); 
 	else
 		ptr = alloc_bootmem_low(PAGE_SIZE); 
 	if (!ptr)
diff -Nru a/drivers/acorn/char/mouse_ps2.c b/drivers/acorn/char/mouse_ps2.c
--- a/drivers/acorn/char/mouse_ps2.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/acorn/char/mouse_ps2.c	Fri Oct 11 21:23:02 2002
@@ -271,9 +271,15 @@
 	iomd_writeb(0, IOMD_MSECTL);
 	iomd_writeb(8, IOMD_MSECTL);
   
-	if (misc_register(&psaux_mouse))
-		return -ENODEV;
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+	if (queue == NULL)
+		return -ENOMEM;
+
+	if (misc_register(&psaux_mouse)) {
+		kfree(queue);
+		return -ENODEV;
+	}
+
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
 	init_waitqueue_head(&queue->proc_list);
diff -Nru a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c
--- a/drivers/acorn/char/pcf8583.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/acorn/char/pcf8583.c	Fri Oct 11 21:23:04 2002
@@ -73,6 +73,7 @@
 pcf8583_detach(struct i2c_client *client)
 {
 	i2c_detach_client(client);
+	kfree(client);
 	return 0;
 }
 
diff -Nru a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c
--- a/drivers/acorn/net/etherh.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/acorn/net/etherh.c	Fri Oct 11 21:23:03 2002
@@ -553,15 +553,15 @@
 
 	ecard_claim(ec);
 	
-	dev = init_etherdev(NULL, 0);
+	dev = init_etherdev(NULL, sizeof(struct etherh_priv));
 	if (!dev)
 		goto out;
 
-	eh = kmalloc(sizeof(struct etherh_priv), GFP_KERNEL);
-	if (!eh)
-		goto out_nopriv;
+	/*
+	 * init_etherdev allocs and zeros dev->priv
+	 */
+	eh = dev->priv;
 
-	memset(eh, 0, sizeof(struct etherh_priv));
 	spin_lock_init(&eh->eidev.page_lock);
 
 	SET_MODULE_OWNER(dev);
@@ -695,9 +695,8 @@
 release:
 	release_region(dev->base_addr, 16);
 free:
-	kfree(eh);
-out_nopriv:
 	unregister_netdev(dev);
+	kfree(dev->priv);
 	kfree(dev);
 out:
 	ecard_release(ec);
diff -Nru a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c
--- a/drivers/acorn/scsi/acornscsi.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/acorn/scsi/acornscsi.c	Fri Oct 11 21:22:50 2002
@@ -2877,6 +2877,11 @@
 	ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */
 
 	instance = scsi_register(tpnt, sizeof(AS_Host));
+	if (!instance) {
+		ecard_release(ecs[count]);
+		break;
+	}
+
 	host = (AS_Host *)instance->hostdata;
 
 	instance->io_port = ecard_address(ecs[count], ECARD_MEMC, 0);
diff -Nru a/drivers/acorn/scsi/cumana_1.c b/drivers/acorn/scsi/cumana_1.c
--- a/drivers/acorn/scsi/cumana_1.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/acorn/scsi/cumana_1.c	Fri Oct 11 21:22:53 2002
@@ -140,6 +140,8 @@
     		break;
 
         instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if (!instance)
+		break;
         instance->io_port = CUMANA_ADDRESS(ecs[count]);
 	instance->irq = CUMANA_IRQ(ecs[count]);
 
@@ -147,7 +149,11 @@
 	ecard_claim(ecs[count]);
 
 	instance->n_io_port = 255;
-	request_region (instance->io_port, instance->n_io_port, "CumanaSCSI-1");
+	if ( !(request_region (instance->io_port, instance->n_io_port, "CumanaSCSI-1")) ) {
+		ecard_release(ecs[count]);
+		scsi_unregister(instance);
+		break;
+	}
 
         ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
         outb(0x00, instance->io_port - 577);
diff -Nru a/drivers/acorn/scsi/ecoscsi.c b/drivers/acorn/scsi/ecoscsi.c
--- a/drivers/acorn/scsi/ecoscsi.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/acorn/scsi/ecoscsi.c	Fri Oct 11 21:23:04 2002
@@ -98,61 +98,62 @@
 
 int ecoscsi_detect(Scsi_Host_Template * tpnt)
 {
-    struct Scsi_Host *instance;
+	struct Scsi_Host *instance;
 
-    tpnt->proc_name = "ecoscsi";
+	tpnt->proc_name = "ecoscsi";
 
-    instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-    instance->io_port = 0x80ce8000;
-    instance->n_io_port = 144;
-    instance->irq = IRQ_NONE;
-
-    if (check_region (instance->io_port, instance->n_io_port)) {
-	scsi_unregister (instance);
-	return 0;
-    }
-
-    ecoscsi_write (instance, MODE_REG, 0x20);		/* Is it really SCSI? */
-    if (ecoscsi_read (instance, MODE_REG) != 0x20) {	/* Write to a reg.    */
-        scsi_unregister(instance);
-        return 0;					/* and try to read    */
-    }
-    ecoscsi_write( instance, MODE_REG, 0x00 );		/* it back.	      */
-    if (ecoscsi_read (instance, MODE_REG) != 0x00) {
-        scsi_unregister(instance);
-        return 0;
-    }
-
-    NCR5380_init(instance, 0);
-    if (request_region (instance->io_port, instance->n_io_port, "ecoscsi") == NULL)
-    	{
-	scsi_unregister(instance);
-	return 0;
+	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if (!instance)
+		return 0;
+
+	instance->io_port = 0x80ce8000;
+	instance->n_io_port = 144;
+	instance->irq = IRQ_NONE;
+
+	if ( !(request_region(instance->io_port, instance->n_io_port, "ecoscsi")) )
+		goto unregister_scsi;
+
+	ecoscsi_write (instance, MODE_REG, 0x20);		/* Is it really SCSI? */
+	if (ecoscsi_read (instance, MODE_REG) != 0x20) /* Write to a reg.    */
+		goto release_reg;
+
+	ecoscsi_write( instance, MODE_REG, 0x00 );		/* it back.	      */
+	if (ecoscsi_read (instance, MODE_REG) != 0x00)
+		goto release_reg;
+
+	NCR5380_init(instance, 0);
+
+	if (instance->irq != IRQ_NONE) {
+		if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) {
+			printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+			instance->host_no, instance->irq);
+			instance->irq = IRQ_NONE;
+		}
 	}
 
-    if (instance->irq != IRQ_NONE)
-	if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) {
-	    printk("scsi%d: IRQ%d not free, interrupts disabled\n",
-	    instance->host_no, instance->irq);
-	    instance->irq = IRQ_NONE;
+	if (instance->irq != IRQ_NONE) {
+		printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
+		printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
 	}
 
-    if (instance->irq != IRQ_NONE) {
-  	printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
-	printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
-    }
-
-    printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
-    if (instance->irq == IRQ_NONE)
-	printk ("s disabled");
-    else
-        printk (" %d", instance->irq);
-    printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
-        CAN_QUEUE, CMD_PER_LUN, ECOSCSI_PUBLIC_RELEASE);
-    printk("\nscsi%d:", instance->host_no);
-    NCR5380_print_options(instance);
-    printk("\n");
-    return 1;
+	printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
+	if (instance->irq == IRQ_NONE)
+		printk ("s disabled");
+	else
+		printk (" %d", instance->irq);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+	CAN_QUEUE, CMD_PER_LUN, ECOSCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", instance->host_no);
+	NCR5380_print_options(instance);
+	printk("\n");
+
+	return 1;
+
+release_reg:
+	release_region(instance->io_port, instance->n_io_port);
+unregister_scsi:
+	scsi_unregister(instance);
+	return 0
 }
 
 int ecoscsi_release (struct Scsi_Host *shpnt)
diff -Nru a/drivers/acorn/scsi/oak.c b/drivers/acorn/scsi/oak.c
--- a/drivers/acorn/scsi/oak.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/acorn/scsi/oak.c	Fri Oct 11 21:22:50 2002
@@ -126,6 +126,8 @@
             break;
 
         instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if (!instance)
+		break;
         instance->io_port = OAK_ADDRESS(ecs[count]);
         instance->irq = OAK_IRQ(ecs[count]);
 
@@ -133,8 +135,11 @@
 	ecard_claim(ecs[count]);
 
 	instance->n_io_port = 255;
-	if (!request_region (instance->io_port, instance->n_io_port, "Oak SCSI"))
+	if (!request_region (instance->io_port, instance->n_io_port, "Oak SCSI")) {
+		ecard_release(ecs[count]);
+		scsi_unregister(instance);
 		break;
+	}
 
 	if (instance->irq != IRQ_NONE)
 	    if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c
--- a/drivers/acpi/acpi_ksyms.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/acpi/acpi_ksyms.c	Fri Oct 11 21:22:55 2002
@@ -43,7 +43,7 @@
 
 /* ACPI Core Subsystem */
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 EXPORT_SYMBOL(acpi_dbg_layer);
 EXPORT_SYMBOL(acpi_dbg_level);
 EXPORT_SYMBOL(acpi_ut_debug_print_raw);
@@ -52,7 +52,7 @@
 EXPORT_SYMBOL(acpi_ut_value_exit);
 EXPORT_SYMBOL(acpi_ut_exit);
 EXPORT_SYMBOL(acpi_ut_trace);
-#endif /*ACPI_DEBUG*/
+#endif /*ACPI_DEBUG_OUTPUT*/
 
 EXPORT_SYMBOL(acpi_get_handle);
 EXPORT_SYMBOL(acpi_get_parent);
diff -Nru a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
--- a/drivers/acpi/blacklist.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/acpi/blacklist.c	Fri Oct 11 21:22:51 2002
@@ -95,7 +95,7 @@
 
 	while (acpi_blacklist[i].oem_id[0] != '\0')
 	{
-		if (!acpi_get_table_header_early(acpi_blacklist[i].table, &table_header)) {
+		if (acpi_get_table_header_early(acpi_blacklist[i].table, &table_header)) {
 			i++;
 			continue;
 		}
diff -Nru a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
--- a/drivers/acpi/dispatcher/dsfield.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/acpi/dispatcher/dsfield.c	Fri Oct 11 21:22:53 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsfield - Dispatcher field routines
- *              $Revision: 67 $
+ *              $Revision: 68 $
  *
  *****************************************************************************/
 
@@ -106,6 +106,7 @@
 			 INTERNAL_TYPE_DEF_ANY, ACPI_IMODE_LOAD_PASS1,
 			 flags, walk_state, &(node));
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_NSERROR (arg->common.value.string, status);
 		return_ACPI_STATUS (status);
 	}
 
@@ -245,12 +246,12 @@
 					  info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE,
 					  walk_state, &info->field_node);
 			if (ACPI_FAILURE (status)) {
+				ACPI_REPORT_NSERROR ((char *) &arg->named.name, status);
 				if (status != AE_ALREADY_EXISTS) {
 					return_ACPI_STATUS (status);
 				}
 
-				ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n",
-						(char *) &arg->named.name));
+				/* Already exists, ignore error */
 			}
 			else {
 				arg->common.node = info->field_node;
@@ -329,6 +330,7 @@
 				  ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE,
 				  ACPI_NS_SEARCH_PARENT, walk_state, &region_node);
 		if (ACPI_FAILURE (status)) {
+			ACPI_REPORT_NSERROR (arg->common.value.name, status);
 			return_ACPI_STATUS (status);
 		}
 	}
@@ -412,13 +414,11 @@
 					  ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
 					  walk_state, &node);
 			if (ACPI_FAILURE (status)) {
+				ACPI_REPORT_NSERROR ((char *) &arg->named.name, status);
 				if (status != AE_ALREADY_EXISTS) {
 					return_ACPI_STATUS (status);
 				}
 
-				ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n",
-						(char *) &arg->named.name));
-
 				/* Name already exists, just ignore this error */
 
 				status = AE_OK;
@@ -472,6 +472,7 @@
 				  ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE,
 				  ACPI_NS_SEARCH_PARENT, walk_state, &region_node);
 		if (ACPI_FAILURE (status)) {
+			ACPI_REPORT_NSERROR (arg->common.value.name, status);
 			return_ACPI_STATUS (status);
 		}
 	}
@@ -483,6 +484,7 @@
 			  INTERNAL_TYPE_BANK_FIELD_DEFN, ACPI_IMODE_EXECUTE,
 			  ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_NSERROR (arg->common.value.string, status);
 		return_ACPI_STATUS (status);
 	}
 
@@ -542,6 +544,7 @@
 			  ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
 			  ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_NSERROR (arg->common.value.string, status);
 		return_ACPI_STATUS (status);
 	}
 
@@ -552,6 +555,7 @@
 			  INTERNAL_TYPE_INDEX_FIELD_DEFN, ACPI_IMODE_EXECUTE,
 			  ACPI_NS_SEARCH_PARENT, walk_state, &info.data_register_node);
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_NSERROR (arg->common.value.string, status);
 		return_ACPI_STATUS (status);
 	}
 
@@ -559,7 +563,6 @@
 
 	arg = arg->common.next;
 	info.field_flags = arg->common.value.integer8;
-
 
 	/* Each remaining arg is a Named Field */
 
diff -Nru a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
--- a/drivers/acpi/dispatcher/dsobject.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/acpi/dispatcher/dsobject.c	Fri Oct 11 21:22:51 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsobject - Dispatcher object management routines
- *              $Revision: 107 $
+ *              $Revision: 108 $
  *
  *****************************************************************************/
 
@@ -240,12 +240,12 @@
 {
 	acpi_operand_object     *obj_desc;
 	acpi_status             status;
-	char                    *name;
 
 
 	ACPI_FUNCTION_TRACE ("Ds_build_internal_object");
 
 
+	*obj_desc_ptr = NULL;
 	if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
 		/*
 		 * This is an named object reference.  If this name was
@@ -259,24 +259,8 @@
 					  (acpi_namespace_node **) &(op->common.node));
 
 			if (ACPI_FAILURE (status)) {
-				if (status == AE_NOT_FOUND) {
-					name = NULL;
-					status = acpi_ns_externalize_name (ACPI_UINT32_MAX, op->common.value.string, NULL, &name);
-					if (ACPI_SUCCESS (status)) {
-						ACPI_REPORT_WARNING (("Reference %s at AML %X not found\n",
-								 name, op->common.aml_offset));
-						ACPI_MEM_FREE (name);
-					}
-					else {
-						ACPI_REPORT_WARNING (("Reference %s at AML %X not found\n",
-								   op->common.value.string, op->common.aml_offset));
-					}
-
-					*obj_desc_ptr = NULL;
-				}
-				else {
-					return_ACPI_STATUS (status);
-				}
+				ACPI_REPORT_NSERROR (op->common.value.string, status);
+				return_ACPI_STATUS (status);
 			}
 		}
 	}
diff -Nru a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
--- a/drivers/acpi/dispatcher/dsutils.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/acpi/dispatcher/dsutils.c	Fri Oct 11 21:22:58 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: dsutils - Dispatcher utilities
- *              $Revision: 94 $
+ *              $Revision: 95 $
  *
  ******************************************************************************/
 
@@ -300,7 +300,6 @@
 	u32                     arg_index)
 {
 	acpi_status             status = AE_OK;
-	acpi_status             status2;
 	NATIVE_CHAR             *name_string;
 	u32                     name_length;
 	acpi_operand_object     *obj_desc;
@@ -308,7 +307,6 @@
 	u16                     opcode;
 	acpi_interpreter_mode   interpreter_mode;
 	const acpi_opcode_info  *op_info;
-	char                    *name;
 
 
 	ACPI_FUNCTION_TRACE_PTR ("Ds_create_operand", arg);
@@ -384,15 +382,11 @@
 				 * very serious error at this point
 				 */
 				status = AE_AML_NAME_NOT_FOUND;
-
-				name = NULL;
-				status2 = acpi_ns_externalize_name (ACPI_UINT32_MAX, name_string, NULL, &name);
-				if (ACPI_SUCCESS (status2)) {
-					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-							"Object name [%s] was not found in namespace\n", name));
-					ACPI_MEM_FREE (name);
-				}
 			}
+		}
+
+		if (ACPI_FAILURE (status)) {
+			ACPI_REPORT_NSERROR (name_string, status);
 		}
 
 		/* Free the namestring created above */
diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
--- a/drivers/acpi/dispatcher/dswload.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/acpi/dispatcher/dswload.c	Fri Oct 11 21:22:53 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dswload - Dispatcher namespace load callbacks
- *              $Revision: 73 $
+ *              $Revision: 75 $
  *
  *****************************************************************************/
 
@@ -183,6 +183,7 @@
 	status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
 			  ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node));
 	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_NSERROR (path, status);
 		return (status);
 	}
 
@@ -194,7 +195,6 @@
 		switch (node->type) {
 		case ACPI_TYPE_ANY:         /* Scope nodes are untyped (ANY) */
 		case ACPI_TYPE_DEVICE:
-		case ACPI_TYPE_METHOD:
 		case ACPI_TYPE_POWER:
 		case ACPI_TYPE_PROCESSOR:
 		case ACPI_TYPE_THERMAL:
@@ -212,10 +212,12 @@
 			 *
 			 *  Name (DEB, 0)
 			 *  Scope (DEB) { ... }
+			 *
+			 * Note: silently change the type here.  On the second pass, we will report a warning
 			 */
 
-			ACPI_REPORT_WARNING (("Invalid type (%s) for target of Scope operator [%4.4s], changing type to ANY\n",
-				acpi_ut_get_type_name (node->type), path));
+			ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
+				path, acpi_ut_get_type_name (node->type)));
 
 			node->type = ACPI_TYPE_ANY;
 			walk_state->scope_info->common.value = ACPI_TYPE_ANY;
@@ -225,7 +227,7 @@
 
 			/* All other types are an error */
 
-			ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n",
+			ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n",
 				acpi_ut_get_type_name (node->type), path));
 
 			return (AE_AML_OPERAND_TYPE);
@@ -458,77 +460,80 @@
 				  ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node));
 	}
 
-	if (ACPI_SUCCESS (status)) {
-		/*
-		 * For the scope op, we must check to make sure that the target is
-		 * one of the opcodes that actually opens a scope
-		 */
-		if (walk_state->opcode == AML_SCOPE_OP) {
-			switch (node->type) {
-			case ACPI_TYPE_ANY:         /* Scope nodes are untyped (ANY) */
-			case ACPI_TYPE_DEVICE:
-			case ACPI_TYPE_METHOD:
-			case ACPI_TYPE_POWER:
-			case ACPI_TYPE_PROCESSOR:
-			case ACPI_TYPE_THERMAL:
-
-				/* These are acceptable types */
-				break;
-
-			case ACPI_TYPE_INTEGER:
-			case ACPI_TYPE_STRING:
-			case ACPI_TYPE_BUFFER:
+	if (ACPI_FAILURE (status)) {
+		ACPI_REPORT_NSERROR (buffer_ptr, status);
+		return_ACPI_STATUS (status);
+	}
 
-				/*
-				 * These types we will allow, but we will change the type.  This
-				 * enables some existing code of the form:
-				 *
-				 *  Name (DEB, 0)
-				 *  Scope (DEB) { ... }
-				 */
+	/*
+	 * For the scope op, we must check to make sure that the target is
+	 * one of the opcodes that actually opens a scope
+	 */
+	if (walk_state->opcode == AML_SCOPE_OP) {
+		switch (node->type) {
+		case ACPI_TYPE_ANY:         /* Scope nodes are untyped (ANY) */
+		case ACPI_TYPE_DEVICE:
+		case ACPI_TYPE_POWER:
+		case ACPI_TYPE_PROCESSOR:
+		case ACPI_TYPE_THERMAL:
 
-				ACPI_REPORT_WARNING (("Invalid type (%s) for target of Scope operator [%4.4s], changing type to ANY\n",
-					acpi_ut_get_type_name (node->type), buffer_ptr));
+			/* These are acceptable types */
+			break;
 
-				node->type = ACPI_TYPE_ANY;
-				walk_state->scope_info->common.value = ACPI_TYPE_ANY;
-				break;
+		case ACPI_TYPE_INTEGER:
+		case ACPI_TYPE_STRING:
+		case ACPI_TYPE_BUFFER:
 
-		   default:
+			/*
+			 * These types we will allow, but we will change the type.  This
+			 * enables some existing code of the form:
+			 *
+			 *  Name (DEB, 0)
+			 *  Scope (DEB) { ... }
+			 */
 
-				/* All other types are an error */
+			ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
+				buffer_ptr, acpi_ut_get_type_name (node->type)));
 
-				ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n",
-					acpi_ut_get_type_name (node->type), buffer_ptr));
+			node->type = ACPI_TYPE_ANY;
+			walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+			break;
 
-				return (AE_AML_OPERAND_TYPE);
-			}
-		}
-		if (!op) {
-			/* Create a new op */
+	   default:
 
-			op = acpi_ps_alloc_op (walk_state->opcode);
-			if (!op) {
-				return_ACPI_STATUS (AE_NO_MEMORY);
-			}
+			/* All other types are an error */
 
-			/* Initialize the new op */
+			ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n",
+				acpi_ut_get_type_name (node->type), buffer_ptr));
 
-			if (node) {
-				op->named.name = node->name.integer;
-			}
-			if (out_op) {
-				*out_op = op;
-			}
+			return (AE_AML_OPERAND_TYPE);
 		}
+	}
 
-		/*
-		 * Put the Node in the "op" object that the parser uses, so we
-		 * can get it again quickly when this scope is closed
-		 */
-		op->common.node = node;
+	if (!op) {
+		/* Create a new op */
+
+		op = acpi_ps_alloc_op (walk_state->opcode);
+		if (!op) {
+			return_ACPI_STATUS (AE_NO_MEMORY);
+		}
+
+		/* Initialize the new op */
+
+		if (node) {
+			op->named.name = node->name.integer;
+		}
+		if (out_op) {
+			*out_op = op;
+		}
 	}
 
+	/*
+	 * Put the Node in the "op" object that the parser uses, so we
+	 * can get it again quickly when this scope is closed
+	 */
+	op->common.node = node;
+
 	return_ACPI_STATUS (status);
 }
 
@@ -834,7 +839,9 @@
 			 */
 			op->common.node = new_node;
 		}
-
+		else {
+			ACPI_REPORT_NSERROR (arg->common.value.string, status);
+		}
 		break;
 
 
diff -Nru a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
--- a/drivers/acpi/dispatcher/dswscope.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/acpi/dispatcher/dswscope.c	Fri Oct 11 21:23:05 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dswscope - Scope stack manipulation
- *              $Revision: 52 $
+ *              $Revision: 53 $
  *
  *****************************************************************************/
 
@@ -63,7 +63,7 @@
 		walk_state->scope_info = scope_info->scope.next;
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
-			"Popped object type %X\n", scope_info->common.value));
+			"Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value)));
 		acpi_ut_delete_generic_state (scope_info);
 	}
 }
@@ -164,7 +164,7 @@
 	}
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
-		"Popped object type %X\n", scope_info->common.value));
+		"Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value)));
 
 	acpi_ut_delete_generic_state (scope_info);
 
diff -Nru a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
--- a/drivers/acpi/events/evevent.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/acpi/events/evevent.c	Fri Oct 11 21:23:03 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: evevent - Fixed and General Purpose Even handling and dispatch
- *              $Revision: 91 $
+ *              $Revision: 92 $
  *
  *****************************************************************************/
 
@@ -202,8 +202,8 @@
 	void)
 {
 	u32                     int_status = ACPI_INTERRUPT_NOT_HANDLED;
-	u32                     gpe_status;
-	u32                     gpe_enable;
+	u32                     fixed_status;
+	u32                     fixed_enable;
 	NATIVE_UINT_MAX32       i;
 
 
@@ -214,12 +214,12 @@
 	 * Read the fixed feature status and enable registers, as all the cases
 	 * depend on their values.  Ignore errors here.
 	 */
-	(void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, &gpe_status);
-	(void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &gpe_enable);
+	(void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, &fixed_status);
+	(void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
 
 	ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
 		"Fixed Acpi_event Block: Enable %08X Status %08X\n",
-		gpe_enable, gpe_status));
+		fixed_enable, fixed_status));
 
 	/*
 	 * Check for all possible Fixed Events and dispatch those that are active
@@ -227,8 +227,8 @@
 	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
 		/* Both the status and enable bits must be on for this event */
 
-		if ((gpe_status & acpi_gbl_fixed_event_info[i].status_bit_mask) &&
-			(gpe_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) {
+		if ((fixed_status & acpi_gbl_fixed_event_info[i].status_bit_mask) &&
+			(fixed_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) {
 			/* Found an active (signalled) event */
 
 			int_status |= acpi_ev_fixed_event_dispatch (i);
diff -Nru a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
--- a/drivers/acpi/executer/exconvrt.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/acpi/executer/exconvrt.c	Fri Oct 11 21:22:52 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exconvrt - Object conversion routines
- *              $Revision: 38 $
+ *              $Revision: 39 $
  *
  *****************************************************************************/
 
@@ -172,7 +172,7 @@
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Convert an ACPI Object to an Buffer
+ * DESCRIPTION: Convert an ACPI Object to a Buffer
  *
  ******************************************************************************/
 
@@ -256,7 +256,6 @@
 		/* Return the new buffer descriptor */
 
 		*result_desc = ret_desc;
-
 		break;
 
 
@@ -280,11 +279,13 @@
  *
  * FUNCTION:    Acpi_ex_convert_ascii
  *
- * PARAMETERS:  Integer
+ * PARAMETERS:  Integer         - Value to be converted
+ *              Base            - 10 or 16
+ *              String          - Where the string is returned
  *
  * RETURN:      Actual string length
  *
- * DESCRIPTION: Convert an ACPI Integer to a hex string
+ * DESCRIPTION: Convert an ACPI Integer to a hex or decimal string
  *
  ******************************************************************************/
 
@@ -596,8 +597,8 @@
 			/* No conversion allowed for these types */
 
 			if (destination_type != ACPI_GET_OBJECT_TYPE (source_desc)) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-					"Target does not allow conversion of type %s to %s\n",
+				ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+					"Explicit operator, will store (%s) over existing type (%s)\n",
 					acpi_ut_get_object_type_name (source_desc),
 					acpi_ut_get_type_name (destination_type)));
 				status = AE_TYPE;
diff -Nru a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
--- a/drivers/acpi/executer/excreate.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/acpi/executer/excreate.c	Fri Oct 11 21:23:04 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: excreate - Named object creation
- *              $Revision: 93 $
+ *              $Revision: 94 $
  *
  *****************************************************************************/
 
@@ -53,7 +53,8 @@
 acpi_ex_create_alias (
 	acpi_walk_state         *walk_state)
 {
-	acpi_namespace_node     *source_node;
+	acpi_namespace_node     *target_node;
+	acpi_namespace_node     *alias_node;
 	acpi_status             status;
 
 
@@ -62,25 +63,61 @@
 
 	/* Get the source/alias operands (both namespace nodes) */
 
-	source_node = (acpi_namespace_node *) walk_state->operands[1];
+	alias_node = (acpi_namespace_node *) walk_state->operands[0];
+	target_node = (acpi_namespace_node *) walk_state->operands[1];
 
-
-	/* Attach the original source object to the new Alias Node */
-
-	status = acpi_ns_attach_object ((acpi_namespace_node *) walk_state->operands[0],
-			   acpi_ns_get_attached_object (source_node),
-			   source_node->type);
+	if (target_node->type == INTERNAL_TYPE_ALIAS) {
+		/*
+		 * Dereference an existing alias so that we don't create a chain
+		 * of aliases.  With this code, we guarantee that an alias is
+		 * always exactly one level of indirection away from the
+		 * actual aliased name.
+		 */
+		target_node = (acpi_namespace_node *) target_node->object;
+	}
 
 	/*
-	 * The new alias assumes the type of the source, but it points
-	 * to the same object.  The reference count of the object has an
-	 * additional reference to prevent deletion out from under either the
-	 * source or the alias Node
+	 * For objects that can never change (i.e., the NS node will
+	 * permanently point to the same object), we can simply attach
+	 * the object to the new NS node.  For other objects (such as
+	 * Integers, buffers, etc.), we have to point the Alias node
+	 * to the original Node.
 	 */
+	switch (target_node->type) {
+	case ACPI_TYPE_INTEGER:
+	case ACPI_TYPE_STRING:
+	case ACPI_TYPE_BUFFER:
+	case ACPI_TYPE_PACKAGE:
+	case ACPI_TYPE_BUFFER_FIELD:
+
+		/*
+		 * The new alias has the type ALIAS and points to the original
+		 * NS node, not the object itself.  This is because for these
+		 * types, the object can change dynamically via a Store.
+		 */
+		alias_node->type = INTERNAL_TYPE_ALIAS;
+		alias_node->object = (acpi_operand_object *) target_node;
+		break;
+
+	default:
+
+		/* Attach the original source object to the new Alias Node */
+
+		/*
+		 * The new alias assumes the type of the target, and it points
+		 * to the same object.  The reference count of the object has an
+		 * additional reference to prevent deletion out from under either the
+		 * target node or the alias Node
+		 */
+		status = acpi_ns_attach_object (alias_node,
+				 acpi_ns_get_attached_object (target_node),
+				 target_node->type);
+		break;
+	}
 
 	/* Since both operands are Nodes, we don't need to delete them */
 
-	return_ACPI_STATUS (status);
+	return_ACPI_STATUS (AE_OK);
 }
 
 
diff -Nru a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
--- a/drivers/acpi/executer/exdump.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/acpi/executer/exdump.c	Fri Oct 11 21:22:53 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exdump - Interpreter debug output routines
- *              $Revision: 159 $
+ *              $Revision: 160 $
  *
  *****************************************************************************/
 
@@ -577,6 +577,14 @@
 		{
 			return_VOID;
 		}
+	}
+
+	if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED)
+	{
+		acpi_ex_dump_node ((acpi_namespace_node *) obj_desc, flags);
+		acpi_os_printf ("\nAttached Object (%p):\n", ((acpi_namespace_node *) obj_desc)->object);
+		acpi_ex_dump_object_descriptor (((acpi_namespace_node *) obj_desc)->object, flags);
+		return;
 	}
 
 	if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND)
diff -Nru a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
--- a/drivers/acpi/executer/exoparg2.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/acpi/executer/exoparg2.c	Fri Oct 11 21:22:58 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg2 - AML execution - opcodes with 2 arguments
- *              $Revision: 110 $
+ *              $Revision: 111 $
  *
  *****************************************************************************/
 
@@ -244,9 +244,10 @@
 {
 	acpi_operand_object     **operand   = &walk_state->operands[0];
 	acpi_operand_object     *return_desc = NULL;
-	acpi_operand_object     *temp_desc;
+	acpi_operand_object     *temp_desc = NULL;
 	u32                     index;
 	acpi_status             status      = AE_OK;
+	ACPI_SIZE               length;
 
 
 	ACPI_FUNCTION_TRACE_STR ("Ex_opcode_2A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
@@ -284,7 +285,6 @@
 
 		status = acpi_ut_divide (&operand[0]->integer.value, &operand[1]->integer.value,
 				  NULL, &return_desc->integer.value);
-
 		break;
 
 
@@ -299,15 +299,15 @@
 		 */
 		switch (ACPI_GET_OBJECT_TYPE (operand[0])) {
 		case ACPI_TYPE_INTEGER:
-			status = acpi_ex_convert_to_integer (operand[1], &operand[1], walk_state);
+			status = acpi_ex_convert_to_integer (operand[1], &temp_desc, walk_state);
 			break;
 
 		case ACPI_TYPE_STRING:
-			status = acpi_ex_convert_to_string (operand[1], &operand[1], 16, ACPI_UINT32_MAX, walk_state);
+			status = acpi_ex_convert_to_string (operand[1], &temp_desc, 16, ACPI_UINT32_MAX, walk_state);
 			break;
 
 		case ACPI_TYPE_BUFFER:
-			status = acpi_ex_convert_to_buffer (operand[1], &operand[1], walk_state);
+			status = acpi_ex_convert_to_buffer (operand[1], &temp_desc, walk_state);
 			break;
 
 		default:
@@ -323,14 +323,63 @@
 		 * (Both are Integer, String, or Buffer), and we can now perform the
 		 * concatenation.
 		 */
-		status = acpi_ex_do_concatenate (operand[0], operand[1], &return_desc, walk_state);
+		status = acpi_ex_do_concatenate (operand[0], temp_desc, &return_desc, walk_state);
+		if (temp_desc != operand[1]) {
+			acpi_ut_remove_reference (temp_desc);
+		}
 		break;
 
 
 	case AML_TO_STRING_OP:          /* To_string (Buffer, Length, Result) (ACPI 2.0) */
 
-		status = acpi_ex_convert_to_string (operand[0], &return_desc, 16,
-				  (u32) operand[1]->integer.value, walk_state);
+		/*
+		 * Input object is guaranteed to be a buffer at this point (it may have
+		 * been converted.)  Copy the raw buffer data to a new object of type String.
+		 */
+
+		/* Get the length of the new string */
+
+		length = 0;
+		if (operand[1]->integer.value == 0) {
+			/* Handle optional length value */
+
+			operand[1]->integer.value = ACPI_INTEGER_MAX;
+		}
+
+		while ((length < operand[0]->buffer.length) &&
+			   (length < operand[1]->integer.value) &&
+			   (operand[0]->buffer.pointer[length])) {
+			length++;
+		}
+
+		if (length > ACPI_MAX_STRING_CONVERSION) {
+			status = AE_AML_STRING_LIMIT;
+			goto cleanup;
+		}
+
+		/* Create the internal return object */
+
+		return_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
+		if (!return_desc) {
+			status = AE_NO_MEMORY;
+			goto cleanup;
+		}
+
+		/* Allocate a new string buffer (Length + 1 for null terminator) */
+
+		return_desc->string.pointer = ACPI_MEM_CALLOCATE (length + 1);
+		if (!return_desc->string.pointer) {
+			status = AE_NO_MEMORY;
+			goto cleanup;
+		}
+
+		/* Copy the raw buffer data with no transform */
+
+		ACPI_MEMCPY (return_desc->string.pointer, operand[0]->buffer.pointer, length);
+
+		/* Set the string length */
+
+		return_desc->string.length = length;
 		break;
 
 
diff -Nru a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
--- a/drivers/acpi/executer/exresnte.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/acpi/executer/exresnte.c	Fri Oct 11 21:22:54 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresnte - AML Interpreter object resolution
- *              $Revision: 58 $
+ *              $Revision: 59 $
  *
  *****************************************************************************/
 
@@ -88,6 +88,15 @@
 	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p Source_desc=%p Type=%X\n",
 		 node, source_desc, entry_type));
 
+	if (entry_type == INTERNAL_TYPE_ALIAS) {
+		/* There is always exactly one level of indirection */
+
+		node       = (acpi_namespace_node *) node->object;
+		source_desc = acpi_ns_get_attached_object (node);
+		entry_type = acpi_ns_get_type ((acpi_handle) node);
+		*object_ptr = node;
+	}
+
 	/*
 	 * Several object types require no further processing:
 	 * 1) Devices rarely have an attached object, return the Node
@@ -204,7 +213,7 @@
 		break;
 
 
-	/* TYPE_Any is untyped, and thus there is no object associated with it */
+	/* TYPE_ANY is untyped, and thus there is no object associated with it */
 
 	case ACPI_TYPE_ANY:
 
diff -Nru a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
--- a/drivers/acpi/executer/exresop.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/acpi/executer/exresop.c	Fri Oct 11 21:23:03 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresop - AML Interpreter operand/object resolution
- *              $Revision: 57 $
+ *              $Revision: 58 $
  *
  *****************************************************************************/
 
@@ -320,6 +320,10 @@
 			return_ACPI_STATUS (status);
 		}
 
+		/* Get the resolved object */
+
+		obj_desc = *stack_ptr;
+
 		/*
 		 * Check the resulting object (value) type
 		 */
@@ -379,19 +383,28 @@
 			/*
 			 * Need an operand of type ACPI_TYPE_INTEGER,
 			 * But we can implicitly convert from a STRING or BUFFER
+			 * Aka - "Implicit Source Operand Conversion"
 			 */
-			status = acpi_ex_convert_to_integer (*stack_ptr, stack_ptr, walk_state);
+			status = acpi_ex_convert_to_integer (obj_desc, stack_ptr, walk_state);
 			if (ACPI_FAILURE (status)) {
 				if (status == AE_TYPE) {
 					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 						"Needed [Integer/String/Buffer], found [%s] %p\n",
-						acpi_ut_get_object_type_name (*stack_ptr), *stack_ptr));
+						acpi_ut_get_object_type_name (obj_desc), obj_desc));
 
 					return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 				}
 
 				return_ACPI_STATUS (status);
 			}
+
+			if (obj_desc != *stack_ptr) {
+				/*
+				 * We just created a new object, remove a reference
+				 * on the original operand object
+				 */
+				acpi_ut_remove_reference (obj_desc);
+			}
 			goto next_operand;
 
 
@@ -400,19 +413,28 @@
 			/*
 			 * Need an operand of type ACPI_TYPE_BUFFER,
 			 * But we can implicitly convert from a STRING or INTEGER
+			 * Aka - "Implicit Source Operand Conversion"
 			 */
-			status = acpi_ex_convert_to_buffer (*stack_ptr, stack_ptr, walk_state);
+			status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr, walk_state);
 			if (ACPI_FAILURE (status)) {
 				if (status == AE_TYPE) {
 					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 						"Needed [Integer/String/Buffer], found [%s] %p\n",
-						acpi_ut_get_object_type_name (*stack_ptr), *stack_ptr));
+						acpi_ut_get_object_type_name (obj_desc), obj_desc));
 
 					return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 				}
 
 				return_ACPI_STATUS (status);
 			}
+
+			if (obj_desc != *stack_ptr) {
+				/*
+				 * We just created a new object, remove a reference
+				 * on the original operand object
+				 */
+				acpi_ut_remove_reference (obj_desc);
+			}
 			goto next_operand;
 
 
@@ -421,19 +443,28 @@
 			/*
 			 * Need an operand of type ACPI_TYPE_STRING,
 			 * But we can implicitly convert from a BUFFER or INTEGER
+			 * Aka - "Implicit Source Operand Conversion"
 			 */
-			status = acpi_ex_convert_to_string (*stack_ptr, stack_ptr, 16, ACPI_UINT32_MAX, walk_state);
+			status = acpi_ex_convert_to_string (obj_desc, stack_ptr, 16, ACPI_UINT32_MAX, walk_state);
 			if (ACPI_FAILURE (status)) {
 				if (status == AE_TYPE) {
 					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 						"Needed [Integer/String/Buffer], found [%s] %p\n",
-						acpi_ut_get_object_type_name (*stack_ptr), *stack_ptr));
+						acpi_ut_get_object_type_name (obj_desc), obj_desc));
 
 					return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 				}
 
 				return_ACPI_STATUS (status);
 			}
+
+			if (obj_desc != *stack_ptr) {
+				/*
+				 * We just created a new object, remove a reference
+				 * on the original operand object
+				 */
+				acpi_ut_remove_reference (obj_desc);
+			}
 			goto next_operand;
 
 
@@ -441,7 +472,7 @@
 
 			/* Need an operand of type INTEGER, STRING or BUFFER */
 
-			switch (ACPI_GET_OBJECT_TYPE (*stack_ptr)) {
+			switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
 			case ACPI_TYPE_INTEGER:
 			case ACPI_TYPE_STRING:
 			case ACPI_TYPE_BUFFER:
@@ -452,7 +483,7 @@
 			default:
 				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 					"Needed [Integer/String/Buffer], found [%s] %p\n",
-					acpi_ut_get_object_type_name (*stack_ptr), *stack_ptr));
+					acpi_ut_get_object_type_name (obj_desc), obj_desc));
 
 				return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 			}
@@ -467,40 +498,7 @@
 			 * The only reference allowed here is a direct reference to
 			 * a namespace node.
 			 */
-#if 0
-			if (ACPI_GET_OBJECT_TYPE (*stack_ptr) == INTERNAL_TYPE_REFERENCE) {
-				if (!(*stack_ptr)->reference.node) {
-					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-						"Needed [Node Reference], found [%p]\n",
-						*stack_ptr));
-
-					return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
-				}
-
-				/* Get the object attached to the node */
-
-				temp_node = acpi_ns_get_attached_object ((*stack_ptr)->reference.node);
-				if (!temp_node) {
-					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-						"Node [%p] has no attached object\n",
-						(*stack_ptr)->reference.node));
-
-					return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
-				}
-
-				/*
-				 * Swap the reference object with the node's object.  Must add
-				 * a reference to the node object, and remove a reference from
-				 * the original reference object.
-				 */
-				acpi_ut_add_reference (temp_node);
-				acpi_ut_remove_reference (*stack_ptr);
-				(*stack_ptr) = temp_node;
-			}
-#endif
-			/* Need a buffer, string, package */
-
-			switch (ACPI_GET_OBJECT_TYPE (*stack_ptr)) {
+			switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
 			case ACPI_TYPE_PACKAGE:
 			case ACPI_TYPE_STRING:
 			case ACPI_TYPE_BUFFER:
@@ -512,7 +510,7 @@
 			default:
 				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 					"Needed [Buf/Str/Pkg], found [%s] %p\n",
-					acpi_ut_get_object_type_name (*stack_ptr), *stack_ptr));
+					acpi_ut_get_object_type_name (obj_desc), obj_desc));
 
 				return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 			}
@@ -523,7 +521,7 @@
 
 			/* Need a buffer or package or (ACPI 2.0) String */
 
-			switch (ACPI_GET_OBJECT_TYPE (*stack_ptr)) {
+			switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
 			case ACPI_TYPE_PACKAGE:
 			case ACPI_TYPE_STRING:
 			case ACPI_TYPE_BUFFER:
@@ -534,7 +532,7 @@
 			default:
 				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
 					"Needed [Buf/Str/Pkg], found [%s] %p\n",
-					acpi_ut_get_object_type_name (*stack_ptr), *stack_ptr));
+					acpi_ut_get_object_type_name (obj_desc), obj_desc));
 
 				return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 			}
@@ -546,7 +544,7 @@
 			/* Unknown type */
 
 			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-				"Internal - Unknown ARGI type %X\n",
+				"Internal - Unknown ARGI (required operand) type %X\n",
 				this_arg_type));
 
 			return_ACPI_STATUS (AE_BAD_PARAMETER);
diff -Nru a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
--- a/drivers/acpi/executer/exstore.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/acpi/executer/exstore.c	Fri Oct 11 21:22:56 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exstore - AML Interpreter object store support
- *              $Revision: 171 $
+ *              $Revision: 172 $
  *
  *****************************************************************************/
 
@@ -459,8 +459,12 @@
 			 * Store the new New_desc as the new value of the Name, and set
 			 * the Name's type to that of the value being stored in it.
 			 * Source_desc reference count is incremented by Attach_object.
+			 *
+			 * Note: This may change the type of the node if an explicit store
+			 * has been performed such that the node/object type has been
+			 * changed.
 			 */
-			status = acpi_ns_attach_object (node, new_desc, target_type);
+			status = acpi_ns_attach_object (node, new_desc, new_desc->common.type);
 
 			ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 				"Store %s into %s via Convert/Attach\n",
diff -Nru a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
--- a/drivers/acpi/executer/exstorob.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/acpi/executer/exstorob.c	Fri Oct 11 21:23:04 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exstorob - AML Interpreter object store support, store to object
- *              $Revision: 44 $
+ *              $Revision: 45 $
  *
  *****************************************************************************/
 
@@ -87,7 +87,6 @@
 		ACPI_MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length);
 		ACPI_MEMCPY (target_desc->buffer.pointer, buffer, length);
 	}
-
 	else {
 		/*
 		 * Truncate the source, copy only what will fit
@@ -102,7 +101,6 @@
 	/* Copy flags */
 
 	target_desc->buffer.flags = source_desc->buffer.flags;
-
 	return (AE_OK);
 }
 
@@ -142,15 +140,16 @@
 	 * Setting a string value replaces the old string
 	 */
 	if (length < target_desc->string.length) {
-		/* Clear old string and copy in the new one */
-
-		ACPI_MEMSET (target_desc->string.pointer, 0, target_desc->string.length);
+		/*
+		 * String will fit in existing buffer.
+		 * Clear old string and copy in the new one
+		 */
+		ACPI_MEMSET (target_desc->string.pointer, 0, target_desc->string.length + 1);
 		ACPI_MEMCPY (target_desc->string.pointer, buffer, length);
 	}
-
 	else {
 		/*
-		 * Free the current buffer, then allocate a buffer
+		 * Free the current buffer, then allocate a new buffer
 		 * large enough to hold the value
 		 */
 		if (target_desc->string.pointer &&
@@ -161,15 +160,17 @@
 			ACPI_MEM_FREE (target_desc->string.pointer);
 		}
 
-		target_desc->string.pointer = ACPI_MEM_ALLOCATE ((ACPI_SIZE) length + 1);
+		target_desc->string.pointer = ACPI_MEM_CALLOCATE ((ACPI_SIZE) length + 1);
 		if (!target_desc->string.pointer) {
 			return (AE_NO_MEMORY);
 		}
 
-		target_desc->string.length = length;
 		ACPI_MEMCPY (target_desc->string.pointer, buffer, length);
 	}
 
+	/* Set the new target length */
+
+	target_desc->string.length = length;
 	return (AE_OK);
 }
 
diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h
--- a/drivers/acpi/include/acconfig.h	Fri Oct 11 21:22:54 2002
+++ b/drivers/acpi/include/acconfig.h	Fri Oct 11 21:22:54 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acconfig.h - Global configuration constants
- *       $Revision: 111 $
+ *       $Revision: 112 $
  *
  *****************************************************************************/
 
@@ -54,7 +54,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20020918
+#define ACPI_CA_VERSION                 0x20021002
 
 /* Version of ACPI supported */
 
diff -Nru a/drivers/acpi/include/acmacros.h b/drivers/acpi/include/acmacros.h
--- a/drivers/acpi/include/acmacros.h	Fri Oct 11 21:22:59 2002
+++ b/drivers/acpi/include/acmacros.h	Fri Oct 11 21:22:59 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acmacros.h - C macros for the entire subsystem.
- *       $Revision: 128 $
+ *       $Revision: 130 $
  *
  *****************************************************************************/
 
@@ -365,6 +365,7 @@
 												acpi_os_printf ACPI_PARAM_LIST(fp);}
 #define ACPI_REPORT_WARNING(fp)             {acpi_ut_report_warning(_THIS_MODULE,__LINE__,_COMPONENT); \
 												acpi_os_printf ACPI_PARAM_LIST(fp);}
+#define ACPI_REPORT_NSERROR(s,e)            acpi_ns_report_error(_THIS_MODULE,__LINE__,_COMPONENT, s, e);
 
 #else
 
@@ -374,6 +375,7 @@
 												acpi_os_printf ACPI_PARAM_LIST(fp);}
 #define ACPI_REPORT_WARNING(fp)             {acpi_ut_report_warning("ACPI",__LINE__,_COMPONENT); \
 												acpi_os_printf ACPI_PARAM_LIST(fp);}
+#define ACPI_REPORT_NSERROR(s,e)            acpi_ns_report_error("ACPI",__LINE__,_COMPONENT, s, e);
 
 #endif
 
diff -Nru a/drivers/acpi/include/acnamesp.h b/drivers/acpi/include/acnamesp.h
--- a/drivers/acpi/include/acnamesp.h	Fri Oct 11 21:22:53 2002
+++ b/drivers/acpi/include/acnamesp.h	Fri Oct 11 21:22:53 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acnamesp.h - Namespace subcomponent prototypes and defines
- *       $Revision: 126 $
+ *       $Revision: 127 $
  *
  *****************************************************************************/
 
@@ -421,6 +421,14 @@
 u32
 acpi_ns_local (
 	acpi_object_type        type);
+
+void
+acpi_ns_report_error (
+	NATIVE_CHAR             *module_name,
+	u32                     line_number,
+	u32                     component_id,
+	char                    *internal_name,
+	acpi_status             lookup_status);
 
 acpi_status
 acpi_ns_build_internal_name (
diff -Nru a/drivers/acpi/include/acutils.h b/drivers/acpi/include/acutils.h
--- a/drivers/acpi/include/acutils.h	Fri Oct 11 21:22:51 2002
+++ b/drivers/acpi/include/acutils.h	Fri Oct 11 21:22:51 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures
- *       $Revision: 144 $
+ *       $Revision: 146 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
--- a/drivers/acpi/namespace/nsdump.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/acpi/namespace/nsdump.c	Fri Oct 11 21:23:04 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsdump - table dumping routines for debug
- *              $Revision: 140 $
+ *              $Revision: 141 $
  *
  *****************************************************************************/
 
@@ -387,6 +387,11 @@
 			break;
 
 
+		case INTERNAL_TYPE_ALIAS:
+
+			acpi_os_printf (" Target %4.4s (%p)\n", ((acpi_namespace_node *) obj_desc)->name.ascii, obj_desc);
+			break;
+
 		default:
 
 			acpi_os_printf (" Object %p\n", obj_desc);
@@ -477,9 +482,9 @@
 
 	/* If there is an attached object, display it */
 
-	dbg_level = acpi_dbg_level;
+	dbg_level    = acpi_dbg_level;
 	acpi_dbg_level = 0;
-	obj_desc = acpi_ns_get_attached_object (this_node);
+	obj_desc     = acpi_ns_get_attached_object (this_node);
 	acpi_dbg_level = dbg_level;
 
 	/* Dump attached objects */
@@ -648,7 +653,7 @@
 		 * If the name space has not been initialized,
 		 * there is nothing to dump.
 		 */
-		ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "name space not initialized!\n"));
+		ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "namespace not initialized!\n"));
 		return_VOID;
 	}
 
diff -Nru a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
--- a/drivers/acpi/namespace/nsutils.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/acpi/namespace/nsutils.c	Fri Oct 11 21:22:58 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
  *                        parents and siblings and Scope manipulation
- *              $Revision: 112 $
+ *              $Revision: 113 $
  *
  *****************************************************************************/
 
@@ -32,6 +32,54 @@
 
 #define _COMPONENT          ACPI_NAMESPACE
 	 ACPI_MODULE_NAME    ("nsutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ns_report_error
+ *
+ * PARAMETERS:  Module_name         - Caller's module name (for error output)
+ *              Line_number         - Caller's line number (for error output)
+ *              Component_id        - Caller's component ID (for error output)
+ *              Message             - Error message to use on failure
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print warning message
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_report_error (
+	NATIVE_CHAR             *module_name,
+	u32                     line_number,
+	u32                     component_id,
+	char                    *internal_name,
+	acpi_status             lookup_status)
+{
+	acpi_status             status;
+	char                    *name;
+
+
+	status = acpi_ns_externalize_name (ACPI_UINT32_MAX, internal_name, NULL, &name);
+
+	acpi_os_printf ("%8s-%04d: *** Error: Looking up ",
+		module_name, line_number);
+
+	if (name) {
+		acpi_os_printf ("[%s]", name);
+	}
+	else {
+		acpi_os_printf ("[COULD NOT EXTERNALIZE NAME]");
+	}
+
+	acpi_os_printf (" in namespace, %s\n",
+		acpi_format_exception (lookup_status));
+
+	if (name) {
+		ACPI_MEM_FREE (name);
+	}
+}
 
 
 /*******************************************************************************
diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c
--- a/drivers/acpi/osl.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/acpi/osl.c	Fri Oct 11 21:23:03 2002
@@ -38,15 +38,10 @@
 #include "acpi.h"
 
 #ifdef CONFIG_ACPI_EFI
-#include <asm/efi.h>
+#include <linux/efi.h>
 u64 efi_mem_attributes (u64 phys_addr);
 #endif
 
-#ifdef CONFIG_IA64
-#include <asm/hw_irq.h>
-#include <asm/delay.h>
-#endif
-
 
 #define _COMPONENT		ACPI_OS_SERVICES
 ACPI_MODULE_NAME	("osl")
@@ -167,10 +162,10 @@
 acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size, void **virt)
 {
 #ifdef CONFIG_ACPI_EFI
-	if (!(EFI_MEMORY_WB & efi_mem_attributes(phys))) {
-		*virt = ioremap(phys, size);
-	} else {
+	if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
 		*virt = phys_to_virt(phys);
+	} else {
+		*virt = ioremap(phys, size);
 	}
 #else
 	if (phys > ULONG_MAX) {
@@ -342,8 +337,7 @@
 
 	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
 		virt_addr = phys_to_virt(phys_addr);
-	}
-	else {
+	} else {
 		iomem = 1;
 		virt_addr = ioremap(phys_addr, width);
 	}
@@ -388,8 +382,7 @@
 
 	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
 		virt_addr = phys_to_virt(phys_addr);
-	}
-	else {
+	} else {
 		iomem = 1;
 		virt_addr = ioremap(phys_addr, width);
 	}
diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
--- a/drivers/acpi/pci_irq.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/acpi/pci_irq.c	Fri Oct 11 21:22:57 2002
@@ -33,7 +33,9 @@
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#ifdef CONFIG_X86_IO_APIC
 #include <asm/mpspec.h>
+#endif
 #include "acpi_bus.h"
 #include "acpi_drivers.h"
 
@@ -387,6 +389,10 @@
 	/* Program IOAPICs using data from PRT entries. */
 	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
 		mp_parse_prt();
+#endif
+#ifdef CONFIG_IOSAPIC
+	if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
+		iosapic_parse_prt();
 #endif
 
 	pci_for_each_dev(dev)
diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c
--- a/drivers/acpi/processor.c	Fri Oct 11 21:23:01 2002
+++ b/drivers/acpi/processor.c	Fri Oct 11 21:23:01 2002
@@ -1478,6 +1478,12 @@
 	 * performance state.
 	 */
 
+	px = pr->limit.thermal.px;
+	tx = pr->limit.thermal.tx;
+
+	px = pr->limit.thermal.px;
+	tx = pr->limit.thermal.tx;
+
 	switch (type) {
 
 	case ACPI_PROCESSOR_LIMIT_NONE:
diff -Nru a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
--- a/drivers/acpi/sleep.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/acpi/sleep.c	Fri Oct 11 21:22:51 2002
@@ -330,7 +330,7 @@
 	
 	state = simple_strtoul(state_string, NULL, 0);
 	
-	if (sleep_states[state])
+	if (!sleep_states[state])
 		return_VALUE(-ENODEV);
 
 #ifdef CONFIG_SOFTWARE_SUSPEND
diff -Nru a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
--- a/drivers/acpi/tables/tbxface.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/acpi/tables/tbxface.c	Fri Oct 11 21:23:03 2002
@@ -2,7 +2,7 @@
  *
  * Module Name: tbxface - Public interfaces to the ACPI subsystem
  *                         ACPI table oriented interfaces
- *              $Revision: 58 $
+ *              $Revision: 59 $
  *
  *****************************************************************************/
 
@@ -96,7 +96,7 @@
 		goto error_exit;
 	}
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_OK, "ACPI Tables successfully loaded\n"));
+	ACPI_DEBUG_PRINT ((ACPI_DB_OK, "ACPI Tables successfully acquired\n"));
 
 
 	/* Load the namespace from the tables */
diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
--- a/drivers/acpi/thermal.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/acpi/thermal.c	Fri Oct 11 21:22:55 2002
@@ -62,7 +62,8 @@
 
 #define ACPI_THERMAL_MAX_ACTIVE	10
 
-#define KELVIN_TO_CELSIUS(t)	((t-2732+5)/10)
+#define KELVIN_TO_CELSIUS(t)    (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
+#define CELSIUS_TO_KELVIN(t)	((t+273)*10)
 
 #define _COMPONENT		ACPI_THERMAL_COMPONENT
 ACPI_MODULE_NAME		("acpi_thermal")
@@ -789,7 +790,7 @@
 	if (result)
 		goto end;
 
-	p += sprintf(p, "temperature:             %lu C\n", 
+	p += sprintf(p, "temperature:             %ld C\n", 
 		KELVIN_TO_CELSIUS(tz->temperature));
 	
 end:
@@ -825,15 +826,15 @@
 		goto end;
 
 	if (tz->trips.critical.flags.valid)
-		p += sprintf(p, "critical (S5):           %lu C\n",
+		p += sprintf(p, "critical (S5):           %ld C\n",
 			KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
 
 	if (tz->trips.hot.flags.valid)
-		p += sprintf(p, "hot (S4):                %lu C\n",
+		p += sprintf(p, "hot (S4):                %ld C\n",
 			KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
 
 	if (tz->trips.passive.flags.valid) {
-		p += sprintf(p, "passive:                 %lu C: tc1=%lu tc2=%lu tsp=%lu devices=",
+		p += sprintf(p, "passive:                 %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
 			KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
 			tz->trips.passive.tc1,
 			tz->trips.passive.tc2, 
@@ -848,7 +849,7 @@
 	for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
 		if (!(tz->trips.active[i].flags.valid))
 			break;
-		p += sprintf(p, "active[%d]:               %lu C: devices=",
+		p += sprintf(p, "active[%d]:               %ld C: devices=",
 			i, KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
 		for (j=0; j<tz->trips.active[i].devices.count; j++) 
 			p += sprintf(p, "0x%p ",
@@ -869,6 +870,46 @@
 
 
 static int
+acpi_thermal_write_trip_points (
+        struct file		*file,
+        const char		*buffer,
+        unsigned long		count,
+        void			*data)
+{
+	struct acpi_thermal	*tz = (struct acpi_thermal *) data;
+	char			limit_string[25] = {'\0'};
+	int			critical, hot, passive, active0, active1;
+
+	ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points");
+
+	if (!tz || (count > sizeof(limit_string) - 1)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
+		return_VALUE(-EINVAL);
+	}
+	
+	if (copy_from_user(limit_string, buffer, count)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
+		return_VALUE(-EFAULT);
+	}
+	
+	limit_string[count] = '\0';
+
+	if (sscanf(limit_string, "%d:%d:%d:%d:%d", &critical, &hot, &passive, &active0, &active1) != 5) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
+		return_VALUE(-EINVAL);
+	}
+
+	tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
+	tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
+	tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
+	tz->trips.active[0].temperature = CELSIUS_TO_KELVIN(active0);
+	tz->trips.active[1].temperature = CELSIUS_TO_KELVIN(active1);
+	
+	return_VALUE(count);
+}
+
+
+static int
 acpi_thermal_read_cooling_mode (
 	char			*page,
 	char			**start,
@@ -1057,15 +1098,16 @@
 		entry->data = acpi_driver_data(device);
 	}
 
-	/* 'trip_points' [R] */
+	/* 'trip_points' [R/W] */
 	entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
-		S_IRUGO, acpi_device_dir(device));
+		S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
 	if (!entry)
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 			"Unable to create '%s' fs entry\n",
 			ACPI_THERMAL_FILE_POLLING_FREQ));
 	else {
 		entry->read_proc = acpi_thermal_read_trip_points;
+		entry->write_proc = acpi_thermal_write_trip_points;
 		entry->data = acpi_driver_data(device);
 	}
 
@@ -1233,6 +1275,8 @@
 	if (result)
 		return_VALUE(result);
 
+	init_timer(&tz->timer);
+
 	acpi_thermal_check(tz);
 
 	status = acpi_install_notify_handler(tz->handle,
@@ -1244,9 +1288,7 @@
 		goto end;
 	}
 
-	init_timer(&tz->timer);
-
-	printk(KERN_INFO PREFIX "%s [%s] (%lu C)\n",
+	printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
 		acpi_device_name(device), acpi_device_bid(device),
 		KELVIN_TO_CELSIUS(tz->temperature));
 
diff -Nru a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
--- a/drivers/acpi/utilities/utmisc.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/acpi/utilities/utmisc.c	Fri Oct 11 21:22:53 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: utmisc - common utility procedures
- *              $Revision: 81 $
+ *              $Revision: 84 $
  *
  ******************************************************************************/
 
diff -Nru a/drivers/acpi/utils.c b/drivers/acpi/utils.c
--- a/drivers/acpi/utils.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/acpi/utils.c	Fri Oct 11 21:23:05 2002
@@ -39,7 +39,7 @@
                             Object Evaluation Helpers
    -------------------------------------------------------------------------- */
 
-#ifdef ACPI_DEBUG
+#ifdef ACPI_DEBUG_OUTPUT
 #define acpi_util_eval_error(h,p,s) {\
 	char prefix[80] = {'\0'};\
 	acpi_buffer buffer = {sizeof(prefix), prefix};\
diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile
--- a/drivers/atm/Makefile	Fri Oct 11 21:22:51 2002
+++ b/drivers/atm/Makefile	Fri Oct 11 21:22:51 2002
@@ -2,61 +2,50 @@
 # Makefile for the Linux network (ATM) device drivers.
 #
 
-export-objs := uPD98402.o suni.o idt77105.o
+EXTRA_CFLAGS := -g
+
+export-objs	:= uPD98402.o suni.o idt77105.o
+fore_200e-objs	:= fore200e.o
+host-progs	:= fore200e_mkfirm
 
-obj-y := atmdev_init.o
 
-obj-$(CONFIG_ATM_ENI) += eni.o suni.o
-obj-$(CONFIG_ATM_ZATM) += zatm.o uPD98402.o
-obj-$(CONFIG_ATM_NICSTAR) += nicstar.o
-obj-$(CONFIG_ATM_IDT77252) += idt77252.o
+obj-$(CONFIG_ATM_ZATM)		+= zatm.o uPD98402.o
+obj-$(CONFIG_ATM_NICSTAR)	+= nicstar.o
+obj-$(CONFIG_ATM_AMBASSADOR)	+= ambassador.o
+obj-$(CONFIG_ATM_HORIZON)	+= horizon.o
+obj-$(CONFIG_ATM_IA)		+= iphase.o suni.o
+obj-$(CONFIG_ATM_FORE200E)	+= fore_200e.o
+obj-$(CONFIG_ATM_ENI)		+= eni.o suni.o
+obj-$(CONFIG_ATM_IDT77252)	+= idt77252.o
 
 ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
-  obj-$(CONFIG_ATM_NICSTAR) += suni.o
+  obj-$(CONFIG_ATM_NICSTAR)	+= suni.o
 endif
-
 ifeq ($(CONFIG_ATM_NICSTAR_USE_IDT77105),y)
-  obj-$(CONFIG_ATM_NICSTAR) += idt77105.o
+  obj-$(CONFIG_ATM_NICSTAR)	+= idt77105.o
 endif
-
 ifeq ($(CONFIG_ATM_IDT77252_USE_SUNI),y)
-  obj-$(CONFIG_ATM_IDT77252) += suni.o
+  obj-$(CONFIG_ATM_IDT77252)	+= suni.o
 endif
 
-obj-$(CONFIG_ATM_HORIZON) += horizon.o
-obj-$(CONFIG_ATM_AMBASSADOR) += ambassador.o
-obj-$(CONFIG_ATM_TCP) += atmtcp.o
-obj-$(CONFIG_ATM_IA) += iphase.o suni.o
-obj-$(CONFIG_ATM_FIRESTREAM) += firestream.o
-obj-$(CONFIG_ATM_LANAI) += lanai.o
+obj-$(CONFIG_ATM_TCP)		+= atmtcp.o
+obj-$(CONFIG_ATM_FIRESTREAM)	+= firestream.o
+obj-$(CONFIG_ATM_LANAI)		+= lanai.o
 
 ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
-  FORE200E_FW_OBJS += fore200e_pca_fw.o
-  ifeq ($(strip $(CONFIG_ATM_FORE200E_PCA_FW)),"")
-    CONFIG_ATM_FORE200E_PCA_DEFAULT_FW := y
-  endif
+  fore_200e-objs		+= fore200e_pca_fw.o
+  # guess the target endianess to choose the right PCA-200E firmware image
   ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
-#   guess the target endianess to choose the right PCA-200E firmware image
-    CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi)
+    CONFIG_ATM_FORE200E_PCA_FW = $(shell if test -n "`$(CC) -E -dM $(src)/../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi)
   endif
 endif
+
 ifeq ($(CONFIG_ATM_FORE200E_SBA),y)
-  FORE200E_FW_OBJS += fore200e_sba_fw.o
-  ifeq ($(strip $(CONFIG_ATM_FORE200E_SBA_FW)),"")
-    CONFIG_ATM_FORE200E_SBA_DEFAULT_FW := y
-  endif
+  fore_200e-objs		+= fore200e_sba_fw.o
   ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y)
-    CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2
+    CONFIG_ATM_FORE200E_SBA_FW	:= sba200e_ecd.bin2
   endif
 endif
-
-obj-$(CONFIG_ATM_FORE200E) += fore_200e.o
-
-fore_200e-objs	:= fore200e.o $(FORE200E_FW_OBJS)
-
-host-progs := fore200e_mkfirm
-
-EXTRA_CFLAGS := -g
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
--- a/drivers/atm/ambassador.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/atm/ambassador.c	Fri Oct 11 21:22:53 2002
@@ -2576,7 +2576,6 @@
 
 /********** module stuff **********/
 
-#ifdef MODULE
 MODULE_AUTHOR(maintainer_string);
 MODULE_DESCRIPTION(description_string);
 MODULE_LICENSE("GPL");
@@ -2597,7 +2596,7 @@
 
 /********** module entry **********/
 
-int init_module (void) {
+static int __init amb_module_init (void) {
   int devs;
   
   PRINTD (DBG_FLOW|DBG_INIT, "init_module");
@@ -2631,7 +2630,7 @@
 
 /********** module exit **********/
 
-void cleanup_module (void) {
+static void __exit amb_module_exit (void) {
   amb_dev * dev;
   
   PRINTD (DBG_FLOW|DBG_INIT, "cleanup_module");
@@ -2659,38 +2658,5 @@
   return;
 }
 
-#else
-
-/********** monolithic entry **********/
-
-int __init amb_detect (void) {
-  int devs;
-  
-  // sanity check - cast needed as printk does not support %Zu
-  if (sizeof(amb_mem) != 4*16 + 4*12) {
-    PRINTK (KERN_ERR, "Fix amb_mem (is %lu words).",
-	    (unsigned long) sizeof(amb_mem));
-    return 0;
-  }
-  
-  show_version();
-  
-  amb_check_args();
-  
-  // get the juice
-  devs = amb_probe();
-  
-  if (devs) {
-    init_timer (&housekeeping);
-    housekeeping.function = do_housekeeping;
-    // paranoia
-    housekeeping.data = 1;
-    set_timer (&housekeeping, 0);
-  } else {
-    PRINTK (KERN_INFO, "no (usable) adapters found");
-  }
-  
-  return devs;
-}
-
-#endif
+module_init(amb_module_init);
+module_exit(amb_module_exit);
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/atm/eni.c	Fri Oct 11 21:22:54 2002
@@ -906,7 +906,7 @@
 	struct eni_dev *eni_dev;
 
 	eni_dev = ENI_DEV(dev);
-	eni_dev->rx_map = (struct atm_vcc **) get_free_page(GFP_KERNEL);
+	eni_dev->rx_map = (struct atm_vcc **) get_zeroed_page(GFP_KERNEL);
 	if (!eni_dev->rx_map) {
 		printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n",
 		    dev->number);
diff -Nru a/drivers/atm/firestream.c b/drivers/atm/firestream.c
--- a/drivers/atm/firestream.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/atm/firestream.c	Fri Oct 11 21:22:54 2002
@@ -330,8 +330,8 @@
 #define FS_DEBUG_QSIZE   0x00001000
 
 
-#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter " __FUNCTION__ "\n")
-#define func_exit()  fs_dprintk (FS_DEBUG_FLOW, "fs: exit  " __FUNCTION__ "\n")
+#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter %s\n", __FUNCTION__)
+#define func_exit()  fs_dprintk (FS_DEBUG_FLOW, "fs: exit  %s\n", __FUNCTION__)
 
 
 struct fs_dev *fs_boards = NULL;
@@ -814,7 +814,7 @@
 				skb_put (skb, qe->p1 & 0xffff); 
 				ATM_SKB(skb)->vcc = atm_vcc;
 				atomic_inc(&atm_vcc->stats->rx);
-				skb->stamp = xtime;
+				do_gettimeofday(&skb->stamp);
 				fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p (pushed)\n", skb);
 				atm_vcc->push (atm_vcc, skb);
 				fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", pe);
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/atm/fore200e.c	Fri Oct 11 21:23:05 2002
@@ -96,11 +96,9 @@
 static struct fore200e* fore200e_boards = NULL;
 
 
-#ifdef MODULE
 MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");
 MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION);
 MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E");
-#endif
 
 
 static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = {
@@ -2583,9 +2581,8 @@
     return 0;
 }
 
-
-int __init
-fore200e_detect(void)
+static int __init
+fore200e_module_init(void)
 {
     const struct fore200e_bus* bus;
     struct       fore200e*     fore200e;
@@ -2618,23 +2615,24 @@
 	}
     }
 
-    return link;
+    if (link)
+        return 0;
+    return -ENODEV;
 }
 
 
-#ifdef MODULE
-static void
-fore200e_cleanup(struct fore200e** head)
+static void __exit
+fore200e_module_cleanup(void)
 {
-    struct fore200e* fore200e = *head;
-
-    fore200e_shutdown(fore200e);
-
-    *head = fore200e->next;
+    while (fore200e_boards) {
+        struct fore200e* fore200e = fore200e_boards;
 
-    kfree(fore200e);
+	fore200e_shutdown(fore200e);
+	fore200e_boards = fore200e->next;
+	kfree(fore200e);
+    }
+    DPRINTK(1, "module being removed\n");
 }
-#endif
 
 
 static int
@@ -2907,27 +2905,8 @@
     return 0;
 }
 
-
-#ifdef MODULE
-static int __init
-fore200e_module_init(void)
-{
-    DPRINTK(1, "module loaded\n");
-    return fore200e_detect() == 0;
-}
-
-static void __exit
-fore200e_module_cleanup(void)
-{
-    while (fore200e_boards) {
-	fore200e_cleanup(&fore200e_boards);
-    }
-    DPRINTK(1, "module being removed\n");
-}
-
 module_init(fore200e_module_init);
 module_exit(fore200e_module_cleanup);
-#endif
 
 
 static const struct atmdev_ops fore200e_ops =
diff -Nru a/drivers/atm/horizon.c b/drivers/atm/horizon.c
--- a/drivers/atm/horizon.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/atm/horizon.c	Fri Oct 11 21:22:50 2002
@@ -2927,7 +2927,6 @@
   return;
 }
 
-#ifdef MODULE
 MODULE_AUTHOR(maintainer_string);
 MODULE_DESCRIPTION(description_string);
 MODULE_LICENSE("GPL");
@@ -2944,7 +2943,7 @@
 
 /********** module entry **********/
 
-int init_module (void) {
+static int __init hrz_module_init (void) {
   int devs;
   
   // sanity check - cast is needed since printk does not support %Zu
@@ -2977,7 +2976,7 @@
 
 /********** module exit **********/
 
-void cleanup_module (void) {
+static void __exit hrz_module_exit (void) {
   hrz_dev * dev;
   PRINTD (DBG_FLOW, "cleanup_module");
   
@@ -3000,40 +2999,5 @@
   return;
 }
 
-#else
-
-/********** monolithic entry **********/
-
-int __init hrz_detect (void) {
-  int devs;
-  
-  // sanity check - cast is needed since printk does not support %Zu
-  if (sizeof(struct MEMMAP) != 128*1024/4) {
-    PRINTK (KERN_ERR, "Fix struct MEMMAP (is %lu fakewords).",
-	    (unsigned long) sizeof(struct MEMMAP));
-    return 0;
-  }
-  
-  show_version();
-  
-  // what about command line arguments?
-  // check arguments
-  hrz_check_args();
-  
-  // get the juice
-  devs = hrz_probe();
-  
-  if (devs) {
-    init_timer (&housekeeping);
-    housekeeping.function = do_housekeeping;
-    // paranoia
-    housekeeping.data = 1;
-    set_timer (&housekeeping, 0);
-  } else {
-    PRINTK (KERN_ERR, "no (usable) adapters found");
-  }
-
-  return devs;
-}
-
-#endif
+module_init(hrz_module_init);
+module_exit(hrz_module_exit);
diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c
--- a/drivers/atm/iphase.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/atm/iphase.c	Fri Oct 11 21:23:04 2002
@@ -40,9 +40,6 @@
 
 *******************************************************************************/
 
-#ifdef IA_MODULE
-#define MODULE
-#endif
 #include <linux/version.h>
 #include <linux/module.h>  
 #include <linux/kernel.h>  
@@ -88,13 +85,11 @@
 static u32 IADebugFlag = /* IF_IADBG_ERR | IF_IADBG_CBR| IF_IADBG_INIT_ADAPTER
             |IF_IADBG_ABR | IF_IADBG_EVENT*/ 0; 
 
-#ifdef MODULE
 MODULE_PARM(IA_TX_BUF, "i");
 MODULE_PARM(IA_TX_BUF_SZ, "i");
 MODULE_PARM(IA_RX_BUF, "i");
 MODULE_PARM(IA_RX_BUF_SZ, "i");
 MODULE_PARM(IADebugFlag, "i");
-#endif
 
 MODULE_LICENSE("GPL");
 
@@ -1162,10 +1157,7 @@
 	   goto out_free_desc;
         }
 		  
-#if LINUX_VERSION_CODE >= 0x20312
         if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) {
-#else
-        if (atm_charge(vcc, atm_pdu2truesize(len))) {
 	   /* lets allocate an skb for now */  
 	   skb = alloc_skb(len, GFP_ATOMIC);  
 	   if (!skb)  
@@ -1178,7 +1170,6 @@
         }
         else {
            IF_EVENT(printk("IA: Rx over the rx_quota %ld\n", vcc->rx_quota);)
-#endif
            if (vcc->vci < 32)
               printk("Drop control packets\n");
 	      goto out_free_desc;
@@ -1323,11 +1314,7 @@
           {
              atomic_inc(&vcc->stats->rx_err);
              dev_kfree_skb_any(skb);
-#if LINUX_VERSION_CODE >= 0x20312
              atm_return(vcc, atm_guess_pdu2truesize(len));
-#else
-             atm_return(vcc, atm_pdu2truesize(len));
-#endif
              goto INCR_DLE;
            }
           // get real pkt length  pwang_test
@@ -1341,11 +1328,7 @@
              IF_ERR(printk("rx_dle_intr: Bad  AAL5 trailer %d (skb len %d)", 
                                                             length, skb->len);)
              dev_kfree_skb_any(skb);
-#if LINUX_VERSION_CODE >= 0x20312
              atm_return(vcc, atm_guess_pdu2truesize(len));
-#else
-             atm_return(vcc, atm_pdu2truesize(len));
-#endif 
              goto INCR_DLE;
           }
           skb_trim(skb, length);
@@ -2001,6 +1984,10 @@
         }
         iadev->desc_tbl = kmalloc(iadev->num_tx_desc *
                                    sizeof(struct desc_tbl_t), GFP_KERNEL);
+	if (!iadev->desc_tbl) {
+		printk(KERN_ERR DEV_LABEL " couldn't get mem\n");
+		return -EAGAIN;
+	}
   
 	/* Communication Queues base address */  
         i = TX_COMP_Q * iadev->memSize;
@@ -2164,13 +2151,8 @@
         writew(0xaa00, iadev->seg_reg+ABRUBR_ARB); 
 
         iadev->close_pending = 0;
-#if LINUX_VERSION_CODE >= 0x20303
         init_waitqueue_head(&iadev->close_wait);
         init_waitqueue_head(&iadev->timeout_wait);
-#else
-        iadev->close_wait = NULL;
-        iadev->timeout_wait = NULL;
-#endif 
 	skb_queue_head_init(&iadev->tx_dma_q);  
 	ia_init_rtn_q(&iadev->tx_return_q);  
 
@@ -2282,11 +2264,7 @@
 }  
 	  
 	  
-#if LINUX_VERSION_CODE >= 0x20312
 static int __init ia_init(struct atm_dev *dev)
-#else
-__initfunc(static int ia_init(struct atm_dev *dev))
-#endif  
 {  
 	IADEV *iadev;  
 	unsigned long real_base, base;  
@@ -2455,11 +2433,7 @@
 	return readl(INPH_IA_DEV(dev)->phy+addr);  
 }  
 
-#if LINUX_VERSION_CODE >= 0x20312
 static int __init ia_start(struct atm_dev *dev)
-#else
-__initfunc(static int ia_start(struct atm_dev *dev))
-#endif  
 {  
 	IADEV *iadev;  
 	int error = 1;  
@@ -2555,7 +2529,7 @@
            SUNI_RSOP_CIE_LOSE - 0x04
         */
         ia_phy_put(dev, ia_phy_get(dev,0x10) | 0x04, 0x10);         
-#ifndef MODULE
+#if 0
 	error = dev->phy->start(dev);  
 	if (error) {
           free_irq(iadev->irq, dev);
@@ -2705,7 +2679,7 @@
   
 	set_bit(ATM_VF_READY,&vcc->flags);
 
-#ifndef MODULE
+#if 0
         {
            static u8 first = 1; 
            if (first) {
@@ -3163,11 +3137,7 @@
 };  
 	  
   
-#if LINUX_VERSION_CODE >= 0x20312
-int __init ia_detect(void)
-#else
-__initfunc(int ia_detect(void)) 
-#endif 
+static int __init ia_detect(void)
 {  
 	struct atm_dev *dev;  
 	IADEV *iadev;  
@@ -3224,10 +3194,7 @@
 	return index;  
 }  
   
-
-#ifdef MODULE  
-  
-int init_module(void)  
+static int __init ia_module_init(void)
 {  
 	IF_EVENT(printk(">ia init_module\n");)  
 	if (!ia_detect()) {  
@@ -3241,7 +3208,7 @@
 }  
   
   
-void cleanup_module(void)  
+static void __exit ia_module_exit(void)
 {  
 	struct atm_dev *dev;  
 	IADEV *iadev;  
@@ -3291,7 +3258,7 @@
                ia_dev[i] =  NULL;
               _ia_dev[i] = NULL;
         }
-}  
-
-#endif  
+}
 
+module_init(ia_module_init);
+module_exit(ia_module_exit);
diff -Nru a/drivers/atm/lanai.c b/drivers/atm/lanai.c
--- a/drivers/atm/lanai.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/atm/lanai.c	Fri Oct 11 21:22:55 2002
@@ -1624,7 +1624,7 @@
 
 /* -------------------- MANAGING HOST-BASED VCC TABLE: */
 
-/* Decide whether to use vmalloc or get_free_page for VCC table */
+/* Decide whether to use vmalloc or get_zeroed_page for VCC table */
 #if (NUM_VCI * BITS_PER_LONG) <= PAGE_SIZE
 #define VCCTABLE_GETFREEPAGE
 #else
@@ -1636,7 +1636,7 @@
 #ifdef VCCTABLE_GETFREEPAGE
 	APRINTK((lanai->num_vci) * sizeof(struct lanai_vcc *) <= PAGE_SIZE,
 	    "vcc table > PAGE_SIZE!");
-	lanai->vccs = (struct lanai_vcc **) get_free_page(GFP_KERNEL);
+	lanai->vccs = (struct lanai_vcc **) get_zeroed_page(GFP_KERNEL);
 	return (lanai->vccs == NULL) ? -ENOMEM : 0;
 #else
 	int bytes = (lanai->num_vci) * sizeof(struct lanai_vcc *);
@@ -2882,27 +2882,16 @@
 	return count;
 }
 
-#ifdef MODULE
-static
-#endif
-int __init lanai_detect(void)
-{
-	return lanai_detect_1(PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAI2) +
-	       lanai_detect_1(PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAIHB);
-}
-
-#ifdef MODULE
-
-int init_module(void)
+static int __init lanai_module_init(void)
 {
-	if (lanai_detect() == 0) {
-		printk(KERN_ERR DEV_LABEL ": no adaptor found\n");
-		return -ENODEV;
-	}
-	return 0;
+	if (lanai_detect_1(PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAI2) +
+	    lanai_detect_1(PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAIHB))
+		return 0;
+	printk(KERN_ERR DEV_LABEL ": no adaptor found\n");
+	return -ENODEV;
 }
 
-void cleanup_module(void)
+static void __exit lanai_module_exit(void)
 {
 	/* We'll only get called when all the interfaces are already
 	 * gone, so there isn't much to do
@@ -2910,8 +2899,9 @@
 	DPRINTK("cleanup_module()\n");
 }
 
+module_init(lanai_module_init);
+module_exit(lanai_module_exit);
+
 MODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>");
 MODULE_DESCRIPTION("Efficient Networks Speedstream 3010 driver");
 MODULE_LICENSE("GPL");
-
-#endif /* MODULE */
diff -Nru a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
--- a/drivers/atm/nicstar.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/atm/nicstar.c	Fri Oct 11 21:22:54 2002
@@ -276,15 +276,13 @@
 
 /* Functions*******************************************************************/
 
-#ifdef MODULE
-
-int __init init_module(void)
+static int __init nicstar_module_init(void)
 {
    int i;
    unsigned error = 0;	/* Initialized to remove compile warning */
    struct pci_dev *pcidev;
 
-   XPRINTK("nicstar: init_module() called.\n");
+   XPRINTK("nicstar: nicstar_module_init() called.\n");
    if(!pci_present())
    {
       printk("nicstar: no PCI subsystem found.\n");
@@ -323,7 +321,7 @@
 #ifdef PHY_LOOPBACK
    printk("nicstar: using PHY loopback.\n");
 #endif /* PHY_LOOPBACK */
-   XPRINTK("nicstar: init_module() returned.\n");
+   XPRINTK("nicstar: nicstar_module_init() returned.\n");
 
    init_timer(&ns_timer);
    ns_timer.expires = jiffies + NS_POLL_PERIOD;
@@ -335,7 +333,7 @@
 
 
 
-void cleanup_module(void)
+static void __exit nicstar_module_exit(void)
 {
    int i, j;
    unsigned short pci_command;
@@ -419,60 +417,6 @@
    XPRINTK("nicstar: cleanup_module() returned.\n");
 }
 
-
-#else
-
-int __init nicstar_detect(void)
-{
-   int i;
-   unsigned error = 0;	/* Initialized to remove compile warning */
-   struct pci_dev *pcidev;
-
-   if(!pci_present())
-   {
-      printk("nicstar: no PCI subsystem found.\n");
-      return -EIO;
-   }
-
-   for(i = 0; i < NS_MAX_CARDS; i++)
-      cards[i] = NULL;
-
-   pcidev = NULL;
-   for(i = 0; i < NS_MAX_CARDS; i++)
-   {
-      if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT,
-                                    PCI_DEVICE_ID_IDT_IDT77201,
-                                    pcidev)) == NULL)
-         break;
-
-      error = ns_init_card(i, pcidev);
-      if (error)
-         cards[i--] = NULL;	/* Try to find another card but don't increment index */
-   }
-
-   if (i == 0 && error)
-      return -EIO;
-
-   TXPRINTK("nicstar: TX debug enabled.\n");
-   RXPRINTK("nicstar: RX debug enabled.\n");
-   PRINTK("nicstar: General debug enabled.\n");
-#ifdef PHY_LOOPBACK
-   printk("nicstar: using PHY loopback.\n");
-#endif /* PHY_LOOPBACK */
-   XPRINTK("nicstar: init_module() returned.\n");
-
-   init_timer(&ns_timer);
-   ns_timer.expires = jiffies + NS_POLL_PERIOD;
-   ns_timer.data = 0UL;
-   ns_timer.function = ns_poll;
-   add_timer(&ns_timer);
-   return i;
-}
-
-
-#endif /* MODULE */
-
-
 static u32 ns_read_sram(ns_dev *card, u32 sram_address)
 {
    unsigned long flags;
@@ -3156,3 +3100,6 @@
    spin_unlock_irqrestore(&card->res_lock, flags);
    return (unsigned char) data;
 }
+
+module_init(nicstar_module_init);
+module_exit(nicstar_module_exit);
diff -Nru a/drivers/atm/zatm.c b/drivers/atm/zatm.c
--- a/drivers/atm/zatm.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/atm/zatm.c	Fri Oct 11 21:22:54 2002
@@ -1806,8 +1806,7 @@
 	.change_qos	= zatm_change_qos,
 };
 
-
-int __init zatm_detect(void)
+static int __init zatm_module_init(void)
 {
 	struct atm_dev *dev;
 	struct zatm_dev *zatm_dev;
@@ -1841,36 +1840,18 @@
 			    zatm_dev),GFP_KERNEL);
 			if (!zatm_dev) {
 				printk(KERN_EMERG "zatm.c: memory shortage\n");
-				return devs;
+				goto out;
 			}
 		}
 	}
+out:
 	kfree(zatm_dev);
-	return devs;
-}
-
 
-#ifdef MODULE
- 
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
-	if (!zatm_detect()) {
-		printk(KERN_ERR DEV_LABEL ": no adapter found\n");
-		return -ENXIO;
-	}
+	/* XXX: currently the driver is not unloadable.. */
 	MOD_INC_USE_COUNT;
 	return 0;
 }
- 
- 
-void cleanup_module(void)
-{
-	/*
-	 * Well, there's no way to get rid of the driver yet, so we don't
-	 * have to clean up, right ? :-)
-	 */
-}
- 
-#endif
+
+MODULE_LICENSE("GPL");
+
+module_init(zatm_module_init);
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/base/core.c	Fri Oct 11 21:22:52 2002
@@ -175,7 +175,7 @@
 	INIT_LIST_HEAD(&dev->intf_list);
 	spin_lock_init(&dev->lock);
 	atomic_set(&dev->refcount,2);
-	
+	dev->present = 1;
 	spin_lock(&device_lock);
 	if (dev->parent) {
 		get_device_locked(dev->parent);
@@ -219,7 +219,7 @@
 struct device * get_device_locked(struct device * dev)
 {
 	struct device * ret = dev;
-	if (dev && atomic_read(&dev->refcount) > 0)
+	if (dev && dev->present && atomic_read(&dev->refcount) > 0)
 		atomic_inc(&dev->refcount);
 	else
 		ret = NULL;
@@ -241,8 +241,35 @@
  */
 void put_device(struct device * dev)
 {
+	struct device * parent;
 	if (!atomic_dec_and_lock(&dev->refcount,&device_lock))
 		return;
+	parent = dev->parent;
+	dev->parent = NULL;
+	spin_unlock(&device_lock);
+
+	BUG_ON(dev->present);
+
+	if (dev->release)
+		dev->release(dev);
+
+	if (parent)
+		put_device(parent);
+}
+
+/**
+ * device_unregister - unlink device
+ * @dev:	device going away
+ *
+ * The device has been removed from the system, so we disavow knowledge
+ * of it. It might not be the final reference to the device, so we mark
+ * it as !present, so no more references to it can be acquired.
+ * In the end, we decrement the final reference count for it.
+ */
+void device_unregister(struct device * dev)
+{
+	spin_lock(&device_lock);
+	dev->present = 0;
 	list_del_init(&dev->node);
 	list_del_init(&dev->g_list);
 	list_del_init(&dev->bus_list);
@@ -267,11 +294,7 @@
 	/* remove the driverfs directory */
 	device_remove_dir(dev);
 
-	if (dev->release)
-		dev->release(dev);
-
-	if (dev->parent)
-		put_device(dev->parent);
+	put_device(dev);
 }
 
 static int __init device_init(void)
@@ -287,5 +310,6 @@
 core_initcall(device_init);
 
 EXPORT_SYMBOL(device_register);
+EXPORT_SYMBOL(device_unregister);
 EXPORT_SYMBOL(get_device);
 EXPORT_SYMBOL(put_device);
diff -Nru a/drivers/base/fs/device.c b/drivers/base/fs/device.c
--- a/drivers/base/fs/device.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/base/fs/device.c	Fri Oct 11 21:22:58 2002
@@ -90,8 +90,7 @@
 {
 	int error = -EINVAL;
 
-	if (dev) {
-		get_device(dev);
+	if (get_device(dev)) {
 		error = driverfs_create_file(&entry->attr,&dev->dir);
 		put_device(dev);
 	}
diff -Nru a/drivers/base/hotplug.c b/drivers/base/hotplug.c
--- a/drivers/base/hotplug.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/base/hotplug.c	Fri Oct 11 21:22:50 2002
@@ -97,7 +97,7 @@
 	scratch += sprintf (scratch, "ACTION=%s", action) + 1;
 
 	envp [i++] = scratch;
-	scratch += sprintf (scratch, "DEVICE=%s", dev_path) + 1;
+	scratch += sprintf (scratch, "DEVPATH=%s", dev_path) + 1;
 	
 	if (dev->bus->hotplug) {
 		/* have the bus specific function add its stuff */
diff -Nru a/drivers/base/power.c b/drivers/base/power.c
--- a/drivers/base/power.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/base/power.c	Fri Oct 11 21:23:00 2002
@@ -6,8 +6,6 @@
  * 
  *  Kai Germaschewski contributed to the list walking routines.
  *
- * FIXME: The suspend and shutdown walks are identical. The resume walk
- * is simply walking the list backward. Anyway we can combine these (cleanly)?
  */
 
 #include <linux/device.h>
@@ -17,13 +15,15 @@
 #define to_dev(node) container_of(node,struct device,g_list)
 
 /**
- * device_suspend - suspend all devices on the device tree
+ * device_suspend - suspend/remove all devices on the device ree
  * @state:	state we're entering
- * @level:	what stage of the suspend process we're at 
- * 
- * The entries in the global device list are inserted such that they're in a 
- * depth-first ordering. So, simply iterate over the list, and call the driver's
- * suspend callback for each device.
+ * @level:	what stage of the suspend process we're at
+ *    (emb: it seems that these two arguments are described backwards of what
+ *          they actually mean .. is this correct?)
+ *
+ * The entries in the global device list are inserted such that they're in a
+ * depth-first ordering.  So, simply interate over the list, and call the 
+ * driver's suspend or remove callback for each device.
  */
 int device_suspend(u32 state, u32 level)
 {
@@ -31,15 +31,23 @@
 	struct device * prev = NULL;
 	int error = 0;
 
-	printk(KERN_EMERG "Suspending Devices\n");
+	if(level == SUSPEND_POWER_DOWN)
+		printk(KERN_EMERG "Shutting down devices\n");
+	else
+		printk(KERN_EMERG "Suspending devices\n");
 
 	spin_lock(&device_lock);
 	list_for_each(node,&global_device_list) {
 		struct device * dev = get_device_locked(to_dev(node));
 		if (dev) {
 			spin_unlock(&device_lock);
-			if (dev->driver && dev->driver->suspend)
-				error = dev->driver->suspend(dev,state,level);
+			if(dev->driver) {
+				if(level == SUSPEND_POWER_DOWN) {
+				       	if(dev->driver->remove)
+						dev->driver->remove(dev);
+				} else if(dev->driver->suspend) 
+					error = dev->driver->suspend(dev,state,level);
+			}
 			if (prev)
 				put_device(prev);
 			prev = dev;
@@ -83,36 +91,12 @@
 }
 
 /**
- * device_shutdown - queisce all the devices before reboot/shutdown
- *
- * Do depth first iteration over device tree, calling ->remove() for each
- * device. This should ensure the devices are put into a sane state before
- * we reboot the system.
- *
+ * device_shutdown - call device_suspend with status set to shutdown, to 
+ * cause all devices to remove themselves cleanly 
  */
 void device_shutdown(void)
 {
-	struct list_head * node, * next;
-	struct device * prev = NULL;
-
-	printk(KERN_EMERG "Shutting down devices\n");
-
-	spin_lock(&device_lock);
-	list_for_each_safe(node,next,&global_device_list) {
-		struct device * dev = get_device_locked(to_dev(node));
-		if (dev) {
-			spin_unlock(&device_lock);
-			if (dev->driver && dev->driver->remove)
-				dev->driver->remove(dev);
-			if (prev)
-				put_device(prev);
-			prev = dev;
-			spin_lock(&device_lock);
-		}
-	}
-	spin_unlock(&device_lock);
-	if (prev)
-		put_device(prev);
+	device_suspend(4, SUSPEND_POWER_DOWN);
 }
 
 EXPORT_SYMBOL(device_suspend);
diff -Nru a/drivers/block/Config.help b/drivers/block/Config.help
--- a/drivers/block/Config.help	Fri Oct 11 21:22:59 2002
+++ b/drivers/block/Config.help	Fri Oct 11 21:22:59 2002
@@ -258,3 +258,7 @@
   supported by this driver, and for further information on the use of
   this driver.
 
+CONFIG_LBD
+  Say Y here if you want to attach large (bigger than 2TB) discs to
+  your machine, or if you want to have a raid or loopback device
+  bigger than 2TB.  Otherwise say N.
diff -Nru a/drivers/block/Config.in b/drivers/block/Config.in
--- a/drivers/block/Config.in	Fri Oct 11 21:22:55 2002
+++ b/drivers/block/Config.in	Fri Oct 11 21:22:55 2002
@@ -48,4 +48,8 @@
 fi
 dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
 
+if [ "$CONFIG_X86" = "y" -o "$CONFIG_PPC32" = "y" ]; then
+#   bool 'Support for Large Block Devices' CONFIG_LBD
+   define_bool CONFIG_LBD y
+fi
 endmenu
diff -Nru a/drivers/block/blkpg.c b/drivers/block/blkpg.c
--- a/drivers/block/blkpg.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/block/blkpg.c	Fri Oct 11 21:22:52 2002
@@ -68,17 +68,22 @@
 {
 	struct gendisk *g;
 	long long ppstart, pplength;
-	long pstart, plength;
 	int part, i;
 
-	/* convert bytes to sectors, check for fit in a hd_struct */
+	/* convert bytes to sectors */
 	ppstart = (p->start >> 9);
 	pplength = (p->length >> 9);
-	pstart = ppstart;
-	plength = pplength;
-	if (pstart != ppstart || plength != pplength
-	    || pstart < 0 || plength < 0)
-		return -EINVAL;
+
+	/* check for fit in a hd_struct */ 
+	if (sizeof(sector_t) == sizeof(long) && 
+	    sizeof(long long) > sizeof(long)) {
+		long pstart, plength;
+		pstart = ppstart;
+		plength = pplength;
+		if (pstart != ppstart || plength != pplength
+		    || pstart < 0 || plength < 0)
+			return -EINVAL;
+	}
 
 	/* find the drive major */
 	g = get_gendisk(bdev->bd_dev, &part);
@@ -101,13 +106,13 @@
 
 	/* overlap? */
 	for (i = 0; i < (1<<g->minor_shift) - 1; i++)
-		if (!(pstart+plength <= g->part[i].start_sect ||
-		      pstart >= g->part[i].start_sect + g->part[i].nr_sects))
+		if (!(ppstart+pplength <= g->part[i].start_sect ||
+		      ppstart >= g->part[i].start_sect + g->part[i].nr_sects))
 			return -EBUSY;
 
 	/* all seems OK */
-	g->part[p->pno - 1].start_sect = pstart;
-	g->part[p->pno - 1].nr_sects = plength;
+	g->part[p->pno - 1].start_sect = ppstart;
+	g->part[p->pno - 1].nr_sects = pplength;
 	update_partition(g, p->pno);
 	return 0;
 }
@@ -259,10 +264,17 @@
 			intval = bdev_hardsect_size(bdev);
 			return put_user(intval, (int *) arg);
 
-		case BLKGETSIZE:
+		case BLKGETSIZE: 
+		{
+			unsigned long ret;
 			/* size in sectors, works up to 2 TB */
 			ullval = bdev->bd_inode->i_size;
-			return put_user((unsigned long)(ullval >> 9), (unsigned long *) arg);
+			ret = ullval >> 9;
+			if ((u64)ret != (ullval >> 9))
+				return -EFBIG;
+			return put_user(ret, (unsigned long *) arg);
+		}
+		
 		case BLKGETSIZE64:
 			/* size in bytes */
 			ullval = bdev->bd_inode->i_size;
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/block/cciss.c	Fri Oct 11 21:23:04 2002
@@ -175,8 +175,8 @@
                 drv = &h->drv[i];
 		if (drv->block_size == 0)
 			continue;
-                size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
-                                ctlr, i, drv->block_size, drv->nr_blocks);
+                size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%llu\n",
+                                ctlr, i, drv->block_size, (unsigned long long)drv->nr_blocks);
                 pos += size; len += size;
         }
 
@@ -405,7 +405,7 @@
                 } else {
                         driver_geo.heads = 0xff;
                         driver_geo.sectors = 0x3f;
-                        driver_geo.cylinders = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
+                        driver_geo.cylinders = (int)hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);
                 }
                 driver_geo.start= get_start_sect(inode->i_bdev);
                 if (copy_to_user((void *) arg, &driver_geo,
@@ -1179,7 +1179,7 @@
 			total_size = 0;
 			block_size = BLOCK_SIZE;
 	}	
-	printk(KERN_INFO "      blocks= %d block_size= %d\n", 
+	printk(KERN_INFO "      blocks= %u block_size= %d\n", 
 					total_size, block_size);
 	/* Execute the command to read the disk geometry */
 	memset(inq_buff, 0, sizeof(InquiryData_struct));
@@ -2274,7 +2274,7 @@
 	struct gendisk *disk[NWD];
 	int i, n;
 	for (n = 0; n < NWD; n++) {
-		disk[n] = disk_alloc();
+		disk[n] = alloc_disk();
 		if (!disk[n])
 			goto out;
 	}
diff -Nru a/drivers/block/cciss.h b/drivers/block/cciss.h
--- a/drivers/block/cciss.h	Fri Oct 11 21:22:50 2002
+++ b/drivers/block/cciss.h	Fri Oct 11 21:22:50 2002
@@ -29,7 +29,7 @@
 {
  	__u32   LunID;	
 	int 	usage_count;
-	int 	nr_blocks;
+	sector_t nr_blocks;
 	int	block_size;
 	int 	heads;
 	int	sectors;
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/block/cpqarray.c	Fri Oct 11 21:22:54 2002
@@ -200,6 +200,7 @@
 	drv_info_t *drv;
 #ifdef CPQ_PROC_PRINT_QUEUES
 	cmdlist_t *c;
+	unsigned long flags;
 #endif
 
 	ctlr = h->ctlr;
@@ -236,6 +237,7 @@
 	}
 
 #ifdef CPQ_PROC_PRINT_QUEUES
+	spin_lock_irqsave(IDA_LOCK(h->ctlr), flags); 
 	size = sprintf(buffer+len, "\nCurrent Queues:\n");
 	pos += size; len += size;
 
@@ -258,6 +260,7 @@
 	}
 
 	size = sprintf(buffer+len, "\n"); pos += size; len += size;
+	spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags); 
 #endif
 	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
 			h->nr_allocs, h->nr_frees);
@@ -355,7 +358,7 @@
 		}
 		num_cntlrs_reg++;
 		for (j=0; j<NWD; j++) {
-			ida_gendisk[i][j] = disk_alloc();
+			ida_gendisk[i][j] = alloc_disk();
 			if (!ida_gendisk[i][j])
 				goto Enomem2;
 		}
@@ -373,8 +376,6 @@
 		getgeometry(i);
 		start_fwbk(i); 
 
-		hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
-
 		ida_procinit(i);
 
 		q = BLK_DEFAULT_QUEUE(MAJOR_NR + i);
@@ -395,6 +396,9 @@
 		hba[i]->timer.function = ida_timer;
 		add_timer(&hba[i]->timer);
 
+		/* Enable IRQ now that spinlock and rate limit timer are set up */
+		hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
+
 		for(j=0; j<NWD; j++) {
 			struct gendisk *disk = ida_gendisk[i][j];
 			drv_info_t *drv = &hba[i]->drv[j];
@@ -437,7 +441,6 @@
 	}
 	return 0;
 }
-}
 
 /*
  * Find the controller and initialize it
@@ -522,6 +525,10 @@
 	int i;
 
 	c->pci_dev = pdev;
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n");
+		return -1;
+	}
 	vendor_id = pdev->vendor;
 	device_id = pdev->device;
 	irq = pdev->irq;
@@ -529,11 +536,6 @@
 	for(i=0; i<6; i++)
 		addr[i] = pci_resource_start(pdev, i);
 
-	if (pci_enable_device(pdev))
-	{
-		printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n");
-		return -1;
-	}
 	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0)
 	{
 		printk(KERN_ERR "cpqarray: Unable to set DMA mask\n");
@@ -811,8 +813,6 @@
 
 	blkdev_dequeue_request(creq);
 
-	spin_unlock_irq(q->queue_lock);
-
 	c->ctlr = h->ctlr;
 	c->hdr.unit = minor(creq->rq_dev) >> NWD_SHIFT;
 	c->hdr.size = sizeof(rblk_t) >> 2;
@@ -844,8 +844,6 @@
 	c->req.hdr.cmd = (rq_data_dir(creq) == READ) ? IDA_READ : IDA_WRITE;
 	c->type = CMD_RWREQ;
 
-	spin_lock_irq(q->queue_lock);
-
 	/* Put the request on the tail of the request queue */
 	addQ(&h->reqQ, c);
 	h->Qdepth++;
@@ -855,7 +853,6 @@
 	goto queue_next;
 
 startio:
-	__blk_stop_queue(q);
 	start_io(h);
 }
 
@@ -1008,8 +1005,8 @@
 	/*
 	 * See if we can queue up some more IO
 	 */
-	spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags);
-	blk_start_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + h->ctlr));
+	do_ida_request(BLK_DEFAULT_QUEUE(MAJOR_NR+h->ctlr));
+	spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags); 
 }
 
 /*
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/block/floppy.c	Fri Oct 11 21:22:54 2002
@@ -492,7 +492,7 @@
  */
 static struct floppy_struct user_params[N_DRIVE];
 
-static int floppy_sizes[256];
+static sector_t floppy_sizes[256];
 
 /*
  * The driver is trying to determine the correct media format
@@ -2652,8 +2652,8 @@
 
 	max_sector = _floppy->sect * _floppy->head;
 
-	TRACK = current_req->sector / max_sector;
-	fsector_t = current_req->sector % max_sector;
+	TRACK = (int)current_req->sector / max_sector;
+	fsector_t = (int)current_req->sector % max_sector;
 	if (_floppy->track && TRACK >= _floppy->track) {
 		if (current_req->current_nr_sectors & 1) {
 			current_count_sectors = 1;
@@ -2990,7 +2990,7 @@
 
 	if (usage_count == 0) {
 		printk("warning: usage count=0, current_req=%p exiting\n", current_req);
-		printk("sect=%ld flags=%lx\n", current_req->sector, current_req->flags);
+		printk("sect=%ld flags=%lx\n", (long)current_req->sector, current_req->flags);
 		return;
 	}
 	if (fdc_busy){
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/block/genhd.c	Fri Oct 11 21:22:58 2002
@@ -177,16 +177,16 @@
 		return 0;
 
 	/* show the full disk and all non-0 size partitions of it */
-	seq_printf(part, "%4d  %4d %10ld %s\n",
+	seq_printf(part, "%4d  %4d %10llu %s\n",
 		sgp->major, sgp->first_minor,
-		get_capacity(sgp) >> 1,
+		(unsigned long long)get_capacity(sgp) >> 1,
 		disk_name(sgp, 0, buf));
 	for (n = 0; n < (1<<sgp->minor_shift) - 1; n++) {
 		if (sgp->part[n].nr_sects == 0)
 			continue;
-		seq_printf(part, "%4d  %4d %10ld %s\n",
+		seq_printf(part, "%4d  %4d %10llu %s\n",
 			sgp->major, n + 1 + sgp->first_minor,
-			sgp->part[n].nr_sects >> 1 ,
+			(unsigned long long)sgp->part[n].nr_sects >> 1 ,
 			disk_name(sgp, n + 1, buf));
 	}
 
@@ -217,14 +217,6 @@
 	for (i = 0; i < MAX_BLKDEV; i++)
 		INIT_LIST_HEAD(&gendisks[i].list);
 	blk_dev_init();
-#ifdef CONFIG_FC4_SOC
-	/* This has to be done before scsi_dev_init */
-	soc_probe();
-#endif
-#ifdef CONFIG_ATM
-	(void) atmdev_init();
-#endif
-
 	devclass_register(&disk_devclass);
 	return 0;
 }
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/block/ll_rw_blk.c	Fri Oct 11 21:22:53 2002
@@ -671,7 +671,7 @@
 	} while (bit < __REQ_NR_BITS);
 
 	if (rq->flags & REQ_CMD)
-		printk("sector %lu, nr/cnr %lu/%u\n", rq->sector,
+		printk("sector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector,
 						       rq->nr_sectors,
 						       rq->current_nr_sectors);
 
@@ -1817,10 +1817,10 @@
 			 * device, e.g., when mounting a device. */
 			printk(KERN_INFO
 			       "attempt to access beyond end of device\n");
-			printk(KERN_INFO "%s: rw=%ld, want=%ld, limit=%Lu\n",
+			printk(KERN_INFO "%s: rw=%ld, want=%Lu, limit=%Lu\n",
 			       bdevname(bio->bi_bdev),
 			       bio->bi_rw,
-			       sector + nr_sectors,
+			       (unsigned long long) sector + nr_sectors,
 			       (long long) maxsector);
 
 			set_bit(BIO_EOF, &bio->bi_flags);
@@ -1849,8 +1849,10 @@
 		}
 
 		if (unlikely(bio_sectors(bio) > q->max_sectors)) {
-			printk("bio too big (%u > %u)\n", bio_sectors(bio),
-							q->max_sectors);
+			printk("bio too big device %s (%u > %u)\n", 
+			       bdevname(bio->bi_bdev),
+			       bio_sectors(bio),
+			       q->max_sectors);
 			goto end_io;
 		}
 
@@ -1953,8 +1955,8 @@
 
 	req->errors = 0;
 	if (!uptodate) {
-		printk("end_request: I/O error, dev %s, sector %lu\n",
-			kdevname(req->rq_dev), req->sector);
+		printk("end_request: I/O error, dev %s, sector %llu\n",
+			kdevname(req->rq_dev), (unsigned long long)req->sector);
 		error = -EIO;
 	}
 
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/block/loop.c	Fri Oct 11 21:22:59 2002
@@ -90,7 +90,7 @@
  * Transfer functions
  */
 static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf,
-			 char *loop_buf, int size, int real_block)
+			 char *loop_buf, int size, sector_t real_block)
 {
 	if (raw_buf != loop_buf) {
 		if (cmd == READ)
@@ -103,7 +103,7 @@
 }
 
 static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf,
-			char *loop_buf, int size, int real_block)
+			char *loop_buf, int size, sector_t real_block)
 {
 	char	*in, *out, *key;
 	int	i, keysize;
@@ -154,16 +154,25 @@
 	&xor_funcs  
 };
 
-#define MAX_DISK_SIZE 1024*1024*1024
-
-static void figure_loop_size(struct loop_device *lo)
+static int figure_loop_size(struct loop_device *lo)
 {
-	loff_t size = lo->lo_backing_file->f_dentry->d_inode->i_size;
-	set_capacity(disks[lo->lo_number], (size - lo->lo_offset) >> 9);
+	loff_t size = lo->lo_backing_file->f_dentry->d_inode->i_mapping->host->i_size;
+	sector_t x;
+	/*
+	 * Unfortunately, if we want to do I/O on the device,
+	 * the number of 512-byte sectors has to fit into a sector_t.
+	 */
+	size = (size - lo->lo_offset) >> 9;
+	x = (sector_t)size;
+	if ((loff_t)x != size)
+		return -EFBIG;
+
+	set_capacity(disks[lo->lo_number], size);
+	return 0;					
 }
 
 static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
-				 char *lbuf, int size, int rblock)
+				 char *lbuf, int size, sector_t rblock)
 {
 	if (!lo->transfer)
 		return 0;
@@ -179,18 +188,18 @@
 	struct address_space_operations *aops = mapping->a_ops;
 	struct page *page;
 	char *kaddr, *data;
-	unsigned long index;
+	pgoff_t index;
 	unsigned size, offset;
 	int len;
 	int ret = 0;
 
 	down(&mapping->host->i_sem);
 	index = pos >> PAGE_CACHE_SHIFT;
-	offset = pos & (PAGE_CACHE_SIZE - 1);
+	offset = pos & ((pgoff_t)PAGE_CACHE_SIZE - 1);
 	data = kmap(bvec->bv_page) + bvec->bv_offset;
 	len = bvec->bv_len;
 	while (len > 0) {
-		int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
+		sector_t IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
 		int transfer_result;
 
 		size = PAGE_CACHE_SIZE - offset;
@@ -209,7 +218,7 @@
 			 * The transfer failed, but we still write the data to
 			 * keep prepare/commit calls balanced.
 			 */
-			printk(KERN_ERR "loop: transfer error block %ld\n", index);
+			printk(KERN_ERR "loop: transfer error block %llu\n", (unsigned long long)index);
 			memset(kaddr + offset, 0, size);
 		}
 		flush_dcache_page(page);
@@ -700,7 +709,11 @@
 	lo->lo_backing_file = file;
 	lo->transfer = NULL;
 	lo->ioctl = NULL;
-	figure_loop_size(lo);
+	if (figure_loop_size(lo)) {
+		error = -EFBIG;
+		fput(file);
+		goto out_putf;
+	}
 	lo->old_gfp_mask = inode->i_mapping->gfp_mask;
 	inode->i_mapping->gfp_mask = GFP_NOIO;
 
@@ -820,6 +833,7 @@
 	struct loop_info info; 
 	int err;
 	unsigned int type;
+	loff_t offset;
 
 	if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && 
 	    !capable(CAP_SYS_ADMIN))
@@ -835,13 +849,23 @@
 		return -EINVAL;
 	if (type == LO_CRYPT_XOR && info.lo_encrypt_key_size == 0)
 		return -EINVAL;
+
 	err = loop_release_xfer(lo);
 	if (!err) 
 		err = loop_init_xfer(lo, type, &info);
+
+	offset = lo->lo_offset;
+	if (offset != info.lo_offset) {
+		lo->lo_offset = info.lo_offset;
+		if (figure_loop_size(lo)){
+			err = -EFBIG;
+			lo->lo_offset = offset;
+		}
+	}
+
 	if (err)
 		return err;	
 
-	lo->lo_offset = info.lo_offset;
 	strncpy(lo->lo_name, info.lo_name, LO_NAME_SIZE);
 
 	lo->transfer = xfer_funcs[type]->transfer;
@@ -854,7 +878,7 @@
 		       info.lo_encrypt_key_size);
 		lo->lo_key_owner = current->uid; 
 	}	
-	figure_loop_size(lo);
+
 	return 0;
 }
 
@@ -1059,7 +1083,7 @@
 	for (i = 0; i < max_loop; i++) {
 		struct loop_device *lo = &loop_dev[i];
 		struct gendisk *disk = disks[i];
-		memset(lo, 0, sizeof(struct loop_device));
+		memset(lo, 0, sizeof(*lo));
 		init_MUTEX(&lo->lo_ctl_mutex);
 		init_MUTEX_LOCKED(&lo->lo_sem);
 		init_MUTEX_LOCKED(&lo->lo_bh_mutex);
diff -Nru a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
--- a/drivers/block/paride/paride.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/block/paride/paride.c	Fri Oct 11 21:22:54 2002
@@ -79,7 +79,7 @@
 static void pi_wake_up( void *p)
 
 {       PIA  *pi = (PIA *) p;
-	long flags;
+	unsigned long flags;
 	void (*cont)(void) = NULL;
 
 	spin_lock_irqsave(&pi_spinlock,flags);
@@ -103,7 +103,7 @@
 
 #ifdef CONFIG_PARPORT
 
-{	long flags;
+{	unsigned long flags;
 
 	spin_lock_irqsave(&pi_spinlock,flags); 
 
diff -Nru a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
--- a/drivers/block/paride/pcd.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/block/paride/pcd.c	Fri Oct 11 21:22:56 2002
@@ -762,7 +762,7 @@
 {
 	int b, i;
 	char rd_cmd[12] = { 0xa8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
-	long saved_flags;
+	unsigned long saved_flags;
 
 	pcd_bufblk = pcd_sector / 4;
 	b = pcd_bufblk;
@@ -792,7 +792,7 @@
 	pcd_retries = 0;
 	pcd_transfer();
 	if (!pcd_count) {
-		long saved_flags;
+		unsigned long saved_flags;
 		spin_lock_irqsave(&pcd_lock, saved_flags);
 		end_request(CURRENT, 1);
 		pcd_busy = 0;
@@ -806,7 +806,7 @@
 
 static void do_pcd_read_drq(void)
 {
-	long saved_flags;
+	unsigned long saved_flags;
 
 	if (pcd_completion(pcd_current, pcd_buffer, "read block")) {
 		if (pcd_retries < PCD_RETRIES) {
diff -Nru a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
--- a/drivers/block/paride/pf.c	Fri Oct 11 21:23:01 2002
+++ b/drivers/block/paride/pf.c	Fri Oct 11 21:23:01 2002
@@ -369,11 +369,11 @@
 		return -EINVAL;
 	capacity = get_capacity(pf->disk);
 	if (capacity < PF_FD_MAX) {
-		g.cylinders = capacity / (PF_FD_HDS * PF_FD_SPT);
+		g.cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT);
 		g.heads = PF_FD_HDS;
 		g.sectors = PF_FD_SPT;
 	} else {
-		g.cylinders = capacity / (PF_HD_HDS * PF_HD_SPT);
+		g.cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT);
 		g.heads = PF_HD_HDS;
 		g.sectors = PF_HD_SPT;
 	}
@@ -685,7 +685,8 @@
 	else {
 		if (pf->media_status == PF_RO)
 			printk(", RO");
-		printk(", %ld blocks\n", get_capacity(pf->disk));
+		printk(", %llu blocks\n",
+			(unsigned long long)get_capacity(pf->disk));
 	}
 	return 0;
 }
diff -Nru a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h
--- a/drivers/block/paride/pseudo.h	Fri Oct 11 21:22:55 2002
+++ b/drivers/block/paride/pseudo.h	Fri Oct 11 21:22:55 2002
@@ -56,7 +56,7 @@
 			 int (*ready)(void),
 			 int timeout, int nice )
 
-{       long	flags;
+{       unsigned long	flags;
 
 	spin_lock_irqsave(&ps_spinlock,flags);
 
@@ -86,7 +86,7 @@
 static void ps_tq_int( void *data )
 
 {       void (*con)(void);
-	long flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&ps_spinlock,flags);
 
@@ -121,7 +121,7 @@
 static void ps_timer_int( unsigned long data)
 
 {       void (*con)(void);
-	long	flags;
+	unsigned long	flags;
 
 	spin_lock_irqsave(&ps_spinlock,flags);
 
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/block/ps2esdi.c	Fri Oct 11 21:22:50 2002
@@ -535,8 +535,9 @@
 	}
 	/* is request is valid */ 
 	else {
-		printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives,
-		       CURRENT->sector, get_capacity(ps2esdi_gendisk[unit]));
+		printk("Grrr. error. ps2esdi_drives: %d, %lu %llu\n",
+		    ps2esdi_drives, CURRENT->sector,
+		    (unsigned long long)get_capacity(ps2esdi_gendisk[unit]));
 		end_request(CURRENT, FAIL);
 	}
 
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/block/rd.c	Fri Oct 11 21:23:00 2002
@@ -459,7 +459,7 @@
 		/* rd_size is given in kB */
 		rd_length[i] = rd_size << 10;
 		disk->major = MAJOR_NR;
-		disk->first_minor = 0;
+		disk->first_minor = i;
 		disk->minor_shift = 0;
 		disk->fops = &rd_bd_op;
 		sprintf(disk->disk_name, "rd%d", i);
diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c
--- a/drivers/block/umem.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/block/umem.c	Fri Oct 11 21:23:05 2002
@@ -48,6 +48,7 @@
 #include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/pci.h>
+#include <linux/slab.h>
 
 #include <linux/fcntl.h>        /* O_ACCMODE */
 #include <linux/hdreg.h>  /* HDIO_GETGEO */
@@ -55,6 +56,7 @@
 #include <linux/umem.h>
 
 #include <asm/uaccess.h>
+#include <asm/io.h>
 
 #define PRINTK(x...) do {} while (0)
 #define dprintk(x...) do {} while (0)
diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/cdrom/cdrom.c	Fri Oct 11 21:22:54 2002
@@ -689,21 +689,28 @@
 
 static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot)
 {
-	struct cdrom_changer_info info;
+	struct cdrom_changer_info *info;
 	int ret;
 
 	cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n"); 
 	if (cdi->sanyo_slot)
 		return CDS_NO_INFO;
 	
-	if ((ret = cdrom_read_mech_status(cdi, &info)))
-		return ret;
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	if ((ret = cdrom_read_mech_status(cdi, info)))
+		goto out_free;
 
-	if (info.slots[slot].disc_present)
-		return CDS_DISC_OK;
+	if (info->slots[slot].disc_present)
+		ret = CDS_DISC_OK;
 	else
-		return CDS_NO_DISC;
+		ret = CDS_NO_DISC;
 
+out_free:
+	kfree(info);
+	return ret;
 }
 
 /* Return the number of slots for an ATAPI/SCSI cdrom, 
@@ -713,15 +720,20 @@
 {
 	int status;
 	int nslots = 1;
-	struct cdrom_changer_info info;
+	struct cdrom_changer_info *info;
 
 	cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n"); 
 	/* cdrom_read_mech_status requires a valid value for capacity: */
 	cdi->capacity = 0; 
 
-	if ((status = cdrom_read_mech_status(cdi, &info)) == 0)
-		nslots = info.hdr.nslots;
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	if ((status = cdrom_read_mech_status(cdi, info)) == 0)
+		nslots = info->hdr.nslots;
 
+	kfree(info);
 	return nslots;
 }
 
@@ -755,7 +767,7 @@
 
 static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
 {
-	struct cdrom_changer_info info;
+	struct cdrom_changer_info *info;
 	int curslot;
 	int ret;
 
@@ -771,10 +783,17 @@
 		return cdrom_load_unload(cdi, -1);
 	}
 
-	if ((ret = cdrom_read_mech_status(cdi, &info)))
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	if ((ret = cdrom_read_mech_status(cdi, info))) {
+		kfree(info);
 		return ret;
+	}
 
-	curslot = info.hdr.curslot;
+	curslot = info->hdr.curslot;
+	kfree(info);
 
 	if (cdi->use_count > 1 || keeplocked) {
 		if (slot == CDSL_CURRENT) {
@@ -1502,7 +1521,8 @@
 		}
 
 	case CDROM_MEDIA_CHANGED: {
-		struct cdrom_changer_info info;
+		struct cdrom_changer_info *info;
+		int changed;
 
 		cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); 
 		if (!CDROM_CAN(CDC_MEDIA_CHANGED))
@@ -1515,10 +1535,18 @@
 		if ((unsigned int)arg >= cdi->capacity)
 			return -EINVAL;
 
-		if ((ret = cdrom_read_mech_status(cdi, &info)))
+		info = kmalloc(sizeof(*info), GFP_KERNEL);
+		if (!info)
+			return -ENOMEM;
+
+		if ((ret = cdrom_read_mech_status(cdi, info))) {
+			kfree(info);
 			return ret;
+		}
 
-		return info.slots[arg].change;
+		changed = info->slots[arg].change;
+		kfree(info);
+		return changed;
 		}
 
 	case CDROM_SET_OPTIONS: {
diff -Nru a/drivers/char/Config.help b/drivers/char/Config.help
--- a/drivers/char/Config.help	Fri Oct 11 21:22:56 2002
+++ b/drivers/char/Config.help	Fri Oct 11 21:22:56 2002
@@ -659,7 +659,7 @@
   To compile this driver as a module ( = code which can be inserted in
   and removed from the running kernel whenever you want), say M here
   and read <file:Documentation/modules.txt>. The module will be called
-  i810_rng.o.
+  amd768_rng.o.
 
   If unsure, say N.
 
diff -Nru a/drivers/char/agp/agp.c b/drivers/char/agp/agp.c
--- a/drivers/char/agp/agp.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/char/agp/agp.c	Fri Oct 11 21:22:54 2002
@@ -823,6 +823,14 @@
 		.chipset_setup	= ali_generic_setup,
 	},
 	{
+		.device_id	= PCI_DEVICE_ID_AL_M1671,
+		.vendor_id	= PCI_VENDOR_ID_AL,
+		.chipset	= ALI_M1671,
+		.vendor_name	= "Ali",
+		.chipset_name	= "M1671",
+		.chipset_setup	= ali_generic_setup,
+	},
+	{
 		.device_id	= 0,
 		.vendor_id	= PCI_VENDOR_ID_AL,
 		.chipset	= ALI_GENERIC,
diff -Nru a/drivers/char/agp/i8x0-agp.c b/drivers/char/agp/i8x0-agp.c
--- a/drivers/char/agp/i8x0-agp.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/char/agp/i8x0-agp.c	Fri Oct 11 21:22:58 2002
@@ -311,6 +311,11 @@
 	return 0;
 }
 
+static void intel_845_resume(void)
+{
+	intel_845_configure();
+}
+
 static int intel_850_configure(void)
 {
 	u32 temp;
@@ -650,7 +655,7 @@
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
 	agp_bridge.suspend = agp_generic_suspend;
-	agp_bridge.resume = agp_generic_resume;
+	agp_bridge.resume = intel_845_resume;
 	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
diff -Nru a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c
--- a/drivers/char/amikeyb.c	Fri Oct 11 21:22:54 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,359 +0,0 @@
-/*
- * linux/arch/m68k/amiga/amikeyb.c
- *
- * Amiga Keyboard driver for Linux/m68k
- *
- * 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.
- */
-
-/*
- * Amiga support by Hamish Macdonald
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/random.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/kbd_kern.h>
-
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-#include <asm/irq.h>
-
-#define AMIKEY_CAPS	(0x62)
-#define BREAK_MASK	(0x80)
-#define RESET_WARNING	(0xf0)	/* before rotation */
-
-static u_short amiplain_map[NR_KEYS] __initdata = {
-	0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
-	0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
-	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-	0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b,
-	0xfb6c, 0xf03b, 0xf027, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d,
-	0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
-	0xf108, 0xf109, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf30a, 0xf11b,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amishift_map[NR_KEYS] __initdata = {
-	0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026,
-	0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07c, 0xf200, 0xf300,
-	0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
-	0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b,
-	0xfb4c, 0xf03a, 0xf022, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d,
-	0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf020, 0xf07f, 0xf009, 0xf30e, 0xf201, 0xf01b, 0xf07f, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
-	0xf112, 0xf113, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf203,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amialtgr_map[NR_KEYS] __initdata = {
-	0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b,
-	0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf300,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf07e, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
-	0xf514, 0xf515, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amictrl_map[NR_KEYS] __initdata = {
-	0xf000, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
-	0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf300,
-	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-	0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b,
-	0xf00c, 0xf200, 0xf007, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d,
-	0xf200, 0xf200, 0xf07f, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf000, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
-	0xf108, 0xf109, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf202,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amishift_ctrl_map[NR_KEYS] __initdata = {
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf310, 0xf307, 0xf308, 0xf309,
-	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amialt_map[NR_KEYS] __initdata = {
-	0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837,
-	0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf85c, 0xf200, 0xf900,
-	0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
-	0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf200, 0xf901, 0xf902, 0xf903,
-	0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b,
-	0xf86c, 0xf83b, 0xf827, 0xf200, 0xf200, 0xf904, 0xf905, 0xf906,
-	0xf200, 0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d,
-	0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf310, 0xf907, 0xf908, 0xf909,
-	0xf820, 0xf87f, 0xf809, 0xf30e, 0xf80d, 0xf81b, 0xf87f, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
-	0xf508, 0xf509, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf204,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short amictrl_alt_map[NR_KEYS] __initdata = {
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf300,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302, 0xf303,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf304, 0xf305, 0xf306,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf307, 0xf308, 0xf309,
-	0xf200, 0xf07f, 0xf200, 0xf30e, 0xf201, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf30b, 0xf200, 0xf603, 0xf600, 0xf602, 0xf601,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf208, 0xf209, 0xf30d, 0xf30c, 0xf30a, 0xf200,
-	0xf700, 0xf700, 0xf207, 0xf702, 0xf703, 0xf701, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-#define	DEFAULT_KEYB_REP_DELAY	(HZ/4)
-#define	DEFAULT_KEYB_REP_RATE	(HZ/25)
-
-/* These could be settable by some ioctl() in future... */
-static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
-static unsigned int key_repeat_rate  = DEFAULT_KEYB_REP_RATE;
-
-static unsigned char rep_scancode;
-static void amikeyb_rep(unsigned long ignore);
-static struct timer_list amikeyb_rep_timer = {function: amikeyb_rep};
-
-static void amikeyb_rep(unsigned long ignore)
-{
-    unsigned long flags;
-    save_flags(flags);
-    cli();
-
-    kbd_pt_regs = NULL;
-
-    amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
-    add_timer(&amikeyb_rep_timer);
-    handle_scancode(rep_scancode, 1);
-
-    restore_flags(flags);
-}
-
-static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-    unsigned char scancode, break_flag, keycode;
-    static int reset_warning = 0;
-
-    /* save frame for register dump */
-    kbd_pt_regs = fp;
-
-    /* get and invert scancode (keyboard is active low) */
-    scancode = ~ciaa.sdr;
-
-    /* switch SP pin to output for handshake */
-    ciaa.cra |= 0x40;
-
-#if 0 /* No longer used */
-    /*
-     *  On receipt of the second RESET_WARNING, we must not pull KDAT high
-     *  again to delay the hard reset as long as possible.
-     *
-     *  Note that not all keyboards send reset warnings...
-     */
-    if (reset_warning)
-	if (scancode == RESET_WARNING) {
-	    printk(KERN_ALERT "amikeyb: Ctrl-Amiga-Amiga reset warning!!\n"
-		   "The system will be reset within 10 seconds!!\n");
-	    /* Panic doesn't sync from within an interrupt, so we do nothing */
-	    return;
-	} else
-	    /* Probably a mistake, cancel the alert */
-	    reset_warning = 0;
-#endif
-
-    /* wait until 85 us have expired */
-    udelay(85);
-    /* switch CIA serial port to input mode */
-    ciaa.cra &= ~0x40;
-
-    tasklet_schedule(&keyboard_tasklet);
-
-    /* rotate scan code to get up/down bit in proper position */
-    scancode = ((scancode >> 1) & 0x7f) | ((scancode << 7) & 0x80);
-
-    /*
-     * Check make/break first
-     */
-    break_flag = scancode & BREAK_MASK;
-    keycode = scancode & (unsigned char)~BREAK_MASK;
-
-    if (keycode == AMIKEY_CAPS) {
-	/* if the key is CAPS, fake a press/release. */
-	handle_scancode(AMIKEY_CAPS, 1);
-	handle_scancode(AMIKEY_CAPS, 0);
-    } else if (keycode < 0x78) {
-	/* handle repeat */
-	if (break_flag) {
-	    del_timer(&amikeyb_rep_timer);
-	    rep_scancode = 0;
-	} else {
-	    del_timer(&amikeyb_rep_timer);
-	    rep_scancode = keycode;
-	    amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
-	    add_timer(&amikeyb_rep_timer);
-	}
-	handle_scancode(keycode, !break_flag);
-    } else
-	switch (keycode) {
-	    case 0x78:
-		reset_warning = 1;
-		break;
-	    case 0x79:
-		printk(KERN_WARNING "amikeyb: keyboard lost sync\n");
-		break;
-	    case 0x7a:
-		printk(KERN_WARNING "amikeyb: keyboard buffer overflow\n");
-		break;
-#if 0 /* obsolete according to the HRM */
-	    case 0x7b:
-		printk(KERN_WARNING "amikeyb: keyboard controller failure\n");
-		break;
-#endif
-	    case 0x7c:
-		printk(KERN_ERR "amikeyb: keyboard selftest failure\n");
-		break;
-	    case 0x7d:
-		printk(KERN_INFO "amikeyb: initiate power-up key stream\n");
-		break;
-	    case 0x7e:
-		printk(KERN_INFO "amikeyb: terminate power-up key stream\n");
-		break;
-#if 0 /* obsolete according to the HRM */
-	    case 0x7f:
-		printk(KERN_WARNING "amikeyb: keyboard interrupt\n");
-		break;
-#endif
-	    default:
-		printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
-		       scancode);
-		break;
-	}
-}
-
-int __init amiga_keyb_init(void)
-{
-    if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
-        return -EIO;
-    if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
-	return -EBUSY;
-
-    /* setup key map */
-    memcpy(key_maps[0], amiplain_map, sizeof(plain_map));
-    memcpy(key_maps[1], amishift_map, sizeof(plain_map));
-    memcpy(key_maps[2], amialtgr_map, sizeof(plain_map));
-    memcpy(key_maps[4], amictrl_map, sizeof(plain_map));
-    memcpy(key_maps[5], amishift_ctrl_map, sizeof(plain_map));
-    memcpy(key_maps[8], amialt_map, sizeof(plain_map));
-    memcpy(key_maps[12], amictrl_alt_map, sizeof(plain_map));
-
-    /*
-     * Initialize serial data direction.
-     */
-    ciaa.cra &= ~0x41;	     /* serial data in, turn off TA */
-
-    /*
-     * arrange for processing of keyboard interrupt
-     */
-    request_irq(IRQ_AMIGA_CIAA_SP, keyboard_interrupt, 0, "keyboard", NULL);
-
-    return 0;
-}
-
-int amiga_kbdrate( struct kbd_repeat *k )
-{
-    if (k->delay > 0) {
-	/* convert from msec to jiffies */
-	key_repeat_delay = (k->delay * HZ + 500) / 1000;
-	if (key_repeat_delay < 1)
-            key_repeat_delay = 1;
-    }
-    if (k->rate > 0) {
-	key_repeat_rate = (k->rate * HZ + 500) / 1000;
-	if (key_repeat_rate < 1)
-            key_repeat_rate = 1;
-    }
-
-    k->delay = key_repeat_delay * 1000 / HZ;
-    k->rate  = key_repeat_rate  * 1000 / HZ;
-    
-    return( 0 );
-}
-
-int amiga_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
-{
-#ifdef CONFIG_MAGIC_SYSRQ
-        /* SHIFT+ALTGR+HELP pressed? */
-        if ((keycode == 0x5f) && ((shift_state & 0xff) == 3))
-                *keycodep = 0xff;
-        else
-#endif
-                *keycodep = keycode;
-        return 1;
-}
-
diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c
--- a/drivers/char/amiserial.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/char/amiserial.c	Fri Oct 11 21:23:05 2002
@@ -597,7 +597,7 @@
 	int	retval=0;
 	unsigned long page;
 
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
@@ -1926,7 +1926,7 @@
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
 			return -ENOMEM;
 		}
diff -Nru a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c
--- a/drivers/char/atarimouse.c	Fri Oct 11 21:22:54 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,136 +0,0 @@
-/*
- * Atari Mouse Driver for Linux
- * by Robert de Vries (robert@and.nl) 19Jul93
- *
- * 16 Nov 1994 Andreas Schwab
- * Compatibility with busmouse
- * Support for three button mouse (shamelessly stolen from MiNT)
- * third button wired to one of the joystick directions on joystick 1
- *
- * 1996/02/11 Andreas Schwab
- * Module support
- * Allow multiple open's
- *
- * Converted to use new generic busmouse code.  5 Apr 1998
- *   Russell King <rmk@arm.uk.linux.org>
- */
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/logibusmouse.h>
-
-#include <asm/setup.h>
-#include <asm/atarikb.h>
-#include <asm/uaccess.h>
-
-#include "busmouse.h"
-
-static int msedev;
-static int mouse_threshold[2] = {2,2};
-MODULE_PARM(mouse_threshold, "2i");
-extern int atari_mouse_buttons;
-
-static void atari_mouse_interrupt(char *buf)
-{
-	int buttons;
-
-/*	ikbd_mouse_disable(); */
-
-	buttons = ((buf[0] & 1)
-	       | ((buf[0] & 2) << 1)
-	       | (atari_mouse_buttons & 2));
-	atari_mouse_buttons = buttons;
-
-	busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7);
-/*	ikbd_mouse_rel_pos(); */
-}
-
-static int release_mouse(struct inode *inode, struct file *file)
-{
-	ikbd_mouse_disable();
-	atari_mouse_interrupt_hook = NULL;
-	return 0;
-}
-
-static int open_mouse(struct inode *inode, struct file *file)
-{
-	atari_mouse_buttons = 0;
-	ikbd_mouse_y0_top ();
-	ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]);
-	ikbd_mouse_rel_pos();
-	atari_mouse_interrupt_hook = atari_mouse_interrupt;
-	return 0;
-}
-
-static struct busmouse atarimouse = {
-	ATARIMOUSE_MINOR, "atarimouse", THIS_MODULE, open_mouse, release_mouse, 0
-};
-
-static int __init atari_mouse_init(void)
-{
-	if (!MACH_IS_ATARI)
-		return -ENODEV;
-	msedev = register_busmouse(&atarimouse);
-	if (msedev < 0)
-    		printk(KERN_WARNING "Unable to register Atari mouse driver.\n");
-	else
-		printk(KERN_INFO "Atari mouse installed.\n");
-	return msedev < 0 ? msedev : 0;
-}
-
-
-#ifndef MODULE
-
-#define	MIN_THRESHOLD 1
-#define	MAX_THRESHOLD 20	/* more seems not reasonable... */
-
-static int __init atari_mouse_setup( char *str )
-{
-    int ints[8];
-
-    str = get_options(str, ARRAY_SIZE(ints), ints);
-
-    if (ints[0] < 1) {
-	printk(KERN_ERR "atari_mouse_setup: no arguments!\n" );
-	return 0;
-    }
-    else if (ints[0] > 2) {
-	printk(KERN_WARNING "atari_mouse_setup: too many arguments\n" );
-    }
-
-    if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
-	printk(KERN_WARNING "atari_mouse_setup: bad threshold value (ignored)\n" );
-    else {
-	mouse_threshold[0] = ints[1];
-	mouse_threshold[1] = ints[1];
-	if (ints[0] > 1) {
-	    if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
-		printk(KERN_WARNING "atari_mouse_setup: bad threshold value (ignored)\n" );
-	    else
-		mouse_threshold[1] = ints[2];
-	}
-    }
-
-    return 1;
-}
-
-__setup("atarimouse=",atari_mouse_setup);
-
-#endif /* !MODULE */
-
-static void __exit atari_mouse_cleanup (void)
-{
-	unregister_busmouse(msedev);
-}
-
-module_init(atari_mouse_init);
-module_exit(atari_mouse_cleanup);
-
-MODULE_LICENSE("GPL");
\ No newline at end of file
diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c
--- a/drivers/char/cyclades.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/char/cyclades.c	Fri Oct 11 21:22:54 2002
@@ -2001,7 +2001,7 @@
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
 
-    page = get_free_page(GFP_KERNEL);
+    page = get_zeroed_page(GFP_KERNEL);
     if (!page)
 	return -ENOMEM;
 
@@ -2648,7 +2648,7 @@
         current->pid, info->count);
 #endif
     if (!tmp_buf) {
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 	    return -ENOMEM;
 	if (tmp_buf)
diff -Nru a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c
--- a/drivers/char/dn_keyb.c	Fri Oct 11 21:23:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,483 +0,0 @@
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/keyboard.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/kd.h>
-#include <linux/kbd_ll.h>
-#include <linux/random.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/irq.h>
-#include <asm/apollohw.h>
-#include <asm/uaccess.h>
-
-#include "busmouse.h"
-
-#define DNKEY_CAPS 0x7e
-#define BREAK_FLAG 0x80
-#define DNKEY_REPEAT_DELAY 50
-#define DNKEY_CTRL 0x43
-#define DNKEY_LSHIFT 0x5e
-#define DNKEY_RSHIFT 0x6a
-#define DNKEY_REPT 0x5d
-#define DNKEY_REPEAT 0x7f
-#define DNKEY_LALT 0x75
-#define DNKEY_RALT 0x77
-
-#define APOLLO_KEYB_CMD_ENTRIES 16
-#define APOLLO_KBD_MODE_KEYB   0x01
-#define APOLLO_KBD_MODE_MOUSE   0x02
-#define APOLLO_KBD_MODE_CHANGE 0xff
-
-static u_char keyb_cmds[APOLLO_KEYB_CMD_ENTRIES];
-static short keyb_cmd_read=0, keyb_cmd_write=0;
-static int keyb_cmd_transmit=0;
-static int msedev;
-
-static unsigned int kbd_mode=APOLLO_KBD_MODE_KEYB;
-
-#if 0
-static void debug_keyb_timer_handler(unsigned long ignored);
-static u_char debug_buf1[4096],debug_buf2[4096],*debug_buf=&debug_buf1[0];
-static u_char *shadow_buf=&debug_buf2[0];
-static short debug_buf_count=0;
-static int debug_buf_overrun=0,debug_timer_running=0;
-static unsigned long debug_buffer_updated=0;
-static struct timer_list debug_keyb_timer = { function: debug_keyb_timer_handler };
-#endif
-
-static u_short dnplain_map[NR_KEYS] __initdata = {
-/*         ins     del     del     F1      F2      F3      F4  
-           mark    line    char                                 */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-/* F5      F6      F7      F8      F9      F0      Again   Read */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-/* Edit    Exit    Hold    Copy    Paste   Grow            ESC  */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
-/* 1       2       3       4       5       6       7       8    */
-   0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038,
-/* 9       0       -       =       `       Back            |<--
-                                           Space                */
-   0xf039, 0xf030, 0xf02d, 0xf03d, 0xf060, 0xf07f, 0xf200, 0xf200,
-/* Shell   -->|                    Tab     q       w       e
-   Cmd                                                          */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf009, 0xfb71, 0xfb77, 0xfb65,
-/* r       t       y       u       i       o       p       [    */
-   0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, 0xf05b,
-/* ]               Del             7       8       9       +    */
-   0xf05d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
-/* [<--]   Up      [-->]   Ctrl                    a       s    */
-   0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xfb61, 0xfb73,
-/* d       f       g       h       j       k       l       ;    */
-   0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
-/* '               Return  \               4       5       6    */
-   0xf027, 0xf200, 0xf201, 0xf05c, 0xf200, 0xf304, 0xf305, 0xf306,
-/* -       <--     Next    -->             Rept    Shift        
-                   Window                                       */
-   0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf700, 0xf200,
-/* z       x       c       v       b       n       m       ,    */
-   0xfb7a, 0xfb78, 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c,
-/* .       /       Shift           Pop             1       2    */
-   0xf02e, 0xf02f, 0xf700, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
-/* 3               PgUp    Down    PgDn    Alt     Space   Alt  */
-   0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf020, 0xf701,
-/*         0               .       Enter                        */
-   0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf700, 0xf200,
-};
-
-static u_short dnshift_map[NR_KEYS] __initdata = {
-/*         ins     del     del     F1      F2      F3      F4
-           mark    line    char                                 */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-/* F5      F6      F7      F8      F9      F0      Again   Read */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-/* Save    Abort   Help    Cut     Undo    Grow            ESC  */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
-/* !       @       #       $       %       ^       &       *    */
-   0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a,
-/* (       )       _       +       ~       Back            |<--
-                                           Space                */
-   0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07e, 0xf07f, 0xf200, 0xf200,
-/* Shell   -->|                    Tab     Q       W       E
-   Cmd                                                          */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf009, 0xfb51, 0xfb57, 0xfb45,
-/* R       T       Y       U       I       O       P       {    */
-   0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, 0xfb4f, 0xfb50, 0xf07b,
-/* }               Del             7       8       9       +    */
-   0xf07d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
-/* [<--]   Up      [-->]   Ctrl                    A       S    */
-   0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xfb41, 0xfb53,
-/* D       F       G       H       J       K       L       :    */
-   0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
-/* "               Return  |               4       5       6    */
-   0xf022, 0xf200, 0xf201, 0xf07c, 0xf200, 0xf304, 0xf305, 0xf306,
-/* -       <--     Next    -->             Rept    Shift        
-                   Window                                       */
-   0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf700, 0xf200,
-/* Z       X       C       V       B       N       M       <    */
-   0xfb5a, 0xfb58, 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c,
-/* >       ?       Shift           Pop             1       2    */
-   0xf03e, 0xf03f, 0xf700, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
-/* 3               PgUp    Down    PgDn    Alt     Space   Alt  */
-   0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf020, 0xf701,
-/*         0               .       Enter                        */
-   0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf708, 0xf200,
-};
-
-static u_short dnctrl_map[NR_KEYS] __initdata = {
-/*         ins     del     del     F1      F2      F3      F4
-           mark    line    char                                 */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-/* F5      F6      F7      F8      F9      F0      Again   Read */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-/* Save    Abort   Help    Cut     Undo    Grow            ESC  */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
-/* !       @       #       $       %       ^       &       *    */
-   0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f,
-/* (       )       _       +       ~       Back            |<--
-                                           Space                */
-   0xf200, 0xf200, 0xf01f, 0xf200, 0xf01c, 0xf200, 0xf200, 0xf200,
-/* Shell   -->|                    Tab     Q       W       E
-   Cmd                                                          */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf009, 0xf011, 0xf017, 0xf005,
-/* R       T       Y       U       I       O       P       {    */
-   0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, 0xf01b,
-/* }               Del             7       8       9       +    */
-   0xf01d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
-/* [<--]   Up      [-->]   Ctrl                    A       S    */
-   0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xfb01, 0xfb53,
-/* D       F       G       H       J       K       L       :    */
-   0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-/* "               Return  |               4       5       6    */
-   0xf200, 0xf200, 0xf201, 0xf01c, 0xf200, 0xf304, 0xf305, 0xf306,
-/* -       <--     Next    -->             Rept    Shift        
-                   Window                                       */
-   0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf704, 0xf200,
-/* Z       X       C       V       B       N       M       <    */
-   0xf01a, 0xf018, 0xf003, 0xf016, 0xf002, 0xf00e, 0xf01d, 0xf03c,
-/* >       ?       Shift           Pop             1       2    */
-   0xf03e, 0xf03f, 0xf705, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
-/* 3               PgUp    Down    PgDn    Alt     Space   Alt  */
-   0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf020, 0xf701,
-/*         0               .       Enter                        */
-   0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short dnalt_map[NR_KEYS] __initdata = {
-/*         ins     del     del     F1      F2      F3      F4  
-           mark    line    char                                 */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf502, 0xf503,
-/* F5      F6      F7      F8      F9      F0      Again   Read */
-   0xf504, 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf200, 0xf200,
-/* Edit    Exit    Hold    Copy    Paste   Grow            ESC  */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf01b,
-/* 1       2       3       4       5       6       7       8    */
-   0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838,
-/* 9       0       -       =       `       Back            |<--
-                                           Space                */
-   0xf839, 0xf830, 0xf82d, 0xf83d, 0xf860, 0xf87f, 0xf200, 0xf200,
-/* Shell   -->|                    Tab     q       w       e
-   Cmd                                                          */
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf809, 0xf871, 0xf877, 0xf865,
-/* r       t       y       u       i       o       p       [    */
-   0xf872, 0xf874, 0xf879, 0xf875, 0xf869, 0xf86f, 0xf870, 0xf85b,
-/* ]               Del             7       8       9       +    */
-   0xf05d, 0xf200, 0xf200, 0xf200, 0xf307, 0xf308, 0xf300, 0xf30a,
-/* [<--]   Up      [-->]   Ctrl                    a       s    */
-   0xf200, 0xf600, 0xf200, 0xf702, 0xf200, 0xf200, 0xf861, 0xf873,
-/* d       f       g       h       j       k       l       ;    */
-   0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf03b,
-/* '               Return  \               4       5       6    */
-   0xf027, 0xf200, 0xf201, 0xf05c, 0xf200, 0xf304, 0xf305, 0xf306,
-/* -       <--     Next    -->             Rept    Shift        
-                   Window                                       */
-   0xf30b, 0xf601, 0xf200, 0xf602, 0xf200, 0xf200, 0xf704, 0xf200,
-/* z       x       c       v       b       n       m       ,    */
-   0xf87a, 0xf878, 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d, 0xf82c,
-/* .       /       Shift           Pop             1       2    */
-   0xf82e, 0xf82f, 0xf705, 0xf200, 0xf200, 0xf200, 0xf301, 0xf302,
-/* 3               PgUp    Down    PgDn    Alt     Space   Alt  */
-   0xf303, 0xf200, 0xf118, 0xf603, 0xf119, 0xf703, 0xf820, 0xf701,
-/*         0               .       Enter                        */
-   0xf200, 0xf300, 0xf200, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short dnaltgr_map[NR_KEYS] __initdata = {
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short dnshift_ctrl_map[NR_KEYS] __initdata = {
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-static u_short dnctrl_alt_map[NR_KEYS] __initdata = {
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-   0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
-};
-
-#if 0
-static void debug_keyb_timer_handler(unsigned long ignored) {
-
-	unsigned long flags;
-	u_char *swap;
-	short length,i;
-
-	if (time_after(jiffies, debug_buffer_updated + 100)) {
-		save_flags(flags);
-		cli();
-		length=debug_buf_count;		
-		swap=debug_buf;	
-		debug_buf=shadow_buf;
-		shadow_buf=swap;
-		debug_buf_count=0;
-		debug_timer_running=0;
-		restore_flags(flags);
-		for(i=1;length;length--,i++)	
-			printk("%02x%c",*(swap++), (i % 25) ? ' ' : '\n');
-		printk("\n");
-	}
-	else {
-		debug_keyb_timer.expires=jiffies+10;
-		add_timer(&debug_keyb_timer);
-	}
-}
-#endif
-
-static void dn_keyb_process_key_event(unsigned char scancode) {
-
-	static unsigned char lastscancode;
-	unsigned char prev_scancode=lastscancode;
-	static unsigned int lastkeypress;
-	
-	lastscancode=scancode;
-
-	/*  printk("scan: %02x, lastscan: %02X, prev_scancode: %02X\n",scancode,lastscancode,prev_scancode); */
-
-	if(prev_scancode==APOLLO_KBD_MODE_CHANGE) {
-		kbd_mode=scancode;
-/*		printk("modechange: %d\n",scancode); */
-	}
-	else if((scancode & (~BREAK_FLAG)) == DNKEY_CAPS) {
-    	/* printk("handle_scancode: %02x\n",DNKEY_CAPS); */
-		handle_scancode(DNKEY_CAPS, 1);
-		/*    printk("handle_scancode: %02x\n",BREAK_FLAG | DNKEY_CAPS); */
-		handle_scancode(DNKEY_CAPS, 0);
-	}
-	else if( (scancode == DNKEY_REPEAT) && (prev_scancode < 0x7e) &&
-   			!(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT ||
-       	   	prev_scancode==DNKEY_RSHIFT || prev_scancode==DNKEY_REPT ||
-       	  	prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) {
-			if (time_after(jiffies, lastkeypress + DNKEY_REPEAT_DELAY)) {
-			/*    	printk("handle_scancode: %02x\n",prev_scancode); */
-           			handle_scancode(prev_scancode, 1);
-			  	}
-	   			lastscancode=prev_scancode;
-  			}
-  	else {
-	/*    	printk("handle_scancode: %02x\n",scancode);  */
-   			handle_scancode(scancode & ~BREAK_FLAG, !(scancode & BREAK_FLAG));
-   			lastkeypress=jiffies;
-  	}
-}
-
-static void dn_keyb_process_mouse_event(unsigned char mouse_data) {
-
-	static short mouse_byte_count=0;
-	static u_char mouse_packet[3];
-	short buttons;
-	int dx, dy;
-
-	mouse_packet[mouse_byte_count++]=mouse_data;
-
-	if(mouse_byte_count==3) {
-		if(mouse_packet[0]==APOLLO_KBD_MODE_CHANGE) {
-			kbd_mode=mouse_packet[1];
-			mouse_byte_count=0;
-/*			printk("modechange: %d\n",mouse_packet[1]); */
-			if(kbd_mode==APOLLO_KBD_MODE_KEYB)
-				dn_keyb_process_key_event(mouse_packet[2]);
-		}
-		if((mouse_packet[0] & 0x8f) == 0x80) {
-			buttons = (mouse_packet[0] >> 4) & 0x7;
-			dx = mouse_packet[1] == 0xff ? 0 : (signed char)mouse_packet[1];
-			dy = mouse_packet[2] == 0xff ? 0 : (signed char)mouse_packet[2];
-			busmouse_add_movementbuttons(msedev, dx, dy, buttons);
-			mouse_byte_count=0;
-/*			printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */
-		}
-	}
-}
-
-static void dn_keyb_int(int irq, void *dummy, struct pt_regs *fp) {
-
-	unsigned char data;
-  	unsigned long flags;
-  	int scn2681_ints;
-
-	do {
-		scn2681_ints=sio01.isr_imr & 3;
-		if(scn2681_ints & 2) {
-			data=sio01.rhra_thra;
-#if 0
-			if(debug_buf_count<4096) {
-				debug_buf[debug_buf_count++]=data;
-				debug_buffer_updated=jiffies;	
-				if(!debug_timer_running) {
-					debug_keyb_timer.expires=jiffies+10;
-					add_timer(&debug_keyb_timer);
-					debug_timer_running=1;
-				}
-			}
-			else
-				debug_buf_overrun=1;
-#endif
-			if(sio01.sra_csra & 0x10) {
-				printk("whaa overrun !\n");
-				continue;
-			}
-
-			if(kbd_mode==APOLLO_KBD_MODE_KEYB)
-				dn_keyb_process_key_event(data);
-			else
-				dn_keyb_process_mouse_event(data);
-		}
-	
-		if(scn2681_ints & 1) {
-			save_flags(flags);
-			cli();
-			if(keyb_cmd_write!=keyb_cmd_read) {
-				sio01.rhra_thra=keyb_cmds[keyb_cmd_read++];
-				if(keyb_cmd_read==APOLLO_KEYB_CMD_ENTRIES)
-					keyb_cmd_read=0;
-				keyb_cmd_transmit=1;
-			}
-			else {
-				keyb_cmd_transmit=0;
-				sio01.BRGtest_cra=9;
-			}
-			restore_flags(flags);
-		}
-	} while(scn2681_ints) ;
-}
-
-void write_keyb_cmd(u_short length, u_char *cmd) {
-
-  	unsigned long flags;
-
-	if((keyb_cmd_write==keyb_cmd_read) && keyb_cmd_transmit)
-		return;
-
-	save_flags(flags);
-	cli();
-	for(;length;length--) {
-		keyb_cmds[keyb_cmd_write++]=*(cmd++);
-		if(keyb_cmd_write==keyb_cmd_read)
-			return;
-		if(keyb_cmd_write==APOLLO_KEYB_CMD_ENTRIES)
-			keyb_cmd_write=0;
-	}
-	if(!keyb_cmd_transmit)  {
- 	   sio01.BRGtest_cra=5;
-	}
-	restore_flags(flags);
-
-}
-
-static struct busmouse apollo_mouse = {
-        APOLLO_MOUSE_MINOR, "apollomouse", THIS_MODULE, NULL, NULL, 7
-};
-
-int __init dn_keyb_init(void){
-
-/*  printk("dn_keyb_init\n"); */
-
-  memcpy(key_maps[0], dnplain_map, sizeof(plain_map));
-  memcpy(key_maps[1], dnshift_map, sizeof(plain_map));
-  memcpy(key_maps[2], dnaltgr_map, sizeof(plain_map));
-  memcpy(key_maps[4], dnctrl_map, sizeof(plain_map));
-  memcpy(key_maps[5], dnshift_ctrl_map, sizeof(plain_map));
-  memcpy(key_maps[8], dnalt_map, sizeof(plain_map));
-  memcpy(key_maps[12], dnctrl_alt_map, sizeof(plain_map));
-
-
-  msedev=register_busmouse(&apollo_mouse);
-  if (msedev < 0)
-      printk(KERN_WARNING "Unable to install Apollo mouse driver.\n");
-   else
-      printk(KERN_INFO "Apollo mouse installed.\n");
-
-  /* program UpDownMode */
-
-  while(!(sio01.sra_csra & 0x4));
-  sio01.rhra_thra=0xff;
-
-  while(!(sio01.sra_csra & 0x4));
-  sio01.rhra_thra=0x1;
-
-  request_irq(1, dn_keyb_int,0,NULL,NULL);
-  
-  /* enable receive int on DUART */
-  sio01.isr_imr=3;
-
-  return 0;
-
-}
-
-int dn_dummy_kbdrate(struct kbd_repeat *k) {
-
-  printk("dn_dummy_kbdrate\n");
-
-  return 0;
-
-}
diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c
--- a/drivers/char/dz.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/char/dz.c	Fri Oct 11 21:22:53 2002
@@ -465,7 +465,7 @@
 	}
 
 	if (!info->xmit_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
 			restore_flags (flags);
 		return -ENOMEM;
diff -Nru a/drivers/char/esp.c b/drivers/char/esp.c
--- a/drivers/char/esp.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/char/esp.c	Fri Oct 11 21:22:50 2002
@@ -894,7 +894,7 @@
 		goto out;
 
 	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL);
+		info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
 		retval = -ENOMEM;
 		if (!info->xmit_buf)
 			goto out;
@@ -2380,7 +2380,7 @@
 	info->tty = tty;
 
 	if (!tmp_buf) {
-		tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
 		if (!tmp_buf)
 			return -ENOMEM;
 	}
diff -Nru a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
--- a/drivers/char/generic_serial.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/char/generic_serial.c	Fri Oct 11 21:22:58 2002
@@ -41,8 +41,8 @@
 #define gs_dprintk(f, str...) /* nothing */
 #endif
 
-#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
-#define func_exit()  gs_dprintk (GS_DEBUG_FLOW, "gs: exit  " __FUNCTION__ "\n")
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__)
+#define func_exit()  gs_dprintk (GS_DEBUG_FLOW, "gs: exit  %s\n", __FUNCTION__)
 
 #if NEW_WRITE_LOCKING
 #define DECL      /* Nothing */
@@ -511,7 +511,7 @@
 
 void gs_shutdown_port (struct gs_port *port)
 {
-	long flags;
+	unsigned long flags;
 
 	func_enter();
 	
@@ -952,7 +952,7 @@
 
 	save_flags (flags);
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 
 		cli (); /* Don't expect this to make a difference. */ 
 		if (tmp_buf)
@@ -970,10 +970,10 @@
 		return 0;
 
 	if (!port->xmit_buf) {
-		/* We may sleep in get_free_page() */
+		/* We may sleep in get_zeroed_page() */
 		unsigned long tmp;
 
-		tmp = get_free_page(GFP_KERNEL);
+		tmp = get_zeroed_page(GFP_KERNEL);
 
 		/* Spinlock? */
 		cli ();
diff -Nru a/drivers/char/isicom.c b/drivers/char/isicom.c
--- a/drivers/char/isicom.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/char/isicom.c	Fri Oct 11 21:22:51 2002
@@ -859,7 +859,7 @@
 	if (!port->xmit_buf) {
 		unsigned long page;
 		
-		if (!(page = get_free_page(GFP_KERNEL)))
+		if (!(page = get_zeroed_page(GFP_KERNEL)))
 			return -ENOMEM;
 		
 		if (port->xmit_buf) {
@@ -1854,7 +1854,7 @@
 	unsigned long page;
 	
 	if (!tmp_buf) { 
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 	      	if (!page) {
 #ifdef ISICOM_DEBUG	      	
 	      		printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n");
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/char/keyboard.c	Fri Oct 11 21:22:55 2002
@@ -264,23 +264,34 @@
 /*
  * Setting the keyboard rate.
  */
+static inline unsigned int ms_to_jiffies(unsigned int ms) {
+	unsigned int j;
+
+	j = (ms * HZ + 500) / 1000;
+	return (j > 0) ? j : 1;
+}
+
 int kbd_rate(struct kbd_repeat *rep)
 {
-	struct list_head * node;
-
-	if (rep->rate < 0 || rep->delay < 0)
-		return -EINVAL;
+	struct list_head *node;
+	unsigned int d = 0;
+	unsigned int p = 0;
 
 	list_for_each(node,&kbd_handler.h_list) {
 		struct input_handle *handle = to_handle_h(node);
-		if (test_bit(EV_REP, handle->dev->evbit)) {
-			if (rep->rate > HZ) rep->rate = HZ;
-			handle->dev->rep[REP_PERIOD] = rep->rate ? (HZ / rep->rate) : 0;
-			handle->dev->rep[REP_DELAY] = rep->delay * HZ / 1000;
-			if (handle->dev->rep[REP_DELAY] < handle->dev->rep[REP_PERIOD])
-				handle->dev->rep[REP_DELAY] = handle->dev->rep[REP_PERIOD];
+		struct input_dev *dev = handle->dev;
+
+		if (test_bit(EV_REP, dev->evbit)) {
+			if (rep->delay > 0)
+				dev->rep[REP_DELAY] = ms_to_jiffies(rep->delay);
+			if (rep->period > 0)
+				dev->rep[REP_PERIOD] = ms_to_jiffies(rep->period);
+			d = dev->rep[REP_DELAY]  * 1000 / HZ;
+			p = dev->rep[REP_PERIOD] * 1000 / HZ;
 		}
 	}
+	rep->delay  = d;
+	rep->period = p;
 	return 0;
 }
 
@@ -917,14 +928,14 @@
 	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
 	 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90,
 	284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
-	367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
-	360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
-	103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
-	291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
+	367,288,302,304,350, 92,334,512,116,377,109,111,373,347,348,349,
+	360, 93, 94, 95, 98,376,100,101,321,316,354,286,289,102,351,355,
+	103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361,
+	291,108,381,281,290,272,292,305,280, 99,112,257,258,359,270,114,
 	118,117,125,374,379,115,112,125,121,123,264,265,266,267,268,269,
-	271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
-	308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
-	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
+	271,273,276,277,278,282,283,295,296,297,299,300,301,293,303,307,
+	308,310,313,314,315,317,318,319,320,357,322,323,324,325,326,330,
+	332,340,365,342,343,344,345,346,356,113,341,368,369,370,371,372 };
 
 #ifdef CONFIG_MAC_EMUMOUSEBTN
 extern int mac_hid_mouse_emulate_buttons(int, int, int);
diff -Nru a/drivers/char/machzwd.c b/drivers/char/machzwd.c
--- a/drivers/char/machzwd.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/char/machzwd.c	Fri Oct 11 21:22:54 2002
@@ -329,7 +329,10 @@
 			
 			/* now scan */
 			for(ofs = 0; ofs != count; ofs++){
-				if(buf[ofs] == 'V'){
+				char c;
+				if (get_user(c, buf + ofs))
+					return -EFAULT;
+				if (c == 'V'){
 					zf_expect_close = 1;
 					dprintk("zf_expect_close 1\n");
 				}
diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c
--- a/drivers/char/moxa.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/char/moxa.c	Fri Oct 11 21:23:04 2002
@@ -565,7 +565,7 @@
 	}
 	down(&moxaBuffSem);
 	if (!moxaXmitBuff) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
 			up(&moxaBuffSem);
 			return (-ENOMEM);
diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c
--- a/drivers/char/mxser.c	Fri Oct 11 21:23:01 2002
+++ b/drivers/char/mxser.c	Fri Oct 11 21:23:01 2002
@@ -760,7 +760,7 @@
 	info->tty = tty;
 
 	if (!mxvar_tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page)
 			return (-ENOMEM);
 		if (mxvar_tmp_buf)
@@ -1689,7 +1689,7 @@
 	unsigned long flags;
 	unsigned long page;
 
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return (-ENOMEM);
 
diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
--- a/drivers/char/pcmcia/synclink_cs.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/char/pcmcia/synclink_cs.c	Fri Oct 11 21:22:55 2002
@@ -1483,7 +1483,7 @@
 	
 	if (!info->tx_buf) {
 		/* allocate a page of memory for a transmit buffer */
-		info->tx_buf = (unsigned char *)get_free_page(GFP_KERNEL);
+		info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
 		if (!info->tx_buf) {
 			printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
 				__FILE__,__LINE__,info->device_name);
diff -Nru a/drivers/char/pcxx.c b/drivers/char/pcxx.c
--- a/drivers/char/pcxx.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/char/pcxx.c	Fri Oct 11 21:23:00 2002
@@ -153,7 +153,6 @@
 DECLARE_TASK_QUEUE(tq_pcxx);
 
 static void pcxxpoll(unsigned long dummy);
-static void pcxxdelay(int);
 static void fepcmd(struct channel *, int, int, int, int, int);
 static void pcxe_put_char(struct tty_struct *, unsigned char);
 static void pcxe_flush_chars(struct tty_struct *);
@@ -1271,7 +1270,7 @@
 	for(crd=0; crd < numcards; crd++) {
 		bd = &boards[crd];
 		outb(FEPRST, bd->port);
-		pcxxdelay(1);
+		mdelay(1);
 
 		for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {
 			if(i > 100) {
@@ -1283,7 +1282,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(10);
+			mdelay(10);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1362,7 +1361,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1413,7 +1412,7 @@
 #ifdef MODULE
 				schedule();
 #endif
-				pcxxdelay(50);
+				mdelay(50);
 			}
 
 			printk("\nPC/Xx: BIOS download failed for board at 0x%x(addr=%lx-%lx)!\n",
@@ -1443,7 +1442,7 @@
 #ifdef MODULE
 				schedule();
 #endif
-				pcxxdelay(10);
+				mdelay(10);
 			}
 
 			printk("\nPC/Xx: BIOS download failed on the %s at 0x%x!\n",
@@ -1487,7 +1486,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 
 		if(bd->status == DISABLED)
@@ -1520,7 +1519,7 @@
 #ifdef MODULE
 			schedule();
 #endif
-			pcxxdelay(1);
+			mdelay(1);
 		}
 		if(bd->status == DISABLED)
 			continue;
@@ -1822,15 +1821,6 @@
 		globalwinon(chan0);
 	}
 
-}
-
-
-/*
- * pcxxdelay - delays a specified number of milliseconds
- */
-static void pcxxdelay(int msec)
-{
-	mdelay(msec);
 }
 
 
diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c
--- a/drivers/char/ppdev.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/char/ppdev.c	Fri Oct 11 21:22:57 2002
@@ -118,6 +118,10 @@
 		return -EINVAL;
 	}
 
+	/* Trivial case. */
+	if (count == 0)
+		return 0;
+
 	kbuffer = kmalloc(min_t(size_t, count, PP_BUFFER_SIZE), GFP_KERNEL);
 	if (!kbuffer) {
 		return -ENOMEM;
diff -Nru a/drivers/char/pty.c b/drivers/char/pty.c
--- a/drivers/char/pty.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/char/pty.c	Fri Oct 11 21:22:55 2002
@@ -5,6 +5,10 @@
  *
  *  Added support for a Unix98-style ptmx device.
  *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *  Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to
+ *      waiting writers -- Sapan Bhatia <sapan@corewars.org>
+ *
+ *
  */
 
 #include <linux/config.h>
@@ -329,6 +333,8 @@
 	clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
 	wake_up_interruptible(&pty->open_wait);
 	set_bit(TTY_THROTTLED, &tty->flags);
+	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
 	/*  Register a slave for the master  */
 	if (tty->driver.major == PTY_MASTER_MAJOR)
 		tty_register_devfs(&tty->link->driver,
diff -Nru a/drivers/char/q40_keyb.c b/drivers/char/q40_keyb.c
--- a/drivers/char/q40_keyb.c	Fri Oct 11 21:22:58 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,443 +0,0 @@
-/*
- * linux/drivers/char/q40_keyb.c
- *
- */
-
-#include <linux/config.h>
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/keyboard.h>
-#include <linux/signal.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/kbd_kern.h>
-#include <linux/delay.h>
-#include <linux/sysrq.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-
-#include <asm/keyboard.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/q40_master.h>
-#include <asm/irq.h>
-#include <asm/q40ints.h>
-
-
-/* Simple translation table for the SysRq keys */
-
-#define SYSRQ_KEY 0x54
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char q40kbd_sysrq_xlate[128] =
-	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
-	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
-	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
-	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
-	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
-	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-	"\r\000/";					/* 0x60 - 0x6f */
-#endif
-
-/* Q40 uses AT scancodes - no way to change it. so we have to translate ..*/
-/* 0x00 means not a valid entry or no conversion known                    */
-
-unsigned static char q40cl[256] =
-{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   f, */
- 0x00,0x43,0x00,0x3f,0x3d,0x3b,0x3c,0x58,0x00,0x44,0x42,0x40,0x3e,0x0f,0x29,0x00,     /* 0x00 - 0x0f */
- 0x00,0x38,0x2a,0x00,0x1d,0x10,0x02,0x00,0x00,0x00,0x2c,0x1f,0x1e,0x11,0x03,0x00,     /* 0x10 - 0x1f */
- 0x00,0x2e,0x2d,0x20,0x12,0x05,0x04,0x00,0x21,0x39,0x2f,0x21,0x14,0x13,0x06,0x00,     /* 0x20 - 0x2f  'f' is at 0x2b, what is 0x28 ???*/
- 0x00,0x31,0x30,0x23,0x22,0x15,0x07,0x00,0x24,0x00,0x32,0x24,0x16,0x08,0x09,0x00,     /* 0x30 - 0x3f */
- 0x00,0x33,0x25,0x17,0x18,0x0b,0x0a,0x00,0x00,0x34,0x35,0x26,0x27,0x19,0x0c,0x00,     /* 0x40 - 0x4f */
- 0x00,0x00,0x28,0x00,0x1a,0x0d,0x00,0x00,0x3a,0x36,0x1c,0x1b,0x00,0x2b,0x00,0x00,     /* 0x50 - 0x5f*/
- 0x00,0x56,0x00,0x00,0x00,0x00,0x0e,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,     /* 0x60 - 0x6f */
- 0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x00,     /* 0x70 - 0x7f */
- 0x00,0x00,0x00,0x41,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x80 - 0x8f  0x84/0x37 is SySrq*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x90 - 0x9f */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xa0 - 0xaf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xb0 - 0xbf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xc0 - 0xcf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xd0 - 0xdf */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xe0 - 0xef */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xf0 - 0xff */
-};
-
-/* another table, AT 0xe0 codes to PC 0xe0 codes, 
-   0xff special entry for SysRq - DROPPED right now  */
-static unsigned char q40ecl[]=
-{/* 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   a,   b,   c,   d,   e,   f, */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x00 - 0x0f*/
- 0x00,0x38,0x2a,0x00,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x10 - 0x1f */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x20 - 0x2f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x30 - 0x3f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x00,0x00,     /* 0x40 - 0x4f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,     /* 0x50 - 0x5f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0x00,0x4b,0x47,0x00,0x00,0x00,     /* 0x60 - 0x6f*/
- 0x52,0x53,0x50,0x00,0x4d,0x48,0x00,0x00,0x00,0x00,0x51,0x00,0x00,0x49,0x00,0x00,     /* 0x70 - 0x7f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x80 - 0x8f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0x90 - 0x9f*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xa0 - 0xaf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xb0 - 0xbf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xc0 - 0xcf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xd0 - 0xdf*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,     /* 0xe0 - 0xef*/
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00      /* 0xf0 - 0xff*/
-};
-
-
-static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
-
-
-/*
- * Translation of escaped scancodes to keycodes.
- * This is now user-settable.
- * The keycodes 1-88,96-111,119 are fairly standard, and
- * should probably not be changed - changing might confuse X.
- * X also interprets scancode 0x5d (KEY_Begin).
- *
- * For 1-88 keycode equals scancode.
- */
-
-#define E0_KPENTER 96
-#define E0_RCTRL   97
-#define E0_KPSLASH 98
-#define E0_PRSCR   99
-#define E0_RALT    100
-#define E0_BREAK   101  /* (control-pause) */
-#define E0_HOME    102
-#define E0_UP      103
-#define E0_PGUP    104
-#define E0_LEFT    105
-#define E0_RIGHT   106
-#define E0_END     107
-#define E0_DOWN    108
-#define E0_PGDN    109
-#define E0_INS     110
-#define E0_DEL     111
-
-#define E1_PAUSE   119
-
-/*
- * The keycodes below are randomly located in 89-95,112-118,120-127.
- * They could be thrown away (and all occurrences below replaced by 0),
- * but that would force many users to use the `setkeycodes' utility, where
- * they needed not before. It does not matter that there are duplicates, as
- * long as no duplication occurs for any single keyboard.
- */
-#define SC_LIM 89
-
-#define FOCUS_PF1 85           /* actual code! */
-#define FOCUS_PF2 89
-#define FOCUS_PF3 90
-#define FOCUS_PF4 91
-#define FOCUS_PF5 92
-#define FOCUS_PF6 93
-#define FOCUS_PF7 94
-#define FOCUS_PF8 95
-#define FOCUS_PF9 120
-#define FOCUS_PF10 121
-#define FOCUS_PF11 122
-#define FOCUS_PF12 123
-
-#define JAP_86     124
-/* tfj@olivia.ping.dk:
- * The four keys are located over the numeric keypad, and are
- * labelled A1-A4. It's an rc930 keyboard, from
- * Regnecentralen/RC International, Now ICL.
- * Scancodes: 59, 5a, 5b, 5c.
- */
-#define RGN1 124
-#define RGN2 125
-#define RGN3 126
-#define RGN4 127
-
-static unsigned char high_keys[128 - SC_LIM] = {
-  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
-  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
-  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
-  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
-  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
-  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
-};
-
-/* BTC */
-#define E0_MACRO   112
-/* LK450 */
-#define E0_F13     113
-#define E0_F14     114
-#define E0_HELP    115
-#define E0_DO      116
-#define E0_F17     117
-#define E0_KPMINPLUS 118
-/*
- * My OmniKey generates e0 4c for  the "OMNI" key and the
- * right alt key does nada. [kkoller@nyx10.cs.du.edu]
- */
-#define E0_OK	124
-/*
- * New microsoft keyboard is rumoured to have
- * e0 5b (left window button), e0 5c (right window button),
- * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
- * [or: Windows_L, Windows_R, TaskMan]
- */
-#define E0_MSLW	125
-#define E0_MSRW	126
-#define E0_MSTM	127
-
-/* this can be changed using setkeys : */
-static unsigned char e0_keys[128] = {
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
-  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
-  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
-  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
-  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
-  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
-  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
-  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
-  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
-  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
-  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
-};
-
-
-int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
-	  return -EINVAL;
-	if (scancode < 128)
-	  high_keys[scancode - SC_LIM] = keycode;
-	else
-	  e0_keys[scancode - 128] = keycode;
-	return 0;
-}
-
-int q40kbd_getkeycode(unsigned int scancode)
-{
-	return
-	  (scancode < SC_LIM || scancode > 255) ? -EINVAL :
-	  (scancode < 128) ? high_keys[scancode - SC_LIM] :
-	    e0_keys[scancode - 128];
-}
-
-
-#define disable_keyboard()	
-#define enable_keyboard()	
-
-
-
-
-int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
-		    char raw_mode)
-{
-	static int prev_scancode;
-
-	/* special prefix scancodes.. */
-	if (scancode == 0xe0 || scancode == 0xe1) {
-		prev_scancode = scancode;
-		return 0;
-	}
-
-	/* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
-	if (scancode == 0x00 || scancode == 0xff) {
-		prev_scancode = 0;
-		return 0;
-	}
-
-	scancode &= 0x7f;
-
-	if (prev_scancode) {
-	  /*
-	   * usually it will be 0xe0, but a Pause key generates
-	   * e1 1d 45 e1 9d c5 when pressed, and nothing when released
-	   */
-	  if (prev_scancode != 0xe0) {
-	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
-		  prev_scancode = 0x100;
-		  return 0;
-	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
-		  *keycode = E1_PAUSE;
-		  prev_scancode = 0;
-	      } else {
-#ifdef KBD_REPORT_UNKN
-		  if (!raw_mode)
-		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
-#endif
-		  prev_scancode = 0;
-		  return 0;
-	      }
-	  } else {
-	      prev_scancode = 0;
-	      /*
-	       *  The keyboard maintains its own internal caps lock and
-	       *  num lock statuses. In caps lock mode E0 AA precedes make
-	       *  code and E0 2A follows break code. In num lock mode,
-	       *  E0 2A precedes make code and E0 AA follows break code.
-	       *  We do our own book-keeping, so we will just ignore these.
-	       */
-	      /*
-	       *  For my keyboard there is no caps lock mode, but there are
-	       *  both Shift-L and Shift-R modes. The former mode generates
-	       *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
-	       *  So, we should also ignore the latter. - aeb@cwi.nl
-	       */
-	      if (scancode == 0x2a || scancode == 0x36)
-		return 0;
-
-	      if (e0_keys[scancode])
-		*keycode = e0_keys[scancode];
-	      else {
-#ifdef KBD_REPORT_UNKN
-		  if (!raw_mode)
-		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
-			   scancode);
-#endif
-		  return 0;
-	      }
-	  }
-	} else if (scancode >= SC_LIM) {
-	    /* This happens with the FOCUS 9000 keyboard
-	       Its keys PF1..PF12 are reported to generate
-	       55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
-	       Moreover, unless repeated, they do not generate
-	       key-down events, so we have to zero up_flag below */
-	    /* Also, Japanese 86/106 keyboards are reported to
-	       generate 0x73 and 0x7d for \ - and \ | respectively. */
-	    /* Also, some Brazilian keyboard is reported to produce
-	       0x73 and 0x7e for \ ? and KP-dot, respectively. */
-
-	  *keycode = high_keys[scancode - SC_LIM];
-
-	  if (!*keycode) {
-	      if (!raw_mode) {
-#ifdef KBD_REPORT_UNKN
-		  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
-			 " - ignored\n", scancode);
-#endif
-	      }
-	      return 0;
-	  }
- 	} else
-	  *keycode = scancode;
- 	return 1;
-}
-
-char q40kbd_unexpected_up(unsigned char keycode)
-{
-	/* unexpected, but this can happen: maybe this was a key release for a
-	   FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
-	if (keycode >= SC_LIM || keycode == 85)
-	    return 0;
-	else
-	    return 0200;
-}
-
-static int keyup=0;
-static int qprev=0;
-
-static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned char status;
-
-	spin_lock(&kbd_controller_lock);
-	kbd_pt_regs = regs;
-
-	status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
-	if (status ) 
-	  {
-	    unsigned char scancode,qcode;
-	    
-	    qcode = master_inb(KEYCODE_REG);
-	    
-	    if (qcode != 0xf0)
-	      {
-		if (qcode == 0xe0)
-		  {
-		    qprev=0xe0;
-		    handle_scancode(qprev , 1);
-		    goto exit;
-		  }
-		
-		scancode=qprev ? q40ecl[qcode] : q40cl[qcode];
-#if 0
-/* next line is last resort to hanlde some oddities */
-		if (qprev && !scancode) scancode=q40cl[qcode];
-#endif
-		qprev=0;
-		if (!scancode)
-		  {
-		    printk("unknown scancode %x\n",qcode);
-		    goto exit;
-		  }
-		if (scancode==0xff)  /* SySrq */
-		  scancode=SYSRQ_KEY;
-
-		handle_scancode(scancode, ! keyup );
-		keyup=0;
-		tasklet_schedule(&keyboard_tasklet);
-	      }
-	    else
-	      keyup=1;
-	  }
-exit:
-	spin_unlock(&kbd_controller_lock);
-	master_outb(-1,KEYBOARD_UNLOCK_REG); /* keyb ints reenabled herewith */
-}
-
-
-#define KBD_NO_DATA	(-1)	/* No data */
-#define KBD_BAD_DATA	(-2)	/* Parity or other error */
-
-static int __init kbd_read_input(void)
-{
-	int retval = KBD_NO_DATA;
-	unsigned char status;
-
-	status = IRQ_KEYB_MASK & master_inb(INTERRUPT_REG);
-	if (status) {
-		unsigned char data = master_inb(KEYCODE_REG);
-
-		retval = data;
-		master_outb(-1,KEYBOARD_UNLOCK_REG);
-	}
-	return retval;
-}
-
-
-static void __init kbd_clear_input(void)
-{
-	int maxread = 100;	/* Random number */
-
-	do {
-		if (kbd_read_input() == KBD_NO_DATA)
-			break;
-	} while (--maxread);
-}
-
-
-int __init q40kbd_init_hw(void)
-{
-
-	/* Flush any pending input. */
-	kbd_clear_input();
-
-	/* Ok, finally allocate the IRQ, and off we go.. */
-	request_irq(Q40_IRQ_KEYBOARD, keyboard_interrupt, 0, "keyboard", NULL);
-	master_outb(-1,KEYBOARD_UNLOCK_REG);
-	master_outb(1,KEY_IRQ_ENABLE_REG);
-
-	return 0;
-}
-
diff -Nru a/drivers/char/qtronix.c b/drivers/char/qtronix.c
--- a/drivers/char/qtronix.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/char/qtronix.c	Fri Oct 11 21:22:55 2002
@@ -51,6 +51,7 @@
 
 #ifdef CONFIG_QTRONIX_KEYBOARD
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -121,7 +122,7 @@
 
 };
 
-void init_qtronix_990P_kbd(void)
+void __init init_qtronix_990P_kbd(void)
 {
 	int retval;
 
@@ -592,4 +593,5 @@
 
 	return 0;
 }
+module_init(init_qtronix_990P_kbd);
 #endif
diff -Nru a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/char/random.c	Fri Oct 11 21:22:53 2002
@@ -414,13 +414,13 @@
  * deal with a variable rotate of x bits.  So we use a bit of asm magic.
  */
 #if (!defined (__i386__))
-extern inline __u32 rotate_left(int i, __u32 word)
+static inline __u32 rotate_left(int i, __u32 word)
 {
 	return (word << i) | (word >> (32 - i));
 	
 }
 #else
-extern inline __u32 rotate_left(int i, __u32 word)
+static inline __u32 rotate_left(int i, __u32 word)
 {
 	__asm__("roll %%cl,%0"
 		:"=r" (word)
@@ -1643,7 +1643,7 @@
 			return -EINVAL;
 		if (size > random_state->poolinfo.poolwords)
 			size = random_state->poolinfo.poolwords;
-		if (copy_to_user(p, random_state->pool, size * 4))
+		if (copy_to_user(p, random_state->pool, size * sizeof(__u32)))
 			return -EFAULT;
 		return 0;
 	case RNDADDENTROPY:
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/char/raw.c	Fri Oct 11 21:23:00 2002
@@ -30,6 +30,10 @@
 /*
  * Open/close code for raw IO.
  *
+ * We just rewrite the i_mapping for the /dev/raw/rawN file descriptor to
+ * point at the blockdev's address_space and set the file handle to use
+ * O_DIRECT.
+ *
  * Set the device's soft blocksize to the minimum possible.  This gives the
  * finest possible alignment and has no adverse impact on performance.
  */
@@ -56,7 +60,12 @@
 		err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW);
 		if (!err) {
 			err = set_blocksize(bdev, bdev_hardsect_size(bdev));
-			raw_devices[minor].inuse++;
+			if (err == 0) {
+				raw_devices[minor].inuse++;
+				filp->f_dentry->d_inode->i_mapping =
+					bdev->bd_inode->i_mapping;
+				filp->f_flags |= O_DIRECT;
+			}
 		}
 	}
 	up(&raw_mutex);
@@ -200,72 +209,22 @@
 	return err;
 }
 
-static ssize_t
-rw_raw_dev(int rw, struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *offp)
+static ssize_t raw_file_write(struct file *file, const char *buf,
+				   size_t count, loff_t *ppos)
 {
-	const int minor = minor(filp->f_dentry->d_inode->i_rdev);
-	struct block_device *bdev = raw_devices[minor].binding;
-	struct inode *inode = bdev->bd_inode;
- 	size_t count = iov_length(iov, nr_segs); 
-	ssize_t ret = 0;
-
-	if (count == 0)
-		goto out;	
-
-	if ((ssize_t)count < 0)
-		return -EINVAL;	
-
-	if (*offp >= inode->i_size) 
-		return -ENXIO;
-
-	if (count + *offp > inode->i_size) {
-		count = inode->i_size - *offp;
-		nr_segs = iov_shorten((struct iovec *)iov, nr_segs, count);
-	}
-	ret = generic_file_direct_IO(rw, filp, iov, *offp, nr_segs);
-
-	if (ret > 0)
-		*offp += ret;
-out:
-	return ret;
-}
-
-static ssize_t
-raw_read(struct file *filp, char *buf, size_t size, loff_t *offp)
-{
-	struct iovec local_iov = { .iov_base = buf, .iov_len = size};
-
-	return rw_raw_dev(READ, filp, &local_iov, 1, offp);
-}
+	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
 
-static ssize_t
-raw_write(struct file *filp, const char *buf, size_t size, loff_t *offp)
-{
-	struct iovec local_iov = { .iov_base = (char *)buf, .iov_len = size};
-
-	return rw_raw_dev(WRITE, filp, &local_iov, 1, offp);
-}
-
-static ssize_t 
-raw_readv(struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *offp) 
-{
-	return rw_raw_dev(READ, filp, iov, nr_segs, offp);
-}
-
-static ssize_t 
-raw_writev(struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *offp) 
-{
-	return rw_raw_dev(WRITE, filp, iov, nr_segs, offp);
+	return generic_file_write_nolock(file, &local_iov, 1, ppos);
 }
 
 static struct file_operations raw_fops = {
-	.read	=	raw_read,
-	.write	=	raw_write,
+	.read	=	generic_file_read,
+	.write	=	raw_file_write,
 	.open	=	raw_open,
 	.release=	raw_release,
 	.ioctl	=	raw_ioctl,
-	.readv	= 	raw_readv,
-	.writev	= 	raw_writev,
+	.readv	= 	generic_file_readv,
+	.writev	= 	generic_file_writev,
 	.owner	=	THIS_MODULE,
 };
 
diff -Nru a/drivers/char/riscom8.c b/drivers/char/riscom8.c
--- a/drivers/char/riscom8.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/char/riscom8.c	Fri Oct 11 21:22:58 2002
@@ -873,10 +873,10 @@
 		return 0;
 	
 	if (!port->xmit_buf) {
-		/* We may sleep in get_free_page() */
+		/* We may sleep in get_zeroed_page() */
 		unsigned long tmp;
 		
-		if (!(tmp = get_free_page(GFP_KERNEL)))
+		if (!(tmp = get_zeroed_page(GFP_KERNEL)))
 			return -ENOMEM;
 		    
 		if (port->xmit_buf) {
@@ -1747,7 +1747,7 @@
 	int i;
 
 	
-	if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {
+	if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
 		printk(KERN_ERR "rc: Couldn't get free page.\n");
 		return 1;
 	}
diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c
--- a/drivers/char/rocket.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/char/rocket.c	Fri Oct 11 21:22:54 2002
@@ -826,7 +826,7 @@
 	if ((line < 0) || (line >= MAX_RP_PORTS))
 		return -ENODEV;
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page)
 			return -ENOMEM;
 		if (tmp_buf)
@@ -834,7 +834,7 @@
 		else
 			tmp_buf = (unsigned char *) page;
 	}
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c
--- a/drivers/char/serial167.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/char/serial167.c	Fri Oct 11 21:22:56 2002
@@ -802,7 +802,7 @@
 	return 0;
     }
     if (!info->xmit_buf){
-	info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
+	info->xmit_buf = (unsigned char *) get_zeroed_page (GFP_KERNEL);
 	if (!info->xmit_buf){
 	    return -ENOMEM;
 	}
@@ -2158,7 +2158,7 @@
     info->tty = tty;
 
     if (!tmp_buf) {
-	tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+	tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
 	if (!tmp_buf){
 	    return -ENOMEM;
         }
diff -Nru a/drivers/char/specialix.c b/drivers/char/specialix.c
--- a/drivers/char/specialix.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/char/specialix.c	Fri Oct 11 21:23:03 2002
@@ -1232,10 +1232,10 @@
 		return 0;
 	
 	if (!port->xmit_buf) {
-		/* We may sleep in get_free_page() */
+		/* We may sleep in get_zeroed_page() */
 		unsigned long tmp;
 		
-		if (!(tmp = get_free_page(GFP_KERNEL)))
+		if (!(tmp = get_zeroed_page(GFP_KERNEL)))
 			return -ENOMEM;
 
 		if (port->xmit_buf) {
@@ -2226,7 +2226,7 @@
 	int i;
 
 	
-	if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {
+	if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
 		printk(KERN_ERR "sx: Couldn't get free page.\n");
 		return 1;
 	}
diff -Nru a/drivers/char/sx.c b/drivers/char/sx.c
--- a/drivers/char/sx.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/char/sx.c	Fri Oct 11 21:22:55 2002
@@ -404,11 +404,11 @@
 
 
 
-#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ "\n")
-#define func_exit()  sx_dprintk (SX_DEBUG_FLOW, "sx: exit  " __FUNCTION__ "\n")
+#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\b",__FUNCTION__)
+#define func_exit()  sx_dprintk (SX_DEBUG_FLOW, "sx: exit  %s\n", __FUNCTION__)
 
-#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter " __FUNCTION__ \
-                                  "(port %d)\n", port->line)
+#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
+					__FUNCTION__, port->line)
 
 
 
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/char/synclink.c	Fri Oct 11 21:22:55 2002
@@ -1788,7 +1788,7 @@
 	
 	if (!info->xmit_buf) {
 		/* allocate a page of memory for a transmit buffer */
-		info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL);
+		info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
 		if (!info->xmit_buf) {
 			printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n",
 				__FILE__,__LINE__,info->device_name);
@@ -3633,7 +3633,7 @@
 	}
 	
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
 			retval = -ENOMEM;
 			goto cleanup;
@@ -8002,7 +8002,7 @@
 {
 	struct mgsl_struct *info = d->priv;
 	int err;
-	long flags;
+	unsigned long flags;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("mgsl_sppp_open(%s)\n",info->netname);	
@@ -8045,7 +8045,7 @@
 void mgsl_sppp_tx_timeout(struct net_device *dev)
 {
 	struct mgsl_struct *info = dev->priv;
-	long flags;
+	unsigned long flags;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("mgsl_sppp_tx_timeout(%s)\n",info->netname);	
diff -Nru a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
--- a/drivers/char/vt_ioctl.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/char/vt_ioctl.c	Fri Oct 11 21:23:02 2002
@@ -430,6 +430,7 @@
 	case KDKBDREP:
 	{
 		struct kbd_repeat kbrep;
+		int err;
 		
 		if (!capable(CAP_SYS_TTY_CONFIG))
 			return -EPERM;
@@ -437,8 +438,9 @@
 		if (copy_from_user(&kbrep, (void *)arg,
 				   sizeof(struct kbd_repeat)))
 			return -EFAULT;
-		if ((i = kbd_rate( &kbrep )))
-			return i;
+		err = kbd_rate(&kbrep);
+		if (err)
+			return err;
 		if (copy_to_user((void *)arg, &kbrep,
 				 sizeof(struct kbd_repeat)))
 			return -EFAULT;
diff -Nru a/drivers/char/w83877f_wdt.c b/drivers/char/w83877f_wdt.c
--- a/drivers/char/w83877f_wdt.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/char/w83877f_wdt.c	Fri Oct 11 21:23:00 2002
@@ -192,8 +192,13 @@
 
 		/* now scan */
 		for(ofs = 0; ofs != count; ofs++)
-			if(buf[ofs] == 'V')
+		{
+			char c;
+			if (get_user(c, buf + ofs))
+				return -EFAULT;
+			if (c == 'V')
 				wdt_expect_close = 1;
+		}
 
 		/* someone wrote to us, we should restart timer */
 		next_heartbeat = jiffies + WDT_HEARTBEAT;
diff -Nru a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
--- a/drivers/char/wdt_pci.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/char/wdt_pci.c	Fri Oct 11 21:23:00 2002
@@ -523,13 +523,13 @@
 		return -ENODEV;
 	}
 
+	if (pci_enable_device (dev))
+		goto out;
+
 	irq = dev->irq;
 	io = pci_resource_start (dev, 2);
 	printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
 		"(Interrupt %d)\n", io, irq);
-
-	if (pci_enable_device (dev))
-		goto out;
 
 	if (request_region (io, 16, "wdt-pci") == NULL) {
 		printk (KERN_ERR PFX "I/O %d is not free.\n", io);
diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help
--- a/drivers/ide/Config.help	Fri Oct 11 21:23:03 2002
+++ b/drivers/ide/Config.help	Fri Oct 11 21:23:03 2002
@@ -258,6 +258,37 @@
 
   If in doubt, say N.
 
+CONFIG_BLK_DEV_IDE_TCQ
+  Support for tagged command queueing on ATA disk drives. This enables
+  the IDE layer to have multiple in-flight requests on hardware that
+  supports it. For now this includes the IBM Deskstar series drives,
+  such as the 22GXP, 75GXP, 40GV, 60GXP, and 120GXP (ie any Deskstar made
+  in the last couple of years), and at least some of the Western
+  Digital drives in the Expert series (by nature of really being IBM
+  drives).
+
+  If you have such a drive, say Y here.
+
+CONFIG_BLK_DEV_IDE_TCQ_DEPTH
+  Maximum size of commands to enable per-drive. Any value between 1
+  and 32 is valid, with 32 being the maxium that the hardware supports.
+
+  You probably just want the default of 32 here. If you enter an invalid
+  number, the default value will be used.
+
+CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+  Enable tagged command queueing unconditionally on drives that report
+  support for it. Regardless of the chosen value here, tagging can be
+  controlled at run time:
+
+  echo "using_tcq:32" > /proc/ide/hdX/settings
+
+  where any value between 1-32 selects chosen queue depth and enables
+  TCQ, and 0 disables it. hdparm version 4.7 an above also support
+  TCQ manipulations.
+
+  Generally say Y here.
+
 CONFIG_BLK_DEV_OFFBOARD
   Normally, IDE controllers built into the motherboard (on-board
   controllers) are assigned to ide0 and ide1 while those on add-in PCI
@@ -713,10 +744,10 @@
   Support for tagged command queueing on ATA disk drives. This enables
   the IDE layer to have multiple in-flight requests on hardware that
   supports it. For now this includes the IBM Deskstar series drives,
-  such as the 22GXP, 75GXP, 40GV, 60GXP, and 120GXP (ie any Deskstar made
-  in the last couple of years), and at least some of the Western
-  Digital drives in the Expert series (by nature of really being IBM
-  drives).
+  such as the 22GXP, 75GXP, 40GV, 60GXP, 120GXP, and 180GXP (ie any
+  Deskstar made in the last couple of years), and at least some of
+  the Western Digital drives in the Expert series (by nature of really
+  being IBM drives).
 
   However, please, note that there are host chip controllers which will
   not cooperate properly if TCQ is enabled. This may cause serious
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Fri Oct 11 21:22:54 2002
+++ b/drivers/ide/Config.in	Fri Oct 11 21:22:54 2002
@@ -36,6 +36,11 @@
 	    dep_bool '    Generic PCI IDE Chipset Support' CONFIG_BLK_DEV_GENERIC $CONFIG_BLK_DEV_IDEPCI
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    ATA tagged command queueing (EXPERIMENTAL)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
+	    dep_bool '      TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ
+	    if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then
+		int '      Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 8
+	    fi
 	    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
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	Fri Oct 11 21:22:58 2002
+++ b/drivers/ide/Makefile	Fri Oct 11 21:22:58 2002
@@ -22,6 +22,7 @@
 
 obj-$(CONFIG_BLK_DEV_IDEPCI)		+= setup-pci.o
 obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
+obj-$(CONFIG_BLK_DEV_IDE_TCQ)		+= ide-tcq.o
 obj-$(CONFIG_BLK_DEV_ISAPNP)		+= ide-pnp.o
 
 ifeq ($(CONFIG_BLK_DEV_IDE),y)
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/ide/ide-cd.c	Fri Oct 11 21:22:57 2002
@@ -1163,7 +1163,7 @@
 	if (rq->current_nr_sectors < bio_sectors(rq->bio) &&
 	    (rq->sector % SECTORS_PER_FRAME) != 0) {
 		printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
-			drive->name, rq->sector);
+			drive->name, (long)rq->sector);
 		cdrom_end_request(drive, 0);
 		return -1;
 	}
@@ -1750,7 +1750,7 @@
  * cdrom driver request routine.
  */
 static ide_startstop_t
-ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block)
+ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
 {
 	ide_startstop_t action;
 	struct cdrom_info *info = drive->driver_data;
@@ -2563,26 +2563,26 @@
  * Device initialization.
  */
 static struct cdrom_device_ops ide_cdrom_dops = {
-	open:			ide_cdrom_open_real,
-	release:		ide_cdrom_release_real,
-	drive_status:		ide_cdrom_drive_status,
-	media_changed:		ide_cdrom_check_media_change_real,
-	tray_move:		ide_cdrom_tray_move,
-	lock_door:		ide_cdrom_lock_door,
-	select_speed:		ide_cdrom_select_speed,
-	get_last_session:	ide_cdrom_get_last_session,
-	get_mcn:		ide_cdrom_get_mcn,
-	reset:			ide_cdrom_reset,
-	audio_ioctl:		ide_cdrom_audio_ioctl,
-	dev_ioctl:		ide_cdrom_dev_ioctl,
-	capability:		CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
+	.open			= ide_cdrom_open_real,
+	.release		= ide_cdrom_release_real,
+	.drive_status		= ide_cdrom_drive_status,
+	.media_changed		= ide_cdrom_check_media_change_real,
+	.tray_move		= ide_cdrom_tray_move,
+	.lock_door		= ide_cdrom_lock_door,
+	.select_speed		= ide_cdrom_select_speed,
+	.get_last_session	= ide_cdrom_get_last_session,
+	.get_mcn		= ide_cdrom_get_mcn,
+	.reset			= ide_cdrom_reset,
+	.audio_ioctl		= ide_cdrom_audio_ioctl,
+	.dev_ioctl		= ide_cdrom_dev_ioctl,
+	.capability		= CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
 				CDC_SELECT_SPEED | CDC_SELECT_DISC |
 				CDC_MULTI_SESSION | CDC_MCN |
 				CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET |
 				CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R |
 				CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
 				CDC_GENERIC_PACKET,
-	generic_packet:		ide_cdrom_packet,
+	.generic_packet		= ide_cdrom_packet,
 };
 
 static int ide_cdrom_register (ide_drive_t *drive, int nslots)
@@ -2775,12 +2775,14 @@
 static int ll_10byte_cmd_build(request_queue_t *q, struct request *rq)
 {
 	int hard_sect = queue_hardsect_size(q);
-	sector_t block = rq->hard_sector / (hard_sect >> 9);
+	long block = (long)rq->hard_sector / (hard_sect >> 9);
 	unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9);
 
 	if (!(rq->flags & REQ_CMD))
 		return 0;
 
+	BUG_ON(sizeof(rq->hard_sector) > 4 && (rq->hard_sector >> 32));
+
 	if (rq->hard_nr_sectors != rq->nr_sectors) {
 		printk(KERN_ERR "ide-cd: hard_nr_sectors differs from nr_sectors! %lu %lu\n",
 				rq->nr_sectors, rq->hard_nr_sectors);
@@ -3048,39 +3050,39 @@
 static int ide_cdrom_attach (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
-	owner:			THIS_MODULE,
-	name:			"ide-cdrom",
-	version:		IDECD_VERSION,
-	media:			ide_cdrom,
-	busy:			0,
+	.owner			= THIS_MODULE,
+	.name			= "ide-cdrom",
+	.version		= IDECD_VERSION,
+	.media			= ide_cdrom,
+	.busy			= 0,
 #ifdef CONFIG_IDEDMA_ONLYDISK
-	supports_dma:		0,
+	.supports_dma		= 0,
 #else
-	supports_dma:		1,
+	.supports_dma		= 1,
 #endif
-	supports_dsc_overlap:	1,
-	cleanup:		ide_cdrom_cleanup,
-	standby:		NULL,
-	suspend:		NULL,
-	resume:			NULL,
-	flushcache:		NULL,
-	do_request:		ide_do_rw_cdrom,
-	end_request:		NULL,
-	sense:			ide_cdrom_dump_status,
-	error:			ide_cdrom_error,
-	ioctl:			ide_cdrom_ioctl,
-	open:			ide_cdrom_open,
-	release:		ide_cdrom_release,
-	media_change:		ide_cdrom_check_media_change,
-	revalidate:		ide_cdrom_revalidate,
-	pre_reset:		NULL,
-	capacity:		ide_cdrom_capacity,
-	special:		NULL,
-	proc:			NULL,
-	attach:			ide_cdrom_attach,
-	ata_prebuilder:		NULL,
-	atapi_prebuilder:	NULL,
-	drives:			LIST_HEAD_INIT(ide_cdrom_driver.drives),
+	.supports_dsc_overlap	= 1,
+	.cleanup		= ide_cdrom_cleanup,
+	.standby		= NULL,
+	.suspend		= NULL,
+	.resume			= NULL,
+	.flushcache		= NULL,
+	.do_request		= ide_do_rw_cdrom,
+	.end_request		= NULL,
+	.sense			= ide_cdrom_dump_status,
+	.error			= ide_cdrom_error,
+	.ioctl			= ide_cdrom_ioctl,
+	.open			= ide_cdrom_open,
+	.release		= ide_cdrom_release,
+	.media_change		= ide_cdrom_check_media_change,
+	.revalidate		= ide_cdrom_revalidate,
+	.pre_reset		= NULL,
+	.capacity		= ide_cdrom_capacity,
+	.special		= NULL,
+	.proc			= NULL,
+	.attach			= ide_cdrom_attach,
+	.ata_prebuilder		= NULL,
+	.atapi_prebuilder	= NULL,
+	.drives			= LIST_HEAD_INIT(ide_cdrom_driver.drives),
 };
 
 /* options */
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/ide/ide-disk.c	Fri Oct 11 21:22:56 2002
@@ -352,13 +352,26 @@
 	return DRIVER(drive)->error(drive, "multwrite_intr", stat);
 }
 
+static int idedisk_start_tag(ide_drive_t *drive, struct request *rq)
+{
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	if (ata_pending_commands(drive) < drive->queue_depth)
+		ret = blk_queue_start_tag(&drive->queue, rq);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ret;
+}
 
 /*
  * 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 do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
@@ -375,6 +388,13 @@
 		return promise_rw_disk(drive, rq, block);
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 
+	if (drive->using_tcq && idedisk_start_tag(drive, rq)) {
+		if (!ata_pending_commands(drive))
+			BUG();
+
+		return ide_started;
+	}
+
 	if (IDE_CONTROL_REG)
 		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 
@@ -382,23 +402,34 @@
 		if (drive->addressing == 1) {
 			task_ioreg_t tasklets[10];
 
-			tasklets[0] = 0;
-			tasklets[1] = 0;
-			tasklets[2] = nsectors.b.low;
-			tasklets[3] = nsectors.b.high;
+			if (blk_rq_tagged(rq)) {
+				tasklets[0] = nsectors.b.low;
+				tasklets[1] = nsectors.b.high;
+				tasklets[2] = rq->tag << 3;
+				tasklets[3] = 0;
+			} else {
+				tasklets[0] = 0;
+				tasklets[1] = 0;
+				tasklets[2] = nsectors.b.low;
+				tasklets[3] = nsectors.b.high;
+			}
+
 			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);
+			if (sizeof(block) == 4) {
+				tasklets[8] = (task_ioreg_t) 0;
+				tasklets[9] = (task_ioreg_t) 0;
+			} else {
+				tasklets[8] = (task_ioreg_t)((u64)block >> 32);
+				tasklets[9] = (task_ioreg_t)((u64)block >> 40);
+			}
 #ifdef DEBUG
 			printk("%s: %sing: LBAsect=%lu, sectors=%ld, "
 				"buffer=0x%08lx, LBAsect=0x%012lx\n",
 				drive->name,
-				(rq->cmd==READ)?"read":"writ",
+				rq_data_dir(rq)==READ?"read":"writ",
 				block,
 				rq->nr_sectors,
 				(unsigned long) rq->buffer,
@@ -422,14 +453,21 @@
 			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
 		} else {
 #ifdef DEBUG
-			printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+			printk("%s: %sing: LBAsect=%llu, sectors=%ld, "
 				"buffer=0x%08lx\n",
-				drive->name, (rq->cmd==READ)?"read":"writ",
-				block, rq->nr_sectors,
+				drive->name,
+				rq_data_dir(rq)==READ?"read":"writ",
+				(unsigned long long)block, rq->nr_sectors,
 				(unsigned long) rq->buffer);
 #endif
-			hwif->OUTB(0x00, IDE_FEATURE_REG);
-			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+			if (blk_rq_tagged(rq)) {
+				hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG);
+				hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG);
+			} else {
+				hwif->OUTB(0x00, IDE_FEATURE_REG);
+				hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+			}
+
 			hwif->OUTB(block, IDE_SECTOR_REG);
 			hwif->OUTB(block>>=8, IDE_LCYL_REG);
 			hwif->OUTB(block>>=8, IDE_HCYL_REG);
@@ -437,29 +475,37 @@
 		}
 	} else {
 		unsigned int sect,head,cyl,track;
-		track = block / drive->sect;
-		sect  = block % drive->sect + 1;
+		track = (int)block / drive->sect;
+		sect  = (int)block % drive->sect + 1;
 		hwif->OUTB(sect, IDE_SECTOR_REG);
 		head  = track % drive->head;
 		cyl   = track / drive->head;
 
-		hwif->OUTB(0x00, IDE_FEATURE_REG);
-		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+		if (blk_rq_tagged(rq)) {
+			hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG);
+			hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG);
+		} else {
+			hwif->OUTB(0x00, IDE_FEATURE_REG);
+			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+		}
+
 		hwif->OUTB(cyl, IDE_LCYL_REG);
 		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
 		hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
 #ifdef DEBUG
 		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
-			drive->name, (rq->cmd==READ)?"read":"writ", cyl,
+			drive->name, rq_data_dir(rq)==READ?"read":"writ", cyl,
 			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
 #endif
 	}
 
 	if (rq_data_dir(rq) == READ) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (blk_rq_tagged(rq))
+			return hwif->ide_dma_queued_read(drive);
+
 		if (drive->using_dma && !hwif->ide_dma_read(drive))
 			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+
 		if (HWGROUP(drive)->handler != NULL)
 			BUG();
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
@@ -471,10 +517,12 @@
 		return ide_started;
 	} else if (rq_data_dir(rq) == WRITE) {
 		ide_startstop_t startstop;
-#ifdef CONFIG_BLK_DEV_IDEDMA
+
+		if (blk_rq_tagged(rq))
+			return hwif->ide_dma_queued_write(drive);
+
 		if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
 			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 		command = ((drive->mult_count) ?
 			   ((lba48) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE) :
@@ -542,7 +590,7 @@
  * using LBA if supported, or CHS otherwise, to address sectors.
  * It also takes care of issuing special DRIVE_CMDs.
  */
-static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block)
 {
 	BUG_ON(drive->blocked);
 	if (!blk_fs_request(rq)) {
@@ -562,6 +610,13 @@
                 return promise_rw_disk(drive, rq, block);
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 
+	if (drive->using_tcq && idedisk_start_tag(drive, rq)) {
+		if (!ata_pending_commands(drive))
+			BUG();
+
+		return ide_started;
+	}
+
 	if (drive->addressing == 1)		/* 48-bit LBA */
 		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
 	if (drive->select.b.lba)		/* 28-bit LBA */
@@ -579,12 +634,16 @@
 	lba48bit = (drive->addressing == 1) ? 1 : 0;
 #endif
 
+	if ((cmd == READ) && drive->using_tcq)
+		return lba48bit ? WIN_READDMA_QUEUED_EXT : WIN_READDMA_QUEUED;
 	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_tcq)
+		return lba48bit ? WIN_WRITEDMA_QUEUED_EXT : WIN_WRITEDMA_QUEUED;
 	else if ((cmd == WRITE) && (drive->using_dma))
 		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
 	else if ((cmd == WRITE) && (drive->mult_count))
@@ -618,7 +677,13 @@
 	memset(&args, 0, sizeof(ide_task_t));
 
 	sectors	= (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
-	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+
+	if (blk_rq_tagged(rq)) {
+		args.tfRegister[IDE_FEATURE_OFFSET] = sectors;
+		args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3;
+	} else
+		args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
+
 	args.tfRegister[IDE_SECTOR_OFFSET]	= sect;
 	args.tfRegister[IDE_LCYL_OFFSET]	= cyl;
 	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);
@@ -650,7 +715,13 @@
 	memset(&args, 0, sizeof(ide_task_t));
 
 	sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
-	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+
+	if (blk_rq_tagged(rq)) {
+		args.tfRegister[IDE_FEATURE_OFFSET] = sectors;
+		args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3;
+	} else
+		args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
+
 	args.tfRegister[IDE_SECTOR_OFFSET]	= block;
 	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);
 	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);
@@ -688,13 +759,22 @@
 	memset(&args, 0, sizeof(ide_task_t));
 
 	sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
-	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+
+	if (blk_rq_tagged(rq)) {
+		args.tfRegister[IDE_FEATURE_OFFSET] = sectors;
+		args.tfRegister[IDE_NSECTOR_OFFSET] = rq->tag << 3;
+		args.hobRegister[IDE_FEATURE_OFFSET_HOB] = sectors >> 8;
+		args.hobRegister[IDE_NSECT_OFFSET_HOB] = 0;
+	} else {
+		args.tfRegister[IDE_NSECTOR_OFFSET] = sectors;
+		args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = sectors >> 8;
+	}
+
 	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */
 	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
 	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
 	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
-	args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;
 	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */
 	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */
 	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */
@@ -825,8 +905,8 @@
 				}
 			}
 			if (HWGROUP(drive) && HWGROUP(drive)->rq)
-				printk(", sector=%ld",
-					HWGROUP(drive)->rq->sector);
+				printk(", sector=%llu",
+					(unsigned long long)HWGROUP(drive)->rq->sector);
 		}
 	}
 #endif	/* FANCY_STATUS_DUMPS */
@@ -1460,6 +1540,37 @@
 	return 0;
 }
 
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+static int set_using_tcq(ide_drive_t *drive, int arg)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int ret;
+
+	if (!drive->driver)
+		return -EPERM;
+	if (!hwif->ide_dma_queued_on || !hwif->ide_dma_queued_off)
+		return -ENXIO;
+	if (arg == drive->queue_depth && drive->using_tcq)
+		return 0;
+
+	/*
+	 * set depth, but check also id for max supported depth
+	 */
+	drive->queue_depth = arg ? arg : 1;
+	if (drive->id) {
+		if (drive->queue_depth > drive->id->queue_depth + 1)
+			drive->queue_depth = drive->id->queue_depth + 1;
+	}
+
+	if (arg)
+		ret = HWIF(drive)->ide_dma_queued_on(drive);
+	else
+		ret = HWIF(drive)->ide_dma_queued_off(drive);
+
+	return ret ? -EIO : 0;
+}
+#endif
+
 static int probe_lba_addressing (ide_drive_t *drive, int arg)
 {
 	drive->addressing =  0;
@@ -1494,6 +1605,9 @@
 	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);
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+	ide_add_setting(drive,	"using_tcq",		SETTING_RW,					HDIO_GET_QDMA,		HDIO_SET_QDMA,		TYPE_BYTE,	0,	IDE_MAX_TAG,			1,		1,		&drive->using_tcq,		set_using_tcq);
+#endif
 }
 
 static int idedisk_suspend(struct device *dev, u32 state, u32 level)
@@ -1550,14 +1664,6 @@
 /* This is just a hook for the overall driver tree.
  */
 
-static struct device_driver idedisk_devdrv = {
-	.bus = &ide_bus_type,
-	.name = "IDE disk driver",
-
-	.suspend = idedisk_suspend,
-	.resume = idedisk_resume,
-};
-
 static int idedisk_ioctl (ide_drive_t *drive, struct inode *inode,
 	struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -1603,12 +1709,6 @@
 			drive->doorlocking = 1;
 		}
 	}
-	{
-		sprintf(drive->disk->disk_dev.name, "ide-disk");
-		drive->disk->disk_dev.driver = &idedisk_devdrv;
-		drive->disk->disk_dev.driver_data = drive;
-	}
-
 #if 1
 	(void) probe_lba_addressing(drive, 1);
 #else
@@ -1692,7 +1792,6 @@
 {
 	struct gendisk *g = drive->disk;
 
-	put_device(&drive->disk->disk_dev);
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
 		if (do_idedisk_flushcache(drive))
 			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
@@ -1709,35 +1808,35 @@
  *      IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idedisk_driver = {
-	owner:			THIS_MODULE,
-	name:			"ide-disk",
-	version:		IDEDISK_VERSION,
-	media:			ide_disk,
-	busy:			0,
-	supports_dma:		1,
-	supports_dsc_overlap:	0,
-	cleanup:		idedisk_cleanup,
-	standby:		do_idedisk_standby,
-	suspend:		do_idedisk_suspend,
-	resume:			do_idedisk_resume,
-	flushcache:		do_idedisk_flushcache,
-	do_request:		do_rw_disk,
-	end_request:		NULL,
-	sense:			idedisk_dump_status,
-	error:			idedisk_error,
-	ioctl:			idedisk_ioctl,
-	open:			idedisk_open,
-	release:		idedisk_release,
-	media_change:		idedisk_media_change,
-	revalidate:		idedisk_revalidate,
-	pre_reset:		idedisk_pre_reset,
-	capacity:		idedisk_capacity,
-	special:		idedisk_special,
-	proc:			idedisk_proc,
-	attach:			idedisk_attach,
-	ata_prebuilder:		NULL,
-	atapi_prebuilder:	NULL,
-	drives:			LIST_HEAD_INIT(idedisk_driver.drives),
+	.owner			= THIS_MODULE,
+	.name			= "ide-disk",
+	.version		= IDEDISK_VERSION,
+	.media			= ide_disk,
+	.busy			= 0,
+	.supports_dma		= 1,
+	.supports_dsc_overlap	= 0,
+	.cleanup		= idedisk_cleanup,
+	.standby		= do_idedisk_standby,
+	.suspend		= do_idedisk_suspend,
+	.resume			= do_idedisk_resume,
+	.flushcache		= do_idedisk_flushcache,
+	.do_request		= do_rw_disk,
+	.end_request		= NULL,
+	.sense			= idedisk_dump_status,
+	.error			= idedisk_error,
+	.ioctl			= idedisk_ioctl,
+	.open			= idedisk_open,
+	.release		= idedisk_release,
+	.media_change		= idedisk_media_change,
+	.revalidate		= idedisk_revalidate,
+	.pre_reset		= idedisk_pre_reset,
+	.capacity		= idedisk_capacity,
+	.special		= idedisk_special,
+	.proc			= idedisk_proc,
+	.attach			= idedisk_attach,
+	.ata_prebuilder		= NULL,
+	.atapi_prebuilder	= NULL,
+	.drives			= LIST_HEAD_INIT(idedisk_driver.drives),
 };
 
 MODULE_DESCRIPTION("ATA DISK Driver");
@@ -1791,7 +1890,6 @@
 static int idedisk_init (void)
 {
 	ide_register_driver(&idedisk_driver);
-	driver_register(&idedisk_devdrv);
 	return 0;
 }
 
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/ide/ide-dma.c	Fri Oct 11 21:22:58 2002
@@ -461,7 +461,14 @@
 {
 	drive->using_dma = 0;
 	ide_toggle_bounce(drive, 0);
-	return HWIF(drive)->ide_dma_host_off(drive);
+
+	if (HWIF(drive)->ide_dma_host_off(drive))
+		return 1;
+
+	if (drive->queue_setup)
+		HWIF(drive)->ide_dma_queued_off(drive);
+
+	return 0;
 }
 
 EXPORT_SYMBOL(__ide_dma_off_quietly);
@@ -493,7 +500,14 @@
 {
 	drive->using_dma = 1;
 	ide_toggle_bounce(drive, 1);
-	return HWIF(drive)->ide_dma_host_on(drive);
+
+	if (HWIF(drive)->ide_dma_host_on(drive))
+		return 1;
+
+	if (drive->queue_setup)
+		HWIF(drive)->ide_dma_queued_on(drive);
+
+	return 0;
 }
 
 EXPORT_SYMBOL(__ide_dma_on);
@@ -505,50 +519,58 @@
 
 EXPORT_SYMBOL(__ide_dma_check);
 
-int __ide_dma_read (ide_drive_t *drive /*, struct request *rq */)
+int ide_start_dma(ide_hwif_t *hwif, ide_drive_t *drive, int reading)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct request *rq	= HWGROUP(drive)->rq;
-//	ide_task_t *args	= rq->special;
-	unsigned int reading	= 1 << 3;
-	unsigned int count	= 0;
-	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
-	task_ioreg_t command	= WIN_NOP;
+	struct request *rq = HWGROUP(drive)->rq;
+	u8 dma_stat;
 
-	if (!(count = ide_build_dmatable(drive, rq)))
-		/* try PIO instead of DMA */
+	/* fall back to pio! */
+	if (!ide_build_dmatable(drive, rq))
 		return 1;
+
 	/* PRD table */
 	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+
 	/* specify r/w */
 	hwif->OUTB(reading, hwif->dma_command);
+
 	/* read dma_status for INTR & ERROR flags */
 	dma_stat = hwif->INB(hwif->dma_status);
+
 	/* clear INTR & ERROR flags */
 	hwif->OUTB(dma_stat|6, hwif->dma_status);
 	drive->waiting_for_dma = 1;
+	return 0;
+}
+
+EXPORT_SYMBOL(ide_start_dma);
+
+int __ide_dma_read (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+	unsigned int reading	= 1 << 3;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	/* try pio */
+	if (ide_start_dma(hwif, drive, reading))
+		return 1;
+
 	if (drive->media != ide_disk)
 		return 0;
+
 	/* paranoia check */
 	if (HWGROUP(drive)->handler != NULL)
 		BUG();
 	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
 
-	/*
-	 * FIX ME to use only ACB ide_task_t args Struct
-	 */
-#if 0
-	{
-		ide_task_t *args = rq->special;
-		command = args->tfRegister[IDE_COMMAND_OFFSET];
-	}
-#else
 	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
 	if (rq->flags & REQ_DRIVE_TASKFILE) {
 		ide_task_t *args = rq->special;
 		command = args->tfRegister[IDE_COMMAND_OFFSET];
 	}
-#endif
+
 	/* issue cmd to drive */
 	hwif->OUTB(command, IDE_COMMAND_REG);
 
@@ -561,47 +583,31 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
-//	ide_task_t *args	= rq->special;
 	unsigned int reading	= 0;
-	unsigned int count	= 0;
-	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
 	task_ioreg_t command	= WIN_NOP;
 
-	if (!(count = ide_build_dmatable(drive, rq)))
-		/* try PIO instead of DMA */
+	/* try PIO instead of DMA */
+	if (ide_start_dma(hwif, drive, reading))
 		return 1;
-	/* PRD table */
-	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
-	/* specify r/w */
-	hwif->OUTB(reading, hwif->dma_command);
-	/* read dma_status for INTR & ERROR flags */
-	dma_stat = hwif->INB(hwif->dma_status);
-	/* clear INTR & ERROR flags */
-	hwif->OUTB(dma_stat|6, hwif->dma_status);
-	drive->waiting_for_dma = 1;
+
 	if (drive->media != ide_disk)
 		return 0;
+
 	/* paranoia check */
 	if (HWGROUP(drive)->handler != NULL)
 		BUG();
 	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
-	/*
-	 * FIX ME to use only ACB ide_task_t args Struct
-	 */
-#if 0
-	{
-		ide_task_t *args = rq->special;
-		command = args->tfRegister[IDE_COMMAND_OFFSET];
-	}
-#else
+
 	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
 	if (rq->flags & REQ_DRIVE_TASKFILE) {
 		ide_task_t *args = rq->special;
 		command = args->tfRegister[IDE_COMMAND_OFFSET];
 	}
-#endif
+
 	/* issue cmd to drive */
 	hwif->OUTB(command, IDE_COMMAND_REG);
+
 	return HWIF(drive)->ide_dma_count(drive);
 }
 
@@ -619,6 +625,8 @@
 	 */
 	/* start DMA */
 	hwif->OUTB(dma_cmd|1, hwif->dma_command);
+	hwif->dma = 1;
+	wmb();
 	return 0;
 }
 
@@ -642,6 +650,8 @@
 	/* purge DMA mappings */
 	ide_destroy_dmatable(drive);
 	/* verify good DMA status */
+	hwif->dma = 0;
+	wmb();
 	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
 }
 
@@ -998,6 +1008,23 @@
 		hwif->ide_dma_retune = &__ide_dma_retune;
 	if (!hwif->ide_dma_lostirq)
 		hwif->ide_dma_lostirq = &__ide_dma_lostirq;
+
+	/*
+	 * dma queued ops. if tcq isn't set, queued on and off are just
+	 * dummy functions. cuts down on ifdef hell
+	 */
+	if (!hwif->ide_dma_queued_on)
+		hwif->ide_dma_queued_on = __ide_dma_queued_on;
+	if (!hwif->ide_dma_queued_off)
+		hwif->ide_dma_queued_off = __ide_dma_queued_off;
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+	if (!hwif->ide_dma_queued_read)
+		hwif->ide_dma_queued_read = __ide_dma_queued_read;
+	if (!hwif->ide_dma_queued_write)
+		hwif->ide_dma_queued_write = __ide_dma_queued_write;
+	if (!hwif->ide_dma_queued_start)
+		hwif->ide_dma_queued_start = __ide_dma_queued_start;
+#endif
 
 	if (hwif->chipset != ide_trm290) {
 		u8 dma_stat = hwif->INB(hwif->dma_status);
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/ide/ide-floppy.c	Fri Oct 11 21:22:58 2002
@@ -1241,17 +1241,18 @@
 /*
  *	idefloppy_do_request is our request handling function.	
  */
-static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, sector_t block_s)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_pc_t *pc;
+	unsigned long block = (unsigned long)block_s;
 
 #if IDEFLOPPY_DEBUG_LOG
 	printk(KERN_INFO "rq_status: %d, rq_dev: %u, flags: %lx, errors: %d\n",
 			rq->rq_status, (unsigned int) rq->rq_dev,
 			rq->flags, rq->errors);
 	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
-			"current_nr_sectors: %ld\n", rq->sector,
+			"current_nr_sectors: %ld\n", (long)rq->sector,
 			rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
@@ -1268,7 +1269,7 @@
 		return ide_stopped;
 	}
 	if (rq->flags & REQ_CMD) {
-		if ((rq->sector % floppy->bs_factor) ||
+		if (((long)rq->sector % floppy->bs_factor) ||
 		    (rq->nr_sectors % floppy->bs_factor)) {
 			printk("%s: unsupported r/w request size\n",
 				drive->name);
@@ -2042,39 +2043,39 @@
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idefloppy_driver = {
-	owner:			THIS_MODULE,
-	name:			"ide-floppy",
-	version:		IDEFLOPPY_VERSION,
-	media:			ide_floppy,
-	busy:			0,
+	.owner			= THIS_MODULE,
+	.name			= "ide-floppy",
+	.version		= IDEFLOPPY_VERSION,
+	.media			= ide_floppy,
+	.busy			= 0,
 #ifdef CONFIG_IDEDMA_ONLYDISK
-	supports_dma:		0,
+	.supports_dma		= 0,
 #else
-	supports_dma:		1,
+	.supports_dma		= 1,
 #endif
-	supports_dsc_overlap:	0,
-	cleanup:		idefloppy_cleanup,
-	standby:		NULL,
-	suspend:		NULL,
-	resume:			NULL,
-	flushcache:		NULL,
-	do_request:		idefloppy_do_request,
-	end_request:		idefloppy_do_end_request,
-	sense:			NULL,
-	error:			NULL,
-	ioctl:			idefloppy_ioctl,
-	open:			idefloppy_open,
-	release:		idefloppy_release,
-	media_change:		idefloppy_media_change,
-	revalidate:		idefloppy_revalidate,
-	pre_reset:		NULL,
-	capacity:		idefloppy_capacity,
-	special:		NULL,
-	proc:			idefloppy_proc,
-	attach:			idefloppy_attach,
-	ata_prebuilder:		NULL,
-	atapi_prebuilder:	NULL,
-	drives:			LIST_HEAD_INIT(idefloppy_driver.drives),
+	.supports_dsc_overlap	= 0,
+	.cleanup		= idefloppy_cleanup,
+	.standby		= NULL,
+	.suspend		= NULL,
+	.resume			= NULL,
+	.flushcache		= NULL,
+	.do_request		= idefloppy_do_request,
+	.end_request		= idefloppy_do_end_request,
+	.sense			= NULL,
+	.error			= NULL,
+	.ioctl			= idefloppy_ioctl,
+	.open			= idefloppy_open,
+	.release		= idefloppy_release,
+	.media_change		= idefloppy_media_change,
+	.revalidate		= idefloppy_revalidate,
+	.pre_reset		= NULL,
+	.capacity		= idefloppy_capacity,
+	.special		= NULL,
+	.proc			= idefloppy_proc,
+	.attach			= idefloppy_attach,
+	.ata_prebuilder		= NULL,
+	.atapi_prebuilder	= NULL,
+	.drives			= LIST_HEAD_INIT(idefloppy_driver.drives),
 };
 
 static int idefloppy_attach (ide_drive_t *drive)
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/ide/ide-probe.c	Fri Oct 11 21:23:00 2002
@@ -221,6 +221,17 @@
 	drive->media = ide_disk;
 	printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
 	QUIRK_LIST(drive);
+
+	/* Initialize queue depth settings */
+	drive->queue_depth = 1;
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEPTH
+	drive->queue_depth = CONFIG_BLK_DEV_IDE_TCQ_DEPTH;
+#else
+	drive->queue_depth = drive->id->queue_depth + 1;
+#endif
+	if (drive->queue_depth < 1 || drive->queue_depth > IDE_MAX_TAG)
+		drive->queue_depth = IDE_MAX_TAG;
+
 	return;
 
 err_misc:
@@ -776,6 +787,7 @@
 
 	q->queuedata = HWGROUP(drive);
 	blk_init_queue(q, do_ide_request, &ide_lock);
+	drive->queue_setup = 1;
 	blk_queue_segment_boundary(q, 0xffff);
 
 #ifdef CONFIG_BLK_DEV_PDC4030
@@ -792,6 +804,10 @@
 	blk_queue_max_phys_segments(q, PRD_ENTRIES);
 
 	ide_toggle_bounce(drive, 1);
+
+#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
+	HWIF(drive)->ide_dma_queued_on(drive);
+#endif
 }
 
 /*
@@ -917,8 +933,11 @@
 			hwgroup->drive = drive;
 		drive->next = hwgroup->drive->next;
 		hwgroup->drive->next = drive;
+		spin_unlock_irqrestore(&ide_lock, flags);
 		ide_init_queue(drive);
+		spin_lock_irqsave(&ide_lock, flags);
 	}
+
 	if (!hwgroup->hwif) {
 		hwgroup->hwif = HWIF(hwgroup->drive);
 #ifdef DEBUG
@@ -979,15 +998,6 @@
 		sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);
 		disk->minor_shift = PARTN_BITS; 
 		disk->fops = ide_fops;
-
-		snprintf(disk->disk_dev.bus_id,BUS_ID_SIZE,"%u.%u",
-			 hwif->index,unit);
-		snprintf(disk->disk_dev.name,DEVICE_NAME_SIZE,
-			 "%s","IDE Drive");
-		disk->disk_dev.parent = &hwif->gendev;
-		disk->disk_dev.bus = &ide_bus_type;
-		device_register(&disk->disk_dev);
-
 		hwif->drives[unit].disk = disk;
 	}
 
@@ -1001,6 +1011,20 @@
 		if (hwif->drives[unit].present)
 			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
 	}
+	
+	for (unit = 0; unit < units; ++unit) {
+		ide_drive_t * drive = &hwif->drives[unit];
+
+		snprintf(drive->gendev.bus_id,BUS_ID_SIZE,"%u.%u",
+			 hwif->index,unit);
+		snprintf(drive->gendev.name,DEVICE_NAME_SIZE,
+			 "%s","IDE Drive");
+		drive->gendev.parent = &hwif->gendev;
+		drive->gendev.bus = &ide_bus_type;
+		if (drive->present)
+			device_register(&drive->gendev);
+	}
+
 	return;
 
 err_kmalloc_gd:
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/ide/ide-proc.c	Fri Oct 11 21:22:59 2002
@@ -851,10 +851,10 @@
 	return seq_open(file, &ide_drivers_op);
 }
 static struct file_operations ide_drivers_operations = {
-	open:		ide_drivers_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= ide_drivers_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 void proc_ide_create(void)
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/ide-tape.c	Fri Oct 11 21:22:55 2002
@@ -6184,51 +6184,51 @@
  *	IDE subdriver functions, registered with ide.c
  */
 static ide_driver_t idetape_driver = {
-	owner:			THIS_MODULE,
-	name:			"ide-tape",
-	version:		IDETAPE_VERSION,
-	media:			ide_tape,
-	busy:			1,
+	.owner			= THIS_MODULE,
+	.name			= "ide-tape",
+	.version		= IDETAPE_VERSION,
+	.media			= ide_tape,
+	.busy			= 1,
 #ifdef CONFIG_IDEDMA_ONLYDISK
-	supports_dma:		0,
+	.supports_dma		= 0,
 #else
-	supports_dma:		1,
+	.supports_dma		= 1,
 #endif
-	supports_dsc_overlap: 	1,
-	cleanup:		idetape_cleanup,
-	standby:		NULL,
-	suspend:		NULL,
-	resume:			NULL,
-	flushcache:		NULL,
-	do_request:		idetape_do_request,
-	end_request:		idetape_end_request,
-	sense:			NULL,
-	error:			NULL,
-	ioctl:			idetape_blkdev_ioctl,
-	open:			idetape_blkdev_open,
-	release:		idetape_blkdev_release,
-	media_change:		NULL,
-	revalidate:		NULL,
-	pre_reset:		idetape_pre_reset,
-	capacity:		NULL,
-	special:		NULL,
-	proc:			idetape_proc,
-	attach:			idetape_attach,
-	ata_prebuilder:		NULL,
-	atapi_prebuilder:	NULL,
-	drives:			LIST_HEAD_INIT(idetape_driver.drives),
+	.supports_dsc_overlap 	= 1,
+	.cleanup		= idetape_cleanup,
+	.standby		= NULL,
+	.suspend		= NULL,
+	.resume			= NULL,
+	.flushcache		= NULL,
+	.do_request		= idetape_do_request,
+	.end_request		= idetape_end_request,
+	.sense			= NULL,
+	.error			= NULL,
+	.ioctl			= idetape_blkdev_ioctl,
+	.open			= idetape_blkdev_open,
+	.release		= idetape_blkdev_release,
+	.media_change		= NULL,
+	.revalidate		= NULL,
+	.pre_reset		= idetape_pre_reset,
+	.capacity		= NULL,
+	.special		= NULL,
+	.proc			= idetape_proc,
+	.attach			= idetape_attach,
+	.ata_prebuilder		= NULL,
+	.atapi_prebuilder	= NULL,
+	.drives			= LIST_HEAD_INIT(idetape_driver.drives),
 };
 
 /*
  *	Our character device supporting functions, passed to register_chrdev.
  */
 static struct file_operations idetape_fops = {
-	owner:		THIS_MODULE,
-	read:		idetape_chrdev_read,
-	write:		idetape_chrdev_write,
-	ioctl:		idetape_chrdev_ioctl,
-	open:		idetape_chrdev_open,
-	release:	idetape_chrdev_release,
+	.owner		= THIS_MODULE,
+	.read		= idetape_chrdev_read,
+	.write		= idetape_chrdev_write,
+	.ioctl		= idetape_chrdev_ioctl,
+	.open		= idetape_chrdev_open,
+	.release	= idetape_chrdev_release,
 };
 
 static int idetape_attach (ide_drive_t *drive)
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/ide/ide-taskfile.c	Fri Oct 11 21:22:50 2002
@@ -201,6 +201,12 @@
 			if (hwif->ide_dma_read(drive))
 				return ide_stopped;
 			break;
+		case WIN_READDMA_QUEUED:
+		case WIN_READDMA_QUEUED_EXT:
+			return hwif->ide_dma_queued_read(drive);
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_QUEUED_EXT:
+			return hwif->ide_dma_queued_write(drive);
 		default:
 			if (task->handler == NULL)
 				return ide_stopped;
@@ -280,8 +286,8 @@
 				}
 			}
 			if (HWGROUP(drive)->rq)
-				printk(", sector=%lu",
-					HWGROUP(drive)->rq->sector);
+				printk(", sector=%llu",
+					(unsigned long long)HWGROUP(drive)->rq->sector);
 		}
 media_out:
 #endif  /* FANCY_STATUS_DUMPS */
diff -Nru a/drivers/ide/ide-tcq.c b/drivers/ide/ide-tcq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-tcq.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 2001, 2002 Jens Axboe <axboe@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Support for the DMA queued protocol, which enables ATA disk drives to
+ * use tagged command queueing.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+
+/*
+ * warning: it will be _very_ verbose if defined
+ */
+#undef IDE_TCQ_DEBUG
+
+#ifdef IDE_TCQ_DEBUG
+#define TCQ_PRINTK printk
+#else
+#define TCQ_PRINTK(x...)
+#endif
+
+/*
+ * use nIEN or not
+ */
+#undef IDE_TCQ_NIEN
+
+/*
+ * we are leaving the SERVICE interrupt alone, IBM drives have it
+ * on per default and it can't be turned off. Doesn't matter, this
+ * is the sane config.
+ */
+#undef IDE_TCQ_FIDDLE_SI
+
+ide_startstop_t ide_dmaq_intr(ide_drive_t *drive);
+ide_startstop_t ide_service(ide_drive_t *drive);
+
+static inline void drive_ctl_nien(ide_drive_t *drive, int set)
+{
+#ifdef IDE_TCQ_NIEN
+	if (IDE_CONTROL_REG) {
+		int mask = set ? 0x02 : 0x00;
+
+		hwif->OUTB(drive->ctl | mask, IDE_CONTROL_REG);
+	}
+#endif
+}
+
+static ide_startstop_t ide_tcq_nop_handler(ide_drive_t *drive)
+{
+	ide_task_t *args = HWGROUP(drive)->rq->special;
+	ide_hwif_t *hwif = HWIF(drive);
+	int auto_poll_check = 0;
+	u8 stat, err;
+
+	if (args->tfRegister[IDE_FEATURE_OFFSET] & 0x01)
+		auto_poll_check = 1;
+
+	local_irq_enable();
+
+	stat = hwif->INB(IDE_STATUS_REG);
+	err = hwif->INB(IDE_ERROR_REG);
+	ide_end_drive_cmd(drive, stat, err);
+
+	/*
+	 * do taskfile and check ABRT bit -- intelligent adapters will not
+	 * pass NOP with sub-code 0x01 to device, so the command will not
+	 * fail there
+	 */
+	if (auto_poll_check) {
+		if (!(args->tfRegister[IDE_FEATURE_OFFSET] & ABRT_ERR)) {
+			HWIF(drive)->auto_poll = 1;
+			printk("%s: NOP Auto-poll enabled\n",HWIF(drive)->name);
+		}
+	}
+
+	kfree(args);
+	return ide_stopped;
+}
+
+/*
+ * if we encounter _any_ error doing I/O to one of the tags, we must
+ * invalidate the pending queue. clear the software busy queue and requeue
+ * on the request queue for restart. issue a WIN_NOP to clear hardware queue
+ */
+static void ide_tcq_invalidate_queue(ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	request_queue_t *q = &drive->queue;
+	struct request *rq;
+	unsigned long flags;
+
+	printk("%s: invalidating tag queue (%d commands)\n", drive->name, ata_pending_commands(drive));
+
+	/*
+	 * first kill timer and block queue
+	 */
+	spin_lock_irqsave(&ide_lock, flags);
+
+	del_timer(&hwgroup->timer);
+
+	if (HWIF(drive)->dma)
+		HWIF(drive)->ide_dma_end(drive);
+
+	blk_queue_invalidate_tags(q);
+
+	drive->using_tcq = 0;
+	drive->queue_depth = 1;
+	hwgroup->busy = 0;
+	hwgroup->handler = NULL;
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	/*
+	 * now kill hardware queue with a NOP
+	 */
+	rq = &hwgroup->wrq;
+	ide_init_drive_cmd(rq);
+	rq->buffer = hwgroup->cmd_buf;
+	memset(rq->buffer, 0, sizeof(hwgroup->cmd_buf));
+	rq->buffer[0] = WIN_NOP;
+	ide_do_drive_cmd(drive, rq, ide_preempt);
+}
+
+void ide_tcq_intr_timeout(unsigned long data)
+{
+	ide_drive_t *drive = (ide_drive_t *) data;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+
+	printk("ide_tcq_intr_timeout: timeout waiting for %s interrupt\n", hwgroup->rq ? "completion" : "service");
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	if (!hwgroup->busy)
+		printk("ide_tcq_intr_timeout: hwgroup not busy\n");
+	if (hwgroup->handler == NULL)
+		printk("ide_tcq_intr_timeout: missing isr!\n");
+
+	hwgroup->busy = 1;
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	/*
+	 * if pending commands, try service before giving up
+	 */
+	if (ata_pending_commands(drive)) {
+		u8 stat = hwif->INB(IDE_STATUS_REG);
+
+		if ((stat & SRV_STAT) && (ide_service(drive) == ide_started))
+			return;
+	}
+
+	if (drive)
+		ide_tcq_invalidate_queue(drive);
+}
+
+void __ide_tcq_set_intr(ide_hwgroup_t *hwgroup, ide_handler_t *handler)
+{
+	/*
+	 * always just bump the timer for now, the timeout handling will
+	 * have to be changed to be per-command
+	 */
+	hwgroup->timer.function = ide_tcq_intr_timeout;
+	hwgroup->timer.data = (unsigned long) hwgroup->drive;
+	mod_timer(&hwgroup->timer, jiffies + 5 * HZ);
+
+	hwgroup->handler = handler;
+}
+
+void ide_tcq_set_intr(ide_hwgroup_t *hwgroup, ide_handler_t *handler)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	__ide_tcq_set_intr(hwgroup, handler);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * wait 400ns, then poll for busy_mask to clear from alt status
+ */
+#define IDE_TCQ_WAIT	(10000)
+int ide_tcq_wait_altstat(ide_drive_t *drive, byte *stat, byte busy_mask)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int i = 0;
+
+	udelay(1);
+
+	do {
+		*stat = hwif->INB(IDE_ALTSTATUS_REG);
+
+		if (!(*stat & busy_mask))
+			break;
+
+		if (unlikely(i++ > IDE_TCQ_WAIT))
+			return 1;
+
+		udelay(10);
+	} while (1);
+
+	return 0;
+}
+
+/*
+ * issue SERVICE command to drive -- drive must have been selected first,
+ * and it must have reported a need for service (status has SRV_STAT set)
+ *
+ * Also, nIEN must be set as not to need protection against ide_dmaq_intr
+ */
+ide_startstop_t ide_service(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	struct request *rq;
+	byte feat, stat;
+	int tag;
+
+	TCQ_PRINTK("%s: started service\n", drive->name);
+
+	/*
+	 * could be called with IDE_DMA in-progress from invalidate
+	 * handler, refuse to do anything
+	 */
+	if (hwif->dma)
+		return ide_stopped;
+
+	/*
+	 * need to select the right drive first...
+	 */
+	if (drive != HWGROUP(drive)->drive) {
+		SELECT_DRIVE(drive);
+		udelay(10);
+	}
+
+	drive_ctl_nien(drive, 1);
+
+	/*
+	 * send SERVICE, wait 400ns, wait for BUSY_STAT to clear
+	 */
+	hwif->OUTB(WIN_QUEUED_SERVICE, IDE_COMMAND_REG);
+
+	if (ide_tcq_wait_altstat(drive, &stat, BUSY_STAT)) {
+		printk("ide_service: BUSY clear took too long\n");
+		ide_dump_status(drive, "ide_service", stat);
+		ide_tcq_invalidate_queue(drive);
+		return ide_stopped;
+	}
+
+	drive_ctl_nien(drive, 0);
+
+	/*
+	 * FIXME, invalidate queue
+	 */
+	if (stat & ERR_STAT) {
+		ide_dump_status(drive, "ide_service", stat);
+		ide_tcq_invalidate_queue(drive);
+		return ide_stopped;
+	}
+
+	/*
+	 * should not happen, a buggy device could introduce loop
+	 */
+	feat = hwif->INB(IDE_NSECTOR_REG);
+	if (feat & REL) {
+		HWGROUP(drive)->rq = NULL;
+		printk("%s: release in service\n", drive->name);
+		return ide_stopped;
+	}
+
+	tag = feat >> 3;
+
+	TCQ_PRINTK("ide_service: stat %x, feat %x\n", stat, feat);
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	if ((rq = blk_queue_find_tag(&drive->queue, tag))) {
+		HWGROUP(drive)->rq = rq;
+
+		/*
+		 * we'll start a dma read or write, device will trigger
+		 * interrupt to indicate end of transfer, release is not
+		 * allowed
+		 */
+		TCQ_PRINTK("ide_service: starting command, stat=%x\n", stat);
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return HWIF(drive)->ide_dma_queued_start(drive);
+	}
+
+	printk("ide_service: missing request for tag %d\n", tag);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ide_stopped;
+}
+
+ide_startstop_t ide_check_service(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	byte stat;
+
+	TCQ_PRINTK("%s: ide_check_service\n", drive->name);
+
+	if (!ata_pending_commands(drive))
+		return ide_stopped;
+
+	stat = hwif->INB(IDE_STATUS_REG);
+	if (stat & SRV_STAT)
+		return ide_service(drive);
+
+	/*
+	 * we have pending commands, wait for interrupt
+	 */
+	TCQ_PRINTK("%s: wait for service interrupt\n", drive->name);
+	ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+	return ide_started;
+}
+
+ide_startstop_t ide_dmaq_complete(ide_drive_t *drive, struct request *rq, byte stat)
+{
+	byte dma_stat;
+
+	/*
+	 * transfer was in progress, stop DMA engine
+	 */
+	dma_stat = HWIF(drive)->ide_dma_end(drive);
+
+	/*
+	 * must be end of I/O, check status and complete as necessary
+	 */
+	if (unlikely(!OK_STAT(stat, READY_STAT, drive->bad_wstat | DRQ_STAT))) {
+		printk("ide_dmaq_intr: %s: error status %x\n",drive->name,stat);
+		ide_dump_status(drive, "ide_dmaq_complete", stat);
+		ide_tcq_invalidate_queue(drive);
+		return ide_stopped;
+	}
+
+	if (dma_stat)
+		printk("%s: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat);
+
+	TCQ_PRINTK("ide_dmaq_complete: ending %p, tag %d\n", rq, rq->tag);
+	ide_end_request(drive, 1, rq->nr_sectors);
+
+	/*
+	 * we completed this command, check if we can service a new command
+	 */
+	return ide_check_service(drive);
+}
+
+/*
+ * intr handler for queued dma operations. this can be entered for two
+ * reasons:
+ *
+ * 1) device has completed dma transfer
+ * 2) service request to start a command
+ *
+ * if the drive has an active tag, we first complete that request before
+ * processing any pending SERVICE.
+ */
+ide_startstop_t ide_dmaq_intr(ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	byte stat = hwif->INB(IDE_STATUS_REG);
+
+	TCQ_PRINTK("ide_dmaq_intr: stat=%x\n", stat);
+
+	/*
+	 * if a command completion interrupt is pending, do that first and
+	 * check service afterwards
+	 */
+	if (rq) {
+		TCQ_PRINTK("ide_dmaq_intr: completion\n");
+		return ide_dmaq_complete(drive, rq, stat);
+	}
+
+	/*
+	 * service interrupt
+	 */
+	if (stat & SRV_STAT) {
+		TCQ_PRINTK("ide_dmaq_intr: SERV (stat=%x)\n", stat);
+		return ide_service(drive);
+	}
+
+	printk("ide_dmaq_intr: stat=%x, not expected\n", stat);
+	return ide_check_service(drive);
+}
+
+/*
+ * check if the ata adapter this drive is attached to supports the
+ * NOP auto-poll for multiple tcq enabled drives on one channel
+ */
+static int ide_tcq_check_autopoll(ide_drive_t *drive)
+{
+	ide_task_t *args;
+	int i, drives;
+
+	/*
+	 * only need to probe if both drives on a channel support tcq
+	 */
+	for (i = 0, drives = 0; i < MAX_DRIVES; i++)
+		if (HWIF(drive)->drives[i].present && drive->media == ide_disk)
+			drives++;
+
+	if (drives <= 1)
+		return 0;
+
+	/*
+	 * what a mess...
+	 */
+	args = kmalloc(sizeof(*args), GFP_ATOMIC);
+	if (!args)
+		return 1;
+
+	memset(args, 0, sizeof(*args));
+
+	args->tfRegister[IDE_FEATURE_OFFSET] = 0x01;
+	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_NOP;
+	args->command_type = ide_cmd_type_parser(args);
+	args->handler = ide_tcq_nop_handler;
+	return ide_raw_taskfile(drive, args, NULL);
+}
+
+/*
+ * configure the drive for tcq
+ */
+static int ide_tcq_configure(ide_drive_t *drive)
+{
+	int tcq_mask = 1 << 1 | 1 << 14;
+	int tcq_bits = tcq_mask | 1 << 15;
+	ide_task_t *args;
+
+	/*
+	 * bit 14 and 1 must be set in word 83 of the device id to indicate
+	 * support for dma queued protocol, and bit 15 must be cleared
+	 */
+	if ((drive->id->command_set_2 & tcq_bits) ^ tcq_mask)
+		return -EIO;
+
+	args = kmalloc(sizeof(*args), GFP_ATOMIC);
+	if (!args)
+		return -ENOMEM;
+
+	memset(args, 0, sizeof(ide_task_t));
+	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
+	args->tfRegister[IDE_FEATURE_OFFSET] = SETFEATURES_EN_WCACHE;
+	args->command_type = ide_cmd_type_parser(args);
+
+	if (ide_raw_taskfile(drive, args, NULL)) {
+		printk("%s: failed to enable write cache\n", drive->name);
+		goto err;
+	}
+
+	/*
+	 * disable RELease interrupt, it's quicker to poll this after
+	 * having sent the command opcode
+	 */
+	memset(args, 0, sizeof(ide_task_t));
+	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
+	args->tfRegister[IDE_FEATURE_OFFSET] = SETFEATURES_DIS_RI;
+	args->command_type = ide_cmd_type_parser(args);
+
+	if (ide_raw_taskfile(drive, args, NULL)) {
+		printk("%s: disabling release interrupt fail\n", drive->name);
+		goto err;
+	}
+
+#ifdef IDE_TCQ_FIDDLE_SI
+	/*
+	 * enable SERVICE interrupt
+	 */
+	memset(args, 0, sizeof(ide_task_t));
+	args->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
+	args->tfRegister[IDE_FEATURE_OFFSET] = SETFEATURES_EN_SI;
+	args->command_type = ide_cmd_type_parser(args);
+
+	if (ide_raw_taskfile(drive, args, NULL)) {
+		printk("%s: enabling service interrupt fail\n", drive->name);
+		goto err;
+	}
+#endif
+
+	kfree(args);
+	return 0;
+err:
+	kfree(args);
+	return 1;
+}
+
+/*
+ * for now assume that command list is always as big as we need and don't
+ * attempt to shrink it on tcq disable
+ */
+static int ide_enable_queued(ide_drive_t *drive, int on)
+{
+	int depth = drive->using_tcq ? drive->queue_depth : 0;
+
+	/*
+	 * disable or adjust queue depth
+	 */
+	if (!on) {
+		if (drive->using_tcq)
+			printk("%s: TCQ disabled\n", drive->name);
+
+		drive->using_tcq = 0;
+		return 0;
+	}
+
+	if (ide_tcq_configure(drive)) {
+		drive->using_tcq = 0;
+		return 1;
+	}
+
+	/*
+	 * enable block tagging
+	 */
+	if (!blk_queue_tagged(&drive->queue))
+		blk_queue_init_tags(&drive->queue, IDE_MAX_TAG);
+
+	/*
+	 * check auto-poll support
+	 */
+	ide_tcq_check_autopoll(drive);
+
+	if (depth != drive->queue_depth)
+		printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth);
+
+	drive->using_tcq = 1;
+	return 0;
+}
+
+int ide_tcq_wait_dataphase(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	byte stat;
+	int i;
+
+	do {
+		stat = hwif->INB(IDE_STATUS_REG);
+		if (!(stat & BUSY_STAT))
+			break;
+
+		udelay(10);
+	} while (1);
+
+	if (OK_STAT(stat, READY_STAT | DRQ_STAT, drive->bad_wstat))
+		return 0;
+
+	i = 0;
+	udelay(1);
+	do {
+		stat = hwif->INB(IDE_STATUS_REG);
+
+		if (OK_STAT(stat, READY_STAT | DRQ_STAT, drive->bad_wstat))
+			break;
+
+		++i;
+		if (unlikely(i >= IDE_TCQ_WAIT))
+			return 1;
+
+		udelay(10);
+	} while (1);
+
+	return 0;
+}
+
+int __ide_dma_queued_on(ide_drive_t *drive)
+{
+	if (!drive->using_dma)
+		return 1;
+
+	if (ata_pending_commands(drive)) {
+		printk("ide-tcq; can't toggle tcq feature on busy drive\n");
+		return 1;
+	}
+
+	return ide_enable_queued(drive, 1);
+}
+
+int __ide_dma_queued_off(ide_drive_t *drive)
+{
+	if (ata_pending_commands(drive)) {
+		printk("ide-tcq; can't toggle tcq feature on busy drive\n");
+		return 1;
+	}
+
+	return ide_enable_queued(drive, 0);
+}
+
+static ide_startstop_t ide_dma_queued_rw(ide_drive_t *drive, u8 command)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	byte stat, feat;
+
+	TCQ_PRINTK("%s: starting tag\n", drive->name);
+
+	/*
+	 * set nIEN, tag start operation will enable again when
+	 * it is safe
+	 */
+	drive_ctl_nien(drive, 1);
+
+	TCQ_PRINTK("%s: sending cmd=%x\n", drive->name, command);
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	if (ide_tcq_wait_altstat(drive, &stat, BUSY_STAT)) {
+		printk("%s: alt stat timeout\n", drive->name);
+		goto err;
+	}
+
+	drive_ctl_nien(drive, 0);
+
+	if (stat & ERR_STAT)
+		goto err;
+
+	/*
+	 * bus not released, start dma
+	 */
+	feat = hwif->INB(IDE_NSECTOR_REG);
+	if (!(feat & REL)) {
+		TCQ_PRINTK("IMMED in queued_start, feat=%x\n", feat);
+		return hwif->ide_dma_queued_start(drive);
+	}
+
+	/*
+	 * drive released the bus, clear active request and check for service
+	 */
+	spin_lock_irqsave(&ide_lock, flags);
+	HWGROUP(drive)->rq = NULL;
+	__ide_tcq_set_intr(HWGROUP(drive), ide_dmaq_intr);
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	TCQ_PRINTK("REL in queued_start\n");
+
+	stat = hwif->INB(IDE_STATUS_REG);
+	if (stat & SRV_STAT)
+		return ide_service(drive);
+
+	return ide_released;
+err:
+	ide_dump_status(drive, "rw_queued", stat);
+	ide_tcq_invalidate_queue(drive);
+	return ide_stopped;
+}
+
+ide_startstop_t __ide_dma_queued_read(ide_drive_t *drive)
+{
+	u8 command = WIN_READDMA_QUEUED;
+
+	if (drive->addressing == 1)
+		 command = WIN_READDMA_QUEUED_EXT;
+
+	return ide_dma_queued_rw(drive, command);
+}
+
+ide_startstop_t __ide_dma_queued_write(ide_drive_t *drive)
+{
+	u8 command = WIN_WRITEDMA_QUEUED;
+
+	if (drive->addressing == 1)
+		 command = WIN_WRITEDMA_QUEUED_EXT;
+
+	return ide_dma_queued_rw(drive, command);
+}
+
+ide_startstop_t __ide_dma_queued_start(ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int reading = 0;
+
+	TCQ_PRINTK("ide_dma: setting up queued tag=%d\n", rq->tag);
+
+	if (!hwgroup->busy)
+		printk("queued_rw: hwgroup not busy\n");
+
+	if (ide_tcq_wait_dataphase(drive)) {
+		printk("timeout waiting for data phase\n");
+		return ide_stopped;
+	}
+
+	if (rq_data_dir(rq) == READ)
+		reading = 1 << 3;
+
+	if (ide_start_dma(hwif, drive, reading))
+		return ide_stopped;
+
+	ide_tcq_set_intr(hwgroup, ide_dmaq_intr);
+
+	if (!hwif->ide_dma_begin(drive))
+		return ide_started;
+
+	return ide_stopped;
+}
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/ide.c	Fri Oct 11 21:22:55 2002
@@ -407,7 +407,10 @@
 
 	if (!end_that_request_first(rq, uptodate, nr_sectors)) {
 		add_blkdev_randomness(major(rq->rq_dev));
-		blkdev_dequeue_request(rq);
+		if (!blk_rq_tagged(rq))
+			blkdev_dequeue_request(rq);
+		else
+			blk_queue_end_tag(&drive->queue, rq);
 		HWGROUP(drive)->rq = NULL;
 		end_that_request_last(rq);
 		ret = 0;
@@ -587,7 +590,7 @@
 					}
 				}
 				if (HWGROUP(drive) && HWGROUP(drive)->rq)
-					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
+					printk(", sector=%llu", (unsigned long long)HWGROUP(drive)->rq->sector);
 			}
 		}
 #endif	/* FANCY_STATUS_DUMPS */
@@ -1117,9 +1120,30 @@
 		drive->sleep = 0;
 		drive->service_start = jiffies;
 
-		BUG_ON(blk_queue_plugged(&drive->queue));
+queue_next:
+		if (!ata_can_queue(drive)) {
+			if (!ata_pending_commands(drive))
+				hwgroup->busy = 0;
+
+			break;
+		}
+
+		if (blk_queue_plugged(&drive->queue)) {
+			if (drive->using_tcq)
+				break;
+
+			printk("ide: huh? queue was plugged!\n");
+			break;
+		}
+
+		rq = elv_next_request(&drive->queue);
+		if (!rq)
+			break;
 
-		rq = hwgroup->rq = elv_next_request(&drive->queue);
+		if (!rq->bio && ata_pending_commands(drive))
+			break;
+
+		hwgroup->rq = rq;
 
 		/*
 		 * Some systems have trouble with IDE IRQs arriving while
@@ -1138,6 +1162,8 @@
 		spin_lock_irq(&ide_lock);
 		if (masked_irq && hwif->irq != masked_irq)
 			enable_irq(hwif->irq);
+		if (startstop == ide_released)
+			goto queue_next;
 		if (startstop == ide_stopped)
 			hwgroup->busy = 0;
 	}
@@ -1689,10 +1715,10 @@
 	return 0;
 }
 struct seq_operations ide_drivers_op = {
-	start:	m_start,
-	next:	m_next,
-	stop:	m_stop,
-	show:	show_driver
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= show_driver
 };
 
 #ifdef CONFIG_PROC_FS
@@ -2437,6 +2463,7 @@
 		if (driver->attach(drive) == 0) {
 			if (driver->owner)
 				__MOD_DEC_USE_COUNT(driver->owner);
+			drive->gendev.driver = &driver->gen_driver;
 			return 0;
 		}
 		spin_lock(&drivers_lock);
@@ -3244,7 +3271,7 @@
 	return 0;
 }
 
-static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
 {
 	ide_end_request(drive, 0, 0);
 	return ide_stopped;
@@ -3396,6 +3423,21 @@
 
 EXPORT_SYMBOL(ide_unregister_subdriver);
 
+static int ide_drive_remove(struct device * dev)
+{
+	ide_drive_t * drive = container_of(dev,ide_drive_t,gendev);
+	ide_driver_t * driver = drive->driver;
+
+	if (driver) {
+		if (driver->standby)
+			driver->standby(drive);
+		if (driver->cleanup)
+			driver->cleanup(drive);
+	}
+	
+	return 0;
+}
+
 int ide_register_driver(ide_driver_t *driver)
 {
 	struct list_head list;
@@ -3414,7 +3456,10 @@
 		list_del_init(&drive->list);
 		ata_attach(drive);
 	}
-	return 0;
+	driver->gen_driver.name = driver->name;
+	driver->gen_driver.bus = &ide_bus_type;
+	driver->gen_driver.remove = ide_drive_remove;
+	return driver_register(&driver->gen_driver);
 }
 
 EXPORT_SYMBOL(ide_register_driver);
@@ -3446,12 +3491,12 @@
 EXPORT_SYMBOL(ide_unregister_driver);
 
 struct block_device_operations ide_fops[] = {{
-	owner:			THIS_MODULE,
-	open:			ide_open,
-	release:		ide_release,
-	ioctl:			ide_ioctl,
-	check_media_change:	ide_check_media_change,
-	revalidate:		ide_revalidate_disk
+	.owner			= THIS_MODULE,
+	.open			= ide_open,
+	.release		= ide_release,
+	.ioctl			= ide_ioctl,
+	.check_media_change	= ide_check_media_change,
+	.revalidate		= ide_revalidate_disk
 }};
 
 EXPORT_SYMBOL(ide_fops);
@@ -3465,52 +3510,6 @@
 EXPORT_SYMBOL(ide_probe);
 EXPORT_SYMBOL(ide_devfs_handle);
 
-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(KERN_INFO "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
-};
-
 struct bus_type ide_bus_type = {
 	.name		= "ide",
 };
@@ -3536,7 +3535,6 @@
 	ide_init_builtin_drivers();
 	initializing = 0;
 
-	register_reboot_notifier(&ide_notifier);
 	return 0;
 }
 
@@ -3571,7 +3569,6 @@
 {
 	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 -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
--- a/drivers/ide/legacy/hd.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/ide/legacy/hd.c	Fri Oct 11 21:22:50 2002
@@ -50,8 +50,6 @@
 #define DEVICE_NR(device) (minor(device)>>6)
 #include <linux/blk.h>
 
-#define HD_IRQ 14	/* the standard disk interrupt */
-
 #ifdef __arm__
 #undef  HD_IRQ
 #endif
diff -Nru a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c
--- a/drivers/ide/legacy/pdc4030.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/ide/legacy/pdc4030.c	Fri Oct 11 21:22:58 2002
@@ -442,8 +442,8 @@
 
 #ifdef DEBUG_READ
 	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
-	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
-	       rq->sector+nsect-1,
+	       "buf=0x%08lx, rem=%ld\n", drive->name, (long)rq->sector,
+	       (long)rq->sector+nsect-1,
 #ifdef CONFIG_IDE_TASKFILE_IO
 		(unsigned long) to,
 #else /* !CONFIG_IDE_TASKFILE_IO */
@@ -670,8 +670,8 @@
 
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
-	       "buffer=%p\n", drive->name, rq->sector,
-	       rq->sector + rq->nr_sectors - 1, rq->buffer);
+	       "buffer=%p\n", drive->name, (long)rq->sector,
+	       (long)rq->sector + rq->nr_sectors - 1, rq->buffer);
 #endif /* DEBUG_WRITE */
 
 	/*
diff -Nru a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
--- a/drivers/ide/pci/aec62xx.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/ide/pci/aec62xx.c	Fri Oct 11 21:23:03 2002
@@ -544,9 +544,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"AEC62xx IDE",
-	id_table:	aec62xx_pci_tbl,
-	probe:		aec62xx_init_one,
+	.name		= "AEC62xx IDE",
+	.id_table	= aec62xx_pci_tbl,
+	.probe		= aec62xx_init_one,
 };
 
 static int aec62xx_ide_init(void)
diff -Nru a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
--- a/drivers/ide/pci/alim15x3.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/pci/alim15x3.c	Fri Oct 11 21:22:55 2002
@@ -869,9 +869,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"ALI15x3 IDE",
-	id_table:	alim15x3_pci_tbl,
-	probe:		alim15x3_init_one,
+	.name		= "ALI15x3 IDE",
+	.id_table	= alim15x3_pci_tbl,
+	.probe		= alim15x3_init_one,
 };
 
 static int ali15x3_ide_init(void)
diff -Nru a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
--- a/drivers/ide/pci/amd74xx.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/ide/pci/amd74xx.c	Fri Oct 11 21:23:05 2002
@@ -414,9 +414,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"AMD IDE",
-	id_table:	amd74xx_pci_tbl,
-	probe:		amd74xx_init_one,
+	.name		= "AMD IDE",
+	.id_table	= amd74xx_pci_tbl,
+	.probe		= amd74xx_init_one,
 };
 
 static int amd74xx_ide_init(void)
diff -Nru a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
--- a/drivers/ide/pci/cmd64x.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/ide/pci/cmd64x.c	Fri Oct 11 21:23:03 2002
@@ -784,9 +784,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"CMD64x IDE",
-	id_table:	cmd64x_pci_tbl,
-	probe:		cmd64x_init_one,
+	.name		= "CMD64x IDE",
+	.id_table	= cmd64x_pci_tbl,
+	.probe		= cmd64x_init_one,
 };
 
 static int cmd64x_ide_init(void)
diff -Nru a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
--- a/drivers/ide/pci/cs5530.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/pci/cs5530.c	Fri Oct 11 21:22:55 2002
@@ -437,9 +437,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"CS5530 IDE",
-	id_table:	cs5530_pci_tbl,
-	probe:		cs5530_init_one,
+	.name		= "CS5530 IDE",
+	.id_table	= cs5530_pci_tbl,
+	.probe		= cs5530_init_one,
 };
 
 static int cs5530_ide_init(void)
diff -Nru a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
--- a/drivers/ide/pci/cy82c693.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/ide/pci/cy82c693.c	Fri Oct 11 21:22:54 2002
@@ -448,9 +448,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"Cypress IDE",
-	id_table:	cy82c693_pci_tbl,
-	probe:		cy82c693_init_one,
+	.name		= "Cypress IDE",
+	.id_table	= cy82c693_pci_tbl,
+	.probe		= cy82c693_init_one,
 };
 
 static int cy82c693_ide_init(void)
diff -Nru a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
--- a/drivers/ide/pci/generic.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/ide/pci/generic.c	Fri Oct 11 21:22:50 2002
@@ -123,9 +123,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"PCI IDE",
-	id_table:	generic_pci_tbl,
-	probe:		generic_init_one,
+	.name		= "PCI IDE",
+	.id_table	= generic_pci_tbl,
+	.probe		= generic_init_one,
 };
 
 static int generic_ide_init(void)
diff -Nru a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
--- a/drivers/ide/pci/hpt34x.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/pci/hpt34x.c	Fri Oct 11 21:22:55 2002
@@ -344,9 +344,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"HPT34x IDE",
-	id_table:	hpt34x_pci_tbl,
-	probe:		hpt34x_init_one,
+	.name		= "HPT34x IDE",
+	.id_table	= hpt34x_pci_tbl,
+	.probe		= hpt34x_init_one,
 };
 
 static int hpt34x_ide_init(void)
diff -Nru a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
--- a/drivers/ide/pci/hpt366.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/ide/pci/hpt366.c	Fri Oct 11 21:22:59 2002
@@ -1199,9 +1199,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"HPT366 IDE",
-	id_table:	hpt366_pci_tbl,
-	probe:		hpt366_init_one,
+	.name		= "HPT366 IDE",
+	.id_table	= hpt366_pci_tbl,
+	.probe		= hpt366_init_one,
 };
 
 static int hpt366_ide_init(void)
diff -Nru a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
--- a/drivers/ide/pci/it8172.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/ide/pci/it8172.c	Fri Oct 11 21:22:54 2002
@@ -315,9 +315,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"IT8172IDE",
-	id_table:	it8172_pci_tbl,
-	probe:		it8172_init_one,
+	.name		= "IT8172IDE",
+	.id_table	= it8172_pci_tbl,
+	.probe		= it8172_init_one,
 };
 
 static int it8172_ide_init(void)
diff -Nru a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
--- a/drivers/ide/pci/ns87415.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/ide/pci/ns87415.c	Fri Oct 11 21:22:57 2002
@@ -246,9 +246,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"NS87415IDE",
-	id_table:	ns87415_pci_tbl,
-	probe:		ns87415_init_one,
+	.name		= "NS87415IDE",
+	.id_table	= ns87415_pci_tbl,
+	.probe		= ns87415_init_one,
 };
 
 static int ns87415_ide_init(void)
diff -Nru a/drivers/ide/pci/nvidia.c b/drivers/ide/pci/nvidia.c
--- a/drivers/ide/pci/nvidia.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/ide/pci/nvidia.c	Fri Oct 11 21:23:04 2002
@@ -353,9 +353,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"nForce IDE",
-	id_table:	nforce_pci_tbl,
-	probe:		nforce_init_one,
+	.name		= "nForce IDE",
+	.id_table	= nforce_pci_tbl,
+	.probe		= nforce_init_one,
 };
 
 static int nforce_ide_init(void)
diff -Nru a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
--- a/drivers/ide/pci/opti621.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/pci/opti621.c	Fri Oct 11 21:22:55 2002
@@ -381,9 +381,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"Opti621 IDE",
-	id_table:	opti621_pci_tbl,
-	probe:		opti621_init_one,
+	.name		= "Opti621 IDE",
+	.id_table	= opti621_pci_tbl,
+	.probe		= opti621_init_one,
 };
 
 static int opti621_ide_init(void)
diff -Nru a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
--- a/drivers/ide/pci/pdc202xx_new.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/ide/pci/pdc202xx_new.c	Fri Oct 11 21:23:02 2002
@@ -679,9 +679,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"Promise IDE",
-	id_table:	pdc202new_pci_tbl,
-	probe:		pdc202new_init_one,
+	.name		= "Promise IDE",
+	.id_table	= pdc202new_pci_tbl,
+	.probe		= pdc202new_init_one,
 };
 
 static int pdc202new_ide_init(void)
diff -Nru a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
--- a/drivers/ide/pci/pdc202xx_old.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/ide/pci/pdc202xx_old.c	Fri Oct 11 21:23:04 2002
@@ -956,9 +956,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"Promise Old IDE",
-	id_table:	pdc202xx_pci_tbl,
-	probe:		pdc202xx_init_one,
+	.name		= "Promise Old IDE",
+	.id_table	= pdc202xx_pci_tbl,
+	.probe		= pdc202xx_init_one,
 };
 
 static int pdc202xx_ide_init(void)
diff -Nru a/drivers/ide/pci/pdcadma.c b/drivers/ide/pci/pdcadma.c
--- a/drivers/ide/pci/pdcadma.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/ide/pci/pdcadma.c	Fri Oct 11 21:23:02 2002
@@ -143,9 +143,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"PDCADMA-IDE",
-	id_table:	pdcadma_pci_tbl,
-	probe:		pdcadma_init_one,
+	.name		= "PDCADMA-IDE",
+	.id_table	= pdcadma_pci_tbl,
+	.probe		= pdcadma_init_one,
 };
 
 static int pdcadma_ide_init(void)
diff -Nru a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
--- a/drivers/ide/pci/piix.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/ide/pci/piix.c	Fri Oct 11 21:22:52 2002
@@ -705,9 +705,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"PIIX IDE",
-	id_table:	piix_pci_tbl,
-	probe:		piix_init_one,
+	.name		= "PIIX IDE",
+	.id_table	= piix_pci_tbl,
+	.probe		= piix_init_one,
 };
 
 static int piix_ide_init(void)
diff -Nru a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
--- a/drivers/ide/pci/rz1000.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/pci/rz1000.c	Fri Oct 11 21:22:55 2002
@@ -73,9 +73,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"RZ1000 IDE",
-	id_table:	rz1000_pci_tbl,
-	probe:		rz1000_init_one,
+	.name		= "RZ1000 IDE",
+	.id_table	= rz1000_pci_tbl,
+	.probe		= rz1000_init_one,
 };
 
 static int rz1000_ide_init(void)
diff -Nru a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
--- a/drivers/ide/pci/serverworks.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/ide/pci/serverworks.c	Fri Oct 11 21:22:52 2002
@@ -797,9 +797,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"Serverworks IDE",
-	id_table:	svwks_pci_tbl,
-	probe:		svwks_init_one,
+	.name		= "Serverworks IDE",
+	.id_table	= svwks_pci_tbl,
+	.probe		= svwks_init_one,
 #if 0	/* FIXME: implement */
 	suspend:	,
 	resume:		,
diff -Nru a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
--- a/drivers/ide/pci/siimage.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/pci/siimage.c	Fri Oct 11 21:22:55 2002
@@ -855,9 +855,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"SiI IDE",
-	id_table:	siimage_pci_tbl,
-	probe:		siimage_init_one,
+	.name		= "SiI IDE",
+	.id_table	= siimage_pci_tbl,
+	.probe		= siimage_init_one,
 };
 
 static int siimage_ide_init(void)
diff -Nru a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
--- a/drivers/ide/pci/sis5513.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/ide/pci/sis5513.c	Fri Oct 11 21:22:58 2002
@@ -1040,9 +1040,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"SIS IDE",
-	id_table:	sis5513_pci_tbl,
-	probe:		sis5513_init_one,
+	.name		= "SIS IDE",
+	.id_table	= sis5513_pci_tbl,
+	.probe		= sis5513_init_one,
 };
 
 static int sis5513_ide_init(void)
diff -Nru a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
--- a/drivers/ide/pci/sl82c105.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/ide/pci/sl82c105.c	Fri Oct 11 21:22:55 2002
@@ -298,9 +298,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"W82C105 IDE",
-	id_table:	sl82c105_pci_tbl,
-	probe:		sl82c105_init_one,
+	.name		= "W82C105 IDE",
+	.id_table	= sl82c105_pci_tbl,
+	.probe		= sl82c105_init_one,
 };
 
 static int sl82c105_ide_init(void)
diff -Nru a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
--- a/drivers/ide/pci/slc90e66.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/ide/pci/slc90e66.c	Fri Oct 11 21:23:02 2002
@@ -382,9 +382,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"SLC90e66 IDE",
-	id_table:	slc90e66_pci_tbl,
-	probe:		slc90e66_init_one,
+	.name		= "SLC90e66 IDE",
+	.id_table	= slc90e66_pci_tbl,
+	.probe		= slc90e66_init_one,
 };
 
 static int slc90e66_ide_init(void)
diff -Nru a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
--- a/drivers/ide/pci/trm290.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/ide/pci/trm290.c	Fri Oct 11 21:22:54 2002
@@ -413,9 +413,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"TRM290 IDE",
-	id_table:	trm290_pci_tbl,
-	probe:		trm290_init_one,
+	.name		= "TRM290 IDE",
+	.id_table	= trm290_pci_tbl,
+	.probe		= trm290_init_one,
 };
 
 static int trm290_ide_init(void)
diff -Nru a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
--- a/drivers/ide/pci/via82cxxx.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/ide/pci/via82cxxx.c	Fri Oct 11 21:22:50 2002
@@ -652,9 +652,9 @@
 };
 
 static struct pci_driver driver = {
-	name:		"VIA IDE",
-	id_table:	via_pci_tbl,
-	probe:		via_init_one,
+	.name 		= "VIA IDE",
+	.id_table 	= via_pci_tbl,
+	.probe 		= via_init_one,
 };
 
 static int via_ide_init(void)
diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/ieee1394/sbp2.c	Fri Oct 11 21:22:54 2002
@@ -3160,12 +3160,13 @@
 
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (int)disk->capacity / (heads * sectors);
+	
 
 	if (cylinders > 1024) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (int)disk->capacity / (heads * sectors);
 	}
 
 	geom[0] = heads;
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/input/evdev.c	Fri Oct 11 21:23:02 2002
@@ -1,29 +1,11 @@
 /*
- * $Id: evdev.c,v 1.48 2002/05/26 14:28:26 jdeneux Exp $
+ * Event char devices, giving access to raw input device events.
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
+ * Copyright (c) 1999-2002 Vojtech Pavlik
  *
- *  Event char devices, giving access to raw input device events.
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #define EVDEV_MINOR_BASE	64
@@ -38,7 +20,7 @@
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 
-struct evdev {
+struct evdev{
 	int exist;
 	int open;
 	int minor;
@@ -46,7 +28,7 @@
 	struct input_handle handle;
 	wait_queue_head_t wait;
 	devfs_handle_t devfs;
-	struct evdev_list *list;
+	struct list_head list;
 };
 
 struct evdev_list {
@@ -55,17 +37,17 @@
 	int tail;
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
-	struct evdev_list *next;
+	struct list_head node;
 };
 
-static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ };
+static struct evdev *evdev_table[EVDEV_MINORS];
 
 static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	struct evdev *evdev = handle->private;
-	struct evdev_list *list = evdev->list;
+	struct evdev_list *list;
 
-	while (list) {
+	list_for_each_entry(list, &evdev->list, node) {
 
 		do_gettimeofday(&list->buffer[list->head].time);
 		list->buffer[list->head].type = type;
@@ -74,8 +56,6 @@
 		list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
 
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
-
-		list = list->next;
 	}
 
 	wake_up_interruptible(&evdev->wait);
@@ -91,7 +71,7 @@
 
 static int evdev_flush(struct file * file)
 {
-	struct evdev_list *list = (struct evdev_list*)file->private_data;
+	struct evdev_list *list = file->private_data;
 	if (!list->evdev->exist) return -ENODEV;
 	return input_flush_device(&list->evdev->handle, file);
 }
@@ -99,14 +79,9 @@
 static int evdev_release(struct inode * inode, struct file * file)
 {
 	struct evdev_list *list = file->private_data;
-	struct evdev_list **listptr;
 
-	listptr = &list->evdev->list;
 	evdev_fasync(-1, file, 0);
-
-	while (*listptr && (*listptr != list))
-		listptr = &((*listptr)->next);
-	*listptr = (*listptr)->next;
+	list_del(&list->node);
 
 	if (!--list->evdev->open) {
 		if (list->evdev->exist) {
@@ -132,19 +107,15 @@
 	if (i >= EVDEV_MINORS || !evdev_table[i])
 		return -ENODEV;
 
-	/* Ask the driver if he wishes to accept the open() */
-	if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) {
+	if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
 		return accept_err;
-	}
 
 	if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
 		return -ENOMEM;
 	memset(list, 0, sizeof(struct evdev_list));
 
 	list->evdev = evdev_table[i];
-	list->next = evdev_table[i]->list;
-	evdev_table[i]->list = list;
-
+	list_add_tail(&list->node, &evdev_table[i]->list);
 	file->private_data = list;
 
 	if (!list->evdev->open++)
@@ -175,40 +146,21 @@
 
 static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
 {
-	DECLARE_WAITQUEUE(wait, current);
 	struct evdev_list *list = file->private_data;
-	int retval = 0;
-
-	if (list->head == list->tail) {
-
-		add_wait_queue(&list->evdev->wait, &wait);
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		while (list->head == list->tail) {
-
-			if (!list->evdev->exist) {
-				retval = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				retval = -ERESTARTSYS;
-				break;
-			}
+	int retval;
 
-			schedule();
-		}
+	if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
 
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&list->evdev->wait, &wait);
-	}
+	retval = wait_event_interruptible(list->evdev->wait,
+		list->head != list->tail && list->evdev->exist);
 
 	if (retval)
 		return retval;
 
+	if (!list->evdev->exist)
+		return -ENODEV;
+
 	while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
 		if (copy_to_user(buffer + retval, list->buffer + list->tail,
 			 sizeof(struct input_event))) return -EFAULT;
@@ -433,21 +385,19 @@
 		return NULL;
 	memset(evdev, 0, sizeof(struct evdev));
 
+	INIT_LIST_HEAD(&evdev->list);
 	init_waitqueue_head(&evdev->wait);
 
+	evdev->exist = 1;
 	evdev->minor = minor;
-	evdev_table[minor] = evdev;
-	
-	sprintf(evdev->name, "event%d", minor);
-
 	evdev->handle.dev = dev;
 	evdev->handle.name = evdev->name;
 	evdev->handle.handler = handler;
 	evdev->handle.private = evdev;
+	sprintf(evdev->name, "event%d", minor);
 
+	evdev_table[minor] = evdev;
 	evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
-
-	evdev->exist = 1;
 
 	return &evdev->handle;
 }
diff -Nru a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
--- a/drivers/input/gameport/emu10k1-gp.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/input/gameport/emu10k1-gp.c	Fri Oct 11 21:23:00 2002
@@ -44,7 +44,6 @@
 
 struct emu {
 	struct pci_dev *dev;
-	struct emu *next;
 	struct gameport gameport;
 	int size;
 	char phys[32];
diff -Nru a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
--- a/drivers/input/gameport/gameport.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/input/gameport/gameport.c	Fri Oct 11 21:22:58 2002
@@ -1,31 +1,13 @@
 /*
- * $Id: gameport.c,v 1.18 2002/01/22 20:41:14 vojtech Exp $
- *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- */
-
-/*
  * Generic gameport layer
+ *
+ * Copyright (c) 1999-2002 Vojtech Pavlik
  */
 
 /*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #include <asm/io.h>
@@ -51,9 +33,8 @@
 EXPORT_SYMBOL(gameport_rescan);
 EXPORT_SYMBOL(gameport_cooked_read);
 
-static struct gameport *gameport_list;
-static struct gameport_dev *gameport_dev;
-
+static LIST_HEAD(gameport_list);
+static LIST_HEAD(gameport_dev_list);
 
 #ifdef __i386__
 
@@ -122,12 +103,13 @@
 
 static void gameport_find_dev(struct gameport *gameport)
 {
-        struct gameport_dev *dev = gameport_dev;
+        struct gameport_dev *dev;
 
-        while (dev && !gameport->dev) {
+        list_for_each_entry(dev, &gameport_dev_list, node) {
+		if (gameport->dev)
+			break;
 		if (dev->connect)
                 	dev->connect(gameport, dev);
-                dev = dev->next;
         }
 }
 
@@ -139,52 +121,37 @@
 
 void gameport_register_port(struct gameport *gameport)
 {
-	gameport->next = gameport_list;	
-	gameport_list = gameport;
-
+	list_add_tail(&gameport->node, &gameport_list);
 	gameport->speed = gameport_measure_speed(gameport);
-
 	gameport_find_dev(gameport);
 }
 
 void gameport_unregister_port(struct gameport *gameport)
 {
-        struct gameport **gameportptr = &gameport_list;
-
-        while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next);
-        *gameportptr = (*gameportptr)->next;
-
+	list_del_init(&gameport->node);
 	if (gameport->dev && gameport->dev->disconnect)
 		gameport->dev->disconnect(gameport);
 }
 
 void gameport_register_device(struct gameport_dev *dev)
 {
-	struct gameport *gameport = gameport_list;
+	struct gameport *gameport;
 
-	dev->next = gameport_dev;	
-	gameport_dev = dev;
-
-	while (gameport) {
+	list_add_tail(&dev->node, &gameport_dev_list);
+	list_for_each_entry(gameport, &gameport_list, node)
 		if (!gameport->dev && dev->connect)
 			dev->connect(gameport, dev);
-		gameport = gameport->next;
-	}
 }
 
 void gameport_unregister_device(struct gameport_dev *dev)
 {
-        struct gameport_dev **devptr = &gameport_dev;
-	struct gameport *gameport = gameport_list;
-
-        while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
-        *devptr = (*devptr)->next;
+	struct gameport *gameport;
 
-	while (gameport) {
+	list_del_init(&dev->node);
+	list_for_each_entry(gameport, &gameport_list, node) {
 		if (gameport->dev == dev && dev->disconnect)
 			dev->disconnect(gameport);
 		gameport_find_dev(gameport);
-		gameport = gameport->next;
 	}
 }
 
@@ -209,5 +176,6 @@
 void gameport_close(struct gameport *gameport)
 {
 	gameport->dev = NULL;
-	if (gameport->close) gameport->close(gameport);
+	if (gameport->close)
+		gameport->close(gameport);
 }
diff -Nru a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
--- a/drivers/input/gameport/ns558.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/input/gameport/ns558.c	Fri Oct 11 21:23:03 2002
@@ -53,13 +53,13 @@
 	int type;
 	int size;
 	struct pci_dev *dev;
-	struct ns558 *next;
+	struct list_head node;
 	struct gameport gameport;
 	char phys[32];
 	char name[32];
 };
 	
-static struct ns558 *ns558;
+static LIST_HEAD(ns558_list);
 
 /*
  * ns558_isa_probe() tries to find an isa gameport at the
@@ -67,7 +67,7 @@
  * A joystick must be attached for this to work.
  */
 
-static struct ns558* ns558_isa_probe(int io, struct ns558 *next)
+static void ns558_isa_probe(int io)
 {
 	int i, j, b;
 	unsigned char c, u, v;
@@ -78,7 +78,7 @@
  */
 
 	if (check_region(io, 1))
-		return next;
+		return;
 
 /*
  * We must not be able to write arbitrary values to the port.
@@ -89,7 +89,7 @@
 	outb(~c & ~3, io);
 	if (~(u = v = inb(io)) & 3) {
 		outb(c, io);
-		return next;
+		return;
 	}
 /*
  * After a trigger, there must be at least some bits changing.
@@ -99,7 +99,7 @@
 
 	if (u == v) {
 		outb(c, io);
-		return next;
+		return;
 	}
 	wait_ms(3);
 /*
@@ -110,7 +110,7 @@
 	for (i = 0; i < 1000; i++)
 		if ((u ^ inb(io)) & 0xf) {
 			outb(c, io);
-			return next;
+			return;
 		}
 /* 
  * And now find the number of mirrors of the port.
@@ -134,11 +134,10 @@
 
 	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
 		printk(KERN_ERR "ns558: Memory allocation failed.\n");
-		return next;
+		return;
 	}
        	memset(port, 0, sizeof(struct ns558));
 	
-	port->next = next;
 	port->type = NS558_ISA;
 	port->size = (1 << i);
 	port->gameport.io = io & (-1 << i);
@@ -157,7 +156,7 @@
 	if (port->size > 1) printk(" size %d", port->size);
 	printk(" speed %d kHz\n", port->gameport.speed);
 
-	return port;
+	list_add(&port->node, &ns558_list);
 }
 
 #ifdef __ISAPNP__
@@ -194,22 +193,22 @@
 
 MODULE_DEVICE_TABLE(isapnp, pnp_devids);
 
-static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
+static void ns558_pnp_probe(struct pci_dev *dev)
 {
 	int ioport, iolen;
 	struct ns558 *port;
 
 	if (dev->prepare && dev->prepare(dev) < 0)
-		return next;
+		return;
 
 	if (!(dev->resource[0].flags & IORESOURCE_IO)) {
 		printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
-		return next;
+		return;
 	}
 
 	if (dev->activate && dev->activate(dev) < 0) {
 		printk(KERN_ERR "ns558: PnP resource allocation failed\n");
-		return next;
+		return;
 	}
 	
 	ioport = pci_resource_start(dev, 0);
@@ -224,7 +223,6 @@
 	}
 	memset(port, 0, sizeof(struct ns558));
 
-	port->next = next;
 	port->type = NS558_PNP;
 	port->size = iolen;
 	port->dev = dev;
@@ -247,12 +245,12 @@
 	if (iolen > 1) printk(" size %d", iolen);
 	printk(" speed %d kHz\n", port->gameport.speed);
 
-	return port;
+	list_add_tail(&port->node, &ns558_list);
+	return;
 
 deactivate:
 	if (dev->deactivate)
 		dev->deactivate(dev);
-	return next;
 }
 #endif
 
@@ -269,28 +267,26 @@
  */
 
 	while (ns558_isa_portlist[i]) 
-		ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
+		ns558_isa_probe(ns558_isa_portlist[i++]);
 
 /*
  * Probe for PnP ports.
  */
 
 #ifdef __ISAPNP__
-	for (devid = pnp_devids; devid->vendor; devid++) {
-		while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
-			ns558 = ns558_pnp_probe(dev, ns558);
-		}
-	}
+	for (devid = pnp_devids; devid->vendor; devid++)
+		while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev)))
+			ns558_pnp_probe(dev);
 #endif
 
-	return ns558 ? 0 : -ENODEV;
+	return list_empty(&ns558_list) ? -ENODEV : 0;
 }
 
 void __exit ns558_exit(void)
 {
-	struct ns558 *next, *port = ns558;
+	struct ns558 *port;
 
-	while (port) {
+	list_for_each_entry(port, &ns558_list, node) {
 		gameport_unregister_port(&port->gameport);
 		switch (port->type) {
 
@@ -308,10 +304,6 @@
 			default:
 				break;
 		}
-		
-		next = port->next;
-		kfree(port);
-		port = next;
 	}
 }
 
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/input/input.c	Fri Oct 11 21:22:59 2002
@@ -58,7 +58,7 @@
 
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-	struct list_head * node;
+	struct input_handle *handle;
 
 	if (dev->pm_dev)
 		pm_access(dev->pm_dev);
@@ -177,11 +177,9 @@
 	if (type != EV_SYN) 
 		dev->sync = 0;
 
-	list_for_each(node,&dev->h_list) {
-		struct input_handle *handle = to_handle(node);
+	list_for_each_entry(handle, &dev->h_list, d_node)
 		if (handle->open)
 			handle->handler->event(handle, type, code, value);
-	}
 }
 
 static void input_repeat_key(unsigned long data)
@@ -234,8 +232,8 @@
 
 static void input_link_handle(struct input_handle *handle)
 {
-	list_add_tail(&handle->d_node,&handle->dev->h_list);
-	list_add_tail(&handle->h_node,&handle->handler->h_list);
+	list_add_tail(&handle->d_node, &handle->dev->h_list);
+	list_add_tail(&handle->h_node, &handle->handler->h_list);
 }
 
 #define MATCH_BIT(bit, max) \
@@ -400,8 +398,8 @@
 
 void input_register_device(struct input_dev *dev)
 {
-	struct list_head * node;
 	struct input_handle *handle;
+	struct input_handler *handler;
 	struct input_device_id *id;
 
 	set_bit(EV_SYN, dev->evbit);
@@ -413,14 +411,12 @@
 	dev->rep[REP_PERIOD] = HZ/33;
 
 	INIT_LIST_HEAD(&dev->h_list);
-	list_add_tail(&dev->node,&input_dev_list);
+	list_add_tail(&dev->node, &input_dev_list);
 
-	list_for_each(node,&input_handler_list) {
-		struct input_handler *handler = to_handler(node);
+	list_for_each_entry(handler, &input_handler_list, node)
 		if ((id = input_match_device(handler->id_table, dev)))
 			if ((handle = handler->connect(handler, dev, id)))
 				input_link_handle(handle);
-	}
 
 #ifdef CONFIG_HOTPLUG
 	input_call_hotplug("add", dev);
@@ -443,7 +439,7 @@
 
 	del_timer_sync(&dev->timer);
 
-	list_for_each_safe(node,next,&dev->h_list) {
+	list_for_each_safe(node, next, &dev->h_list) {
 		struct input_handle * handle = to_handle(node);
 		list_del_init(&handle->d_node);
 		list_del_init(&handle->h_node);
@@ -464,7 +460,7 @@
 
 void input_register_handler(struct input_handler *handler)
 {
-	struct list_head * node;
+	struct input_dev *dev;
 	struct input_handle *handle;
 	struct input_device_id *id;
 
@@ -475,14 +471,12 @@
 	if (handler->fops != NULL)
 		input_table[handler->minor >> 5] = handler;
 
-	list_add_tail(&handler->node,&input_handler_list);
+	list_add_tail(&handler->node, &input_handler_list);
 	
-	list_for_each(node,&input_dev_list) {
-		struct input_dev *dev = to_dev(node);
+	list_for_each_entry(dev, &input_dev_list, node)
 		if ((id = input_match_device(handler->id_table, dev)))
 			if ((handle = handler->connect(handler, dev, id)))
 				input_link_handle(handle);
-	}
 
 #ifdef CONFIG_PROC_FS
 	input_devices_state++;
@@ -494,7 +488,7 @@
 {
 	struct list_head * node, * next;
 
-	list_for_each_safe(node,next,&handler->h_list) {
+	list_for_each_safe(node, next, &handler->h_list) {
 		struct input_handle * handle = to_handle_h(node);
 		list_del_init(&handle->h_node);
 		list_del_init(&handle->d_node);
@@ -591,14 +585,13 @@
 
 static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
 {
-	struct list_head * node;
+	struct input_dev *dev;
+	struct input_handle *handle;
 
 	off_t at = 0;
 	int i, len, cnt = 0;
 
-	list_for_each(node,&input_dev_list) {
-		struct input_dev * dev = to_dev(node);
-		struct list_head * hnode;
+	list_for_each_entry(dev, &input_dev_list, node) {
 
 		len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",
 			dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
@@ -607,10 +600,8 @@
 		len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : "");
 		len += sprintf(buf + len, "H: Handlers=");
 
-		list_for_each(hnode,&dev->h_list) {
-			struct input_handle * handle = to_handle(hnode);
+		list_for_each_entry(handle, &dev->h_list, d_node)
 			len += sprintf(buf + len, "%s ", handle->name);
-		}
 
 		len += sprintf(buf + len, "\n");
 
@@ -638,7 +629,7 @@
 		}
 	}
 
-	if (node == &input_dev_list)
+	if (&dev->node == &input_dev_list)
 		*eof = 1;
 
 	return (count > cnt) ? cnt : count;
@@ -646,14 +637,13 @@
 
 static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
 {
-	struct list_head * node;
+	struct input_handler *handler;
 
 	off_t at = 0;
 	int len = 0, cnt = 0;
 	int i = 0;
 
-	list_for_each(node,&input_handler_list) {
-		struct input_handler *handler = to_handler(node);
+	list_for_each_entry(handler, &input_handler_list, node) {
 
 		if (handler->fops)
 			len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n",
@@ -674,7 +664,7 @@
 				break;
 		}
 	}
-	if (node == &input_handler_list)
+	if (&handler->node == &input_handler_list)
 		*eof = 1;
 
 	return (count > cnt) ? cnt : count;
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/input/joydev.c	Fri Oct 11 21:22:58 2002
@@ -1,30 +1,13 @@
 /*
- * $Id: joydev.c,v 1.43 2002/04/09 23:59:01 jsimmons Exp $
+ * Joystick device driver for the input driver suite.
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik 
- *  Copyright (c) 1999 Colin Van Dyke 
+ * Copyright (c) 1999-2002 Vojtech Pavlik 
+ * Copyright (c) 1999 Colin Van Dyke 
  *
- *  Joystick device driver for the input driver suite.
- */
-
-/*
  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -63,8 +46,7 @@
 	struct input_handle handle;
 	wait_queue_head_t wait;
 	devfs_handle_t devfs;
-	struct joydev *next;
-	struct joydev_list *list;
+	struct list_head list;
 	struct js_corr corr[ABS_MAX];
 	struct JS_DATA_SAVE_TYPE glue;
 	int nabs;
@@ -83,7 +65,7 @@
 	int startup;
 	struct fasync_struct *fasync;
 	struct joydev *joydev;
-	struct joydev_list *next;
+	struct list_head node;
 };
 
 static struct joydev *joydev_table[JOYDEV_MINORS];
@@ -111,7 +93,7 @@
 static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	struct joydev *joydev = handle->private;
-	struct joydev_list *list = joydev->list;
+	struct joydev_list *list;
 	struct js_event event;
 
 	switch (type) {
@@ -137,7 +119,7 @@
 
 	event.time = MSECS(jiffies);
 
-	while (list) {
+	list_for_each_entry(list, &joydev->list, node) {
 
 		memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
 
@@ -146,8 +128,6 @@
 				list->startup = 0;
 
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
-
-		list = list->next;
 	}
 
 	wake_up_interruptible(&joydev->wait);
@@ -164,14 +144,10 @@
 static int joydev_release(struct inode * inode, struct file * file)
 {
 	struct joydev_list *list = file->private_data;
-	struct joydev_list **listptr;
 
-	listptr = &list->joydev->list;
 	joydev_fasync(-1, file, 0);
 
-	while (*listptr && (*listptr != list))
-		listptr = &((*listptr)->next);
-	*listptr = (*listptr)->next;
+	list_del(&list->node);
 
 	if (!--list->joydev->open) {
 		if (list->joydev->exist) {
@@ -201,9 +177,7 @@
 	memset(list, 0, sizeof(struct joydev_list));
 
 	list->joydev = joydev_table[i];
-	list->next = joydev_table[i]->list;
-	joydev_table[i]->list = list;	
-
+	list_add_tail(&list->node, &joydev_table[i]->list);
 	file->private_data = list;
 
 	if (!list->joydev->open++)
@@ -220,12 +194,14 @@
 
 static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
-	DECLARE_WAITQUEUE(wait, current);
 	struct joydev_list *list = file->private_data;
 	struct joydev *joydev = list->joydev;
 	struct input_dev *input = joydev->handle.dev;
 	int retval = 0;
 
+	if (!list->joydev->exist)
+		return -ENODEV;
+
 	if (count < sizeof(struct js_event))
 		return -EINVAL;
 
@@ -248,36 +224,19 @@
 		return sizeof(struct JS_DATA_TYPE);
 	}
 
-	if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) {
-
-		add_wait_queue(&list->joydev->wait, &wait);
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		while (list->head == list->tail) {
-
-			if (!joydev->exist) {
-				retval = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				retval = -ERESTARTSYS;
-				break;
-			}
-
-			schedule();
-		}
+	if (list->startup == joydev->nabs + joydev->nkey
+		&& list->head == list->tail && (file->f_flags & O_NONBLOCK))
+			return -EAGAIN;
 
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&list->joydev->wait, &wait);
-	}
+	retval = wait_event_interruptible(list->joydev->wait, list->joydev->exist
+		&& (list->startup < joydev->nabs + joydev->nkey || list->head != list->tail));
 
 	if (retval)
 		return retval;
 
+	if (!list->joydev->exist)
+		return -ENODEV;
+
 	while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
 
 		struct js_event event;
@@ -431,17 +390,16 @@
 		return NULL;
 	memset(joydev, 0, sizeof(struct joydev));
 
+	INIT_LIST_HEAD(&joydev->list);
 	init_waitqueue_head(&joydev->wait);
 
 	joydev->minor = minor;
-	joydev_table[minor] = joydev;
-
-	sprintf(joydev->name, "js%d", minor);
-
+	joydev->exist = 1;
 	joydev->handle.dev = dev;
 	joydev->handle.name = joydev->name;
 	joydev->handle.handler = handler;
 	joydev->handle.private = joydev;
+	sprintf(joydev->name, "js%d", minor);
 
 	for (i = 0; i < ABS_MAX; i++)
 		if (test_bit(i, dev->absbit)) {
@@ -482,9 +440,8 @@
 		joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
 	}
 
+	joydev_table[minor] = joydev;
 	joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
-
-	joydev->exist = 1;
 
 	return &joydev->handle;
 }
diff -Nru a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
--- a/drivers/input/joystick/a3d.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/input/joystick/a3d.c	Fri Oct 11 21:22:50 2002
@@ -300,6 +300,8 @@
 
 		a3d->length = 33;
 
+		init_input_dev(&a3d->dev);
+
 		a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
 		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
 		a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
@@ -327,6 +329,8 @@
 
 	} else {
 		a3d->length = 29;
+
+		init_input_dev(&a3d->dev);
 
 		a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
 		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
diff -Nru a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
--- a/drivers/input/joystick/adi.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/input/joystick/adi.c	Fri Oct 11 21:22:55 2002
@@ -404,6 +404,8 @@
 
 	if (!adi->length) return;
 
+	init_input_dev(&adi->dev);
+
 	t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
 
 	sprintf(buf, adi_names[t], adi->id);
diff -Nru a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
--- a/drivers/input/joystick/analog.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/input/joystick/analog.c	Fri Oct 11 21:23:04 2002
@@ -431,8 +431,9 @@
 
 	analog_name(analog);
 	sprintf(analog->phys, "%s/input%d", port->gameport->phys, index);
-
 	analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
+
+	init_input_dev(&analog->dev);
 
 	analog->dev.name = analog->name;
 	analog->dev.phys = analog->phys;
diff -Nru a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
--- a/drivers/input/joystick/gf2k.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/input/joystick/gf2k.c	Fri Oct 11 21:22:54 2002
@@ -290,6 +290,8 @@
 
 	gf2k->length = gf2k_lens[gf2k->id];
 
+	init_input_dev(&gf2k->dev);
+
 	gf2k->dev.private = gf2k;
 	gf2k->dev.open = gf2k_open;
 	gf2k->dev.close = gf2k_close;
diff -Nru a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
--- a/drivers/input/joystick/magellan.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/input/joystick/magellan.c	Fri Oct 11 21:22:51 2002
@@ -169,6 +169,7 @@
 
 	sprintf(magellan->phys, "%s/input0", serio->phys);
 
+	init_input_dev(&magellan->dev);
 	magellan->dev.private = magellan;
 	magellan->dev.name = magellan_name;
 	magellan->dev.phys = magellan->phys;
@@ -187,6 +188,7 @@
 	input_register_device(&magellan->dev);
 
 	printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys);
+
 }
 
 /*
diff -Nru a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
--- a/drivers/input/joystick/spaceball.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/input/joystick/spaceball.c	Fri Oct 11 21:22:52 2002
@@ -240,6 +240,7 @@
 
 	sprintf(spaceball->phys, "%s/input0", serio->phys);
 
+	init_input_dev(&spaceball->dev);
 	spaceball->dev.name = spaceball_names[id];
 	spaceball->dev.phys = spaceball->phys;
 	spaceball->dev.id.bustype = BUS_RS232;
diff -Nru a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
--- a/drivers/input/joystick/spaceorb.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/input/joystick/spaceorb.c	Fri Oct 11 21:22:57 2002
@@ -187,6 +187,7 @@
 
 	sprintf(spaceorb->phys, "%s/input0", serio->phys);
 
+	init_input_dev(&spaceorb->dev);
 	spaceorb->dev.name = spaceorb_name;
 	spaceorb->dev.phys = spaceorb->phys;
 	spaceorb->dev.id.bustype = BUS_RS232;
diff -Nru a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
--- a/drivers/input/joystick/stinger.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/input/joystick/stinger.c	Fri Oct 11 21:22:50 2002
@@ -152,6 +152,7 @@
 
 	sprintf(stinger->phys, "%s/serio0", serio->phys);
 
+	init_input_dev(&stinger->dev);
 	stinger->dev.name = stinger_name;
 	stinger->dev.phys = stinger->phys;
 	stinger->dev.id.bustype = BUS_RS232;
@@ -166,7 +167,6 @@
 	}
 
 	stinger->dev.private = stinger;
-	
 	serio->private = stinger;
 
 	if (serio_open(serio, dev)) {
@@ -177,6 +177,7 @@
 	input_register_device(&stinger->dev);
 
 	printk(KERN_INFO "input: %s on %s\n",  stinger_name, serio->phys);
+
 }
 
 /*
diff -Nru a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
--- a/drivers/input/joystick/twidjoy.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/input/joystick/twidjoy.c	Fri Oct 11 21:22:53 2002
@@ -198,6 +198,7 @@
 
 	sprintf(twidjoy->phys, "%s/input0", serio->phys);
 
+	init_input_dev(&twidjoy->dev);
 	twidjoy->dev.name = twidjoy_name;
 	twidjoy->dev.phys = twidjoy->phys;
 	twidjoy->dev.id.bustype = BUS_RS232;
@@ -224,7 +225,6 @@
 	}
 
 	twidjoy->dev.private = twidjoy;
-	
 	serio->private = twidjoy;
 
 	if (serio_open(serio, dev)) {
diff -Nru a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
--- a/drivers/input/joystick/warrior.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/input/joystick/warrior.c	Fri Oct 11 21:23:02 2002
@@ -155,6 +155,7 @@
 
 	sprintf(warrior->phys, "%s/input0", serio->phys);
 
+	init_input_dev(&warrior->dev);
 	warrior->dev.name = warrior_name;
 	warrior->dev.phys = warrior->phys;
 	warrior->dev.id.bustype = BUS_RS232;
@@ -180,7 +181,7 @@
 	
 	serio->private = warrior;
 
-	if (serio_open(serio, dev)) {
+	if (serio_open(serio, dev)) { 
 		kfree(warrior);
 		return;
 	}
diff -Nru a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
--- a/drivers/input/keyboard/amikbd.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/input/keyboard/amikbd.c	Fri Oct 11 21:22:55 2002
@@ -112,6 +112,8 @@
 	if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
 		return -EBUSY;
 
+	init_input_dev(&amibkd_dev);
+
 	amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 	amikbd_dev.keycode = amikbd_keycode;
 	amikbd_dev.keycodesize = sizeof(unsigned char);
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/input/keyboard/atkbd.c	Fri Oct 11 21:23:03 2002
@@ -22,9 +22,15 @@
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
 MODULE_PARM(atkbd_set, "1i");
+MODULE_PARM(atkbd_reset, "1i");
 MODULE_LICENSE("GPL");
 
 static int atkbd_set = 2;
+#if defined(__i386__) || defined (__x86_64__)
+static int atkbd_reset;
+#else
+static int atkbd_reset = 1;
+#endif
 
 /*
  * Scancode to keycode tables. These are just the default setting, and
@@ -38,7 +44,7 @@
 	  0, 49, 48, 35, 34, 21,  7,  0,  0,  0, 50, 36, 22,  8,  9,  0,
 	  0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
 	122, 89, 40,120, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0,  0,
-	 85, 86, 90, 91, 92, 93, 14, 94, 95, 79,  0, 75, 71,121,  0,123,
+	 85, 86, 90, 91, 92, 93, 14, 94, 95, 79,183, 75, 71,121,  0,123,
 	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
 	252,  0,  0, 65, 99,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
@@ -49,11 +55,11 @@
 	252,253,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	254,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,255,
 	  0,  0, 92, 90, 85,  0,137,  0,  0,  0,  0, 91, 89,144,115,  0,
-	136,100,255,  0, 97,149,164,  0,156,  0,  0,140,115,  0,  0,125,
-	  0,150,  0,154,152,163,151,126,112,166,  0,140,  0,147,  0,127,
-	159,167,139,160,163,  0,  0,116,158,  0,150,165,  0,  0,  0,142,
-	157,  0,114,166,168,  0,  0,  0,155,  0, 98,113,  0,148,  0,138,
-	  0,  0,  0,  0,  0,  0,153,140,  0,255, 96,  0,  0,  0,143,  0,
+	217,100,255,  0, 97,165,164,  0,156,  0,  0,140,115,  0,  0,125,
+	173,114,  0,113,152,163,151,126,128,166,  0,140,  0,147,  0,127,
+	159,167,115,160,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
+	157,  0,114,166,168,  0,  0,  0,155,  0, 98,113,  0,163,  0,138,
+	226,  0,  0,  0,  0,  0,153,140,  0,255, 96,  0,  0,  0,143,  0,
 	133,  0,116,  0,143,  0,174,133,  0,107,  0,105,102,  0,  0,112,
 	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119
 };
@@ -67,7 +73,7 @@
 	113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70,
 	108,105,119,103,111,107, 14,110,  0, 79,106, 75, 71,109,102,104,
 	 82, 83, 80, 76, 77, 72, 69, 98,  0, 96, 81,  0, 78, 73, 55, 85,
-	 89, 90, 91, 92, 74,  0,  0,  0,  0,  0,  0,125,126,127,112,  0,
+	 89, 90, 91, 92, 74,185,184,182,  0,  0,  0,125,126,127,112,  0,
 	  0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
 	148,149,147,140,  0,  0,  0,  0,  0,  0,251,  0,  0,  0,  0,  0,
 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
@@ -89,6 +95,7 @@
 #define ATKBD_CMD_RESEND	0x00fe
 #define ATKBD_CMD_EX_ENABLE	0x10ea
 #define ATKBD_CMD_EX_SETLEDS	0x20eb
+#define ATKBD_CMD_OK_GETID	0x02e8
 
 #define ATKBD_RET_ACK		0xfa
 #define ATKBD_RET_NAK		0xfe
@@ -113,6 +120,7 @@
 	unsigned char cmdbuf[4];
 	unsigned char cmdcnt;
 	unsigned char set;
+	unsigned char oldset;
 	unsigned char release;
 	signed char ack;
 	unsigned char emul;
@@ -134,7 +142,6 @@
 	printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
 #endif
 
-	/* Interface error.  Request that the keyboard resend. */
 	if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && atkbd->write) {
 		printk("atkbd.c: frame/parity error: %02x\n", flags);
 		serio_write(serio, ATKBD_CMD_RESEND);
@@ -205,7 +212,9 @@
 #ifdef ATKBD_DEBUG
 	printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
 #endif
-	serio_write(atkbd->serio, byte);
+	if (serio_write(atkbd->serio, byte))
+		return -1;
+
 	while (!atkbd->ack && timeout--) udelay(10);
 
 	return -(atkbd->ack <= 0);
@@ -235,8 +244,9 @@
 
 	while (atkbd->cmdcnt && timeout--) udelay(10);
 
-	for (i = 0; i < receive; i++)
-		param[i] = atkbd->cmdbuf[(receive - 1) - i];
+	if (param)
+		for (i = 0; i < receive; i++)
+			param[i] = atkbd->cmdbuf[(receive - 1) - i];
 
 	if (atkbd->cmdcnt) 
 		return (atkbd->cmdcnt = 0) - 1;
@@ -271,6 +281,7 @@
 				param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
 					 | (test_bit(LED_SLEEP,   dev->led) ? 0x02 : 0)
 					 | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
+				         | (test_bit(LED_MISC,    dev->led) ? 0x10 : 0)
 				         | (test_bit(LED_MUTE,    dev->led) ? 0x20 : 0);
 				atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
 			}
@@ -289,34 +300,45 @@
 
 static int atkbd_set_3(struct atkbd *atkbd)
 {
-	unsigned char param;
+	unsigned char param[2];
+
+/*
+ * Remember original scancode set value, so that we can restore it on exit.
+ */
+
+	if (atkbd_command(atkbd, &atkbd->oldset, ATKBD_CMD_GSCANSET))
+		atkbd->oldset = 2;
 
 /*
  * For known special keyboards we can go ahead and set the correct set.
+ * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and
+ * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
  */
 
 	if (atkbd->id == 0xaca1) {
-		param = 3;
-		atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET);
+		param[0] = 3;
+		atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET);
 		return 3;
 	}
 
-/*
- * We check for the extra keys on an some keyboards that need extra
- * command to get enabled. This shouldn't harm any keyboards not
- * knowing the command.
- */
+	if (atkbd_set != 2) 
+		if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
+			atkbd->id = param[0] << 8 | param[1];
+			return 2;
+		}
 
-	param = 0x71;
-	if (!atkbd_command(atkbd, &param, ATKBD_CMD_EX_ENABLE))
-		return 4;
+	if (atkbd_set == 4) {
+		param[0] = 0x71;
+		if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE))
+			return 4;
+	}
 
 /*
  * Try to set the set we want.
  */
 
-	param = atkbd_set;
-	if (atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET))
+	param[0] = atkbd_set;
+	if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
 		return 2;
 
 /*
@@ -327,8 +349,8 @@
  * In that case we time out, and return 2.
  */
 
-	param = 0;
-	if (atkbd_command(atkbd, &param, ATKBD_CMD_GSCANSET))
+	param[0] = 0;
+	if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET))
 		return 2;
 
 /*
@@ -336,7 +358,7 @@
  * itself.
  */
 
-	return (param == 3) ? 3 : 2;
+	return (param[0] == 3) ? 3 : 2;
 }
 
 /*
@@ -353,10 +375,9 @@
  * these systems the BIOS also usually doesn't do it for us.
  */
 
-#ifdef CONFIG_KEYBOARD_ATKBD_RESET
-	if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
-		printk(KERN_WARNING "atkbd.c: keyboard reset failed\n");
-#endif
+	if (atkbd_reset)
+		if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
+			printk(KERN_WARNING "atkbd.c: keyboard reset failed\n");
 
 /*
  * Next we check we can set LEDs on the keyboard. This should work on every
@@ -405,7 +426,18 @@
 }
 
 /*
- * atkbd_disconnect() cleans up behind us ...
+ * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
+ * reboot.
+ */
+
+static void atkbd_cleanup(struct serio *serio)
+{
+	struct atkbd *atkbd = serio->private;
+	atkbd_command(atkbd, &atkbd->oldset, ATKBD_CMD_SSCANSET);
+}
+
+/*
+ * atkbd_disconnect() closes and frees.
  */
 
 static void atkbd_disconnect(struct serio *serio)
@@ -447,6 +479,8 @@
 
 	atkbd->serio = serio;
 
+	init_input_dev(&atkbd->dev);
+
 	atkbd->dev.keycode = atkbd->keycode;
 	atkbd->dev.keycodesize = sizeof(unsigned char);
 	atkbd->dev.keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
@@ -476,7 +510,7 @@
 	}
 
 	if (atkbd->set == 4) {
-		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE);
+		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
 		sprintf(atkbd->name, "AT Set 2 Extended keyboard");
 	} else
 		sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set);
@@ -508,18 +542,28 @@
 static struct serio_dev atkbd_dev = {
 	.interrupt =	atkbd_interrupt,
 	.connect =	atkbd_connect,
-	.disconnect =	atkbd_disconnect
+	.disconnect =	atkbd_disconnect,
+	.cleanup =	atkbd_cleanup,
 };
 
 #ifndef MODULE
-static int __init atkbd_setup(char *str)
+static int __init atkbd_setup_set(char *str)
 {
         int ints[4];
         str = get_options(str, ARRAY_SIZE(ints), ints);
         if (ints[0] > 0) atkbd_set = ints[1];
         return 1;
 }
-__setup("atkbd_set=", atkbd_setup);
+static int __init atkbd_setup_reset(char *str)
+{
+        int ints[4];
+        str = get_options(str, ARRAY_SIZE(ints), ints);
+        if (ints[0] > 0) atkbd_reset = ints[1];
+        return 1;
+}
+
+__setup("atkbd_set=", atkbd_setup_set);
+__setup("atkbd_reset", atkbd_setup_reset);
 #endif
 
 int __init atkbd_init(void)
diff -Nru a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
--- a/drivers/input/keyboard/newtonkbd.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/input/keyboard/newtonkbd.c	Fri Oct 11 21:22:50 2002
@@ -93,11 +93,11 @@
 
 	nkbd->serio = serio;
 
+	init_input_dev(&nkbd->dev);
 	nkbd->dev.keycode = nkbd->keycode;
 	nkbd->dev.keycodesize = sizeof(unsigned char);
 	nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode);
 	nkbd->dev.private = nkbd;
-
 	serio->private = nkbd;
 
 	if (serio_open(serio, dev)) {
diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- a/drivers/input/keyboard/sunkbd.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/input/keyboard/sunkbd.c	Fri Oct 11 21:22:50 2002
@@ -234,6 +234,8 @@
 
 	memset(sunkbd, 0, sizeof(struct sunkbd));
 
+	init_input_dev(&sunkbd->dev);
+
 	sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
 	sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
 	sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL);
diff -Nru a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
--- a/drivers/input/keyboard/xtkbd.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/input/keyboard/xtkbd.c	Fri Oct 11 21:22:59 2002
@@ -100,6 +100,7 @@
 
 	xtkbd->serio = serio;
 
+	init_input_dev(&xtkbd->dev);
 	xtkbd->dev.keycode = xtkbd->keycode;
 	xtkbd->dev.keycodesize = sizeof(unsigned char);
 	xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode);
diff -Nru a/drivers/input/misc/Config.in b/drivers/input/misc/Config.in
--- a/drivers/input/misc/Config.in	Fri Oct 11 21:23:02 2002
+++ b/drivers/input/misc/Config.in	Fri Oct 11 21:23:02 2002
@@ -8,4 +8,7 @@
 if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
    dep_tristate '  SPARC Speaker support' CONFIG_INPUT_SPARCSPKR $CONFIG_INPUT $CONFIG_INPUT_MISC
 fi
+if [ "$CONFIG_M68K" = "y" ]; then
+dep_tristate '  M68k Beeper support' CONFIG_INPUT_M68K_BEEP $CONFIG_INPUT $CONFIG_INPUT_MISC
+fi
 dep_tristate '  User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT $CONFIG_INPUT_MISC
diff -Nru a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
--- a/drivers/input/misc/Makefile	Fri Oct 11 21:23:00 2002
+++ b/drivers/input/misc/Makefile	Fri Oct 11 21:23:00 2002
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_INPUT_SPARCSPKR)		+= sparcspkr.o
 obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
+obj-$(CONFIG_INPUT_M68K_BEEP)		+= m68kspkr.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
 
 # The global Rules.make.
diff -Nru a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/misc/m68kspkr.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,83 @@
+/*
+ *  m68k beeper driver for Linux
+ *
+ *  Copyright (c) 2002 Richard Zidlicky
+ *  Copyright (c) 2002 Vojtech Pavlik
+ *  Copyright (c) 1992 Orest Zborowski
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+
+MODULE_AUTHOR("Richard Zidlicky <rz@linux-m68k.org>");
+MODULE_DESCRIPTION("m68k beeper driver");
+MODULE_LICENSE("GPL");
+
+static char m68kspkr_name[] = "m68k beeper";
+static char m68kspkr_phys[] = "m68k/generic";
+static struct input_dev m68kspkr_dev;
+
+static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	unsigned int count = 0;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+		case SND_BELL: if (value) value = 1000;
+		case SND_TONE: break;
+		default: return -1;
+	}
+
+	if (value > 20 && value < 32767)
+		count = 1193182 / value;
+
+	mach_beep(count, -1);
+
+	return 0;
+}
+
+static int __init m68kspkr_init(void)
+{
+        if (!mach_beep){
+		printk("%s: no lowlevel beep support\n", m68kspkr_name);
+		return -1;
+        }
+
+	m68kspkr_dev.evbit[0] = BIT(EV_SND);
+	m68kspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+	m68kspkr_dev.event = m68kspkr_event;
+
+	m68kspkr_dev.name = m68kspkr_name;
+	m68kspkr_dev.phys = m68kspkr_phys;
+	m68kspkr_dev.id.bustype = BUS_HOST;
+	m68kspkr_dev.id.vendor = 0x001f;
+	m68kspkr_dev.id.product = 0x0001;
+	m68kspkr_dev.id.version = 0x0100;
+
+	input_register_device(&m68kspkr_dev);
+
+        printk(KERN_INFO "input: %s\n", m68kspkr_name);
+
+	return 0;
+}
+
+static void __exit m68kspkr_exit(void)
+{
+        input_unregister_device(&m68kspkr_dev);
+}
+
+module_init(m68kspkr_init);
+module_exit(m68kspkr_exit);
diff -Nru a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
--- a/drivers/input/misc/uinput.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/input/misc/uinput.c	Fri Oct 11 21:23:03 2002
@@ -49,7 +49,7 @@
 
 	udev = (struct uinput_device *)dev->private;
 
-	udev->head = (udev->head + 1) & 0xF;
+	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
 	udev->buff[udev->head].type = type;
 	udev->buff[udev->head].code = code;
 	udev->buff[udev->head].value = value;
@@ -87,14 +87,14 @@
 
 	input_register_device(udev->dev);
 
-	udev->state |= UIST_CREATED;
+	set_bit(UIST_CREATED, &(udev->state));
 
 	return 0;
 }
 
 static int uinput_destroy_device(struct uinput_device *udev)
 {
-	if (!(udev->state & UIST_CREATED)) {
+	if (!test_bit(UIST_CREATED, &(udev->state))) {
 		printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
 		return -EINVAL;
 	}
@@ -135,6 +135,39 @@
 	return -ENOMEM;
 }
 
+static int uinput_validate_absbits(struct input_dev *dev)
+{
+	unsigned int cnt;
+	int retval = 0;
+	
+	for (cnt = 0; cnt < ABS_MAX; cnt++) {
+		if (!test_bit(cnt, dev->absbit)) 
+			continue;
+		
+		if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
+		    (dev->absmax[cnt] <= dev->absmin[cnt])) {
+			printk(KERN_DEBUG 
+				"%s: invalid abs[%02x] min:%d max:%d\n",
+				UINPUT_NAME, cnt, 
+				dev->absmin[cnt], dev->absmax[cnt]);
+			retval = -EINVAL;
+			break;
+		}
+
+		if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
+		    (dev->absflat[cnt] > dev->absmax[cnt])) {
+			printk(KERN_DEBUG 
+				"%s: absflat[%02x] out of range: %d "
+				"(min:%d/max:%d)\n",
+				UINPUT_NAME, cnt, dev->absflat[cnt],
+				dev->absmin[cnt], dev->absmax[cnt]);
+			retval = -EINVAL;
+			break;
+		}
+	}
+	return retval;
+}
+
 static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
 {
 	struct uinput_user_dev	user_dev;
@@ -145,14 +178,17 @@
 
 	retval = count;
 
+	udev = (struct uinput_device *)file->private_data;
+	dev = udev->dev;
+
 	if (copy_from_user(&user_dev, buffer, sizeof(struct uinput_user_dev))) {
 		retval = -EFAULT;
 		goto exit;
 	}
 
-	udev = (struct uinput_device *)file->private_data;
-	dev = udev->dev;
-
+	if (NULL != dev->name) 
+		kfree(dev->name);
+		
 	size = strnlen(user_dev.name, UINPUT_MAX_NAME_SIZE);
 	dev->name = kmalloc(size + 1, GFP_KERNEL);
 	if (!dev->name) {
@@ -168,7 +204,7 @@
 	dev->id.version	= user_dev.id.version;
 	dev->ff_effects_max = user_dev.ff_effects_max;
 
-	size = sizeof(unsigned long) * NBITS(ABS_MAX + 1);
+	size = sizeof(int) * (ABS_MAX + 1);
 	memcpy(dev->absmax, user_dev.absmax, size);
 	memcpy(dev->absmin, user_dev.absmin, size);
 	memcpy(dev->absfuzz, user_dev.absfuzz, size);
@@ -177,33 +213,20 @@
 	/* check if absmin/absmax/absfuzz/absflat are filled as
 	 * told in Documentation/input/input-programming.txt */
 	if (test_bit(EV_ABS, dev->evbit)) {
-		unsigned int cnt;
-		for (cnt = 1; cnt < ABS_MAX; cnt++)
-			if (test_bit(cnt, dev->absbit) &&
-					(!dev->absmin[cnt] ||
-					 !dev->absmax[cnt] ||
-					 !dev->absfuzz[cnt] ||
-					 !dev->absflat[cnt])) {
-				printk(KERN_DEBUG "%s: set abs fields "
-					"first\n", UINPUT_NAME);
-				retval = -EINVAL;
-				goto free_name;
-			}
+		retval = uinput_validate_absbits(dev);
+		if (retval < 0)
+			kfree(dev->name);
 	}
 
 exit:
 	return retval;
-free_name:
-	kfree(dev->name);
-	goto exit;
 }
 
 static int uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct uinput_device	*udev = file->private_data;
 	
-
-	if (udev->state & UIST_CREATED) {
+	if (test_bit(UIST_CREATED, &(udev->state))) {
 		struct input_event	ev;
 
 		if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
@@ -218,43 +241,30 @@
 
 static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
-	struct uinput_device	*udev;
+	struct uinput_device *udev = file->private_data;
 	int retval = 0;
-	DECLARE_WAITQUEUE(waitq, current);
-
-	udev = (struct uinput_device *)file->private_data;
+	
+	if (!test_bit(UIST_CREATED, &(udev->state)))
+		return -ENODEV;
 
-	if (udev->head == udev->tail) {
-		add_wait_queue(&udev->waitq, &waitq);
-		current->state = TASK_INTERRUPTIBLE;
-
-		while (udev->head == udev->tail) {
-			if (!(udev->state & UIST_CREATED)) {
-				retval = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				retval = -ERESTARTSYS;
-				break;
-			}
-			schedule();
-		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(&udev->waitq, &waitq);
-	}
+	if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
 
+	retval = wait_event_interruptible(udev->waitq,
+			(udev->head != udev->tail) || 
+			!test_bit(UIST_CREATED, &(udev->state)));
+	
 	if (retval)
 		return retval;
 
-	while (udev->head != udev->tail && retval + sizeof(struct uinput_device) <= count) {
+	if (!test_bit(UIST_CREATED, &(udev->state)))
+		return -ENODEV;
+
+	while ((udev->head != udev->tail) && 
+	    (retval + sizeof(struct uinput_device) <= count)) {
 		if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
-		    sizeof(struct input_event)))
-			return -EFAULT;
-		udev->tail = (udev->tail + 1)%(UINPUT_BUFFER_SIZE - 1);
+		    sizeof(struct input_event))) return -EFAULT;
+		udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
 		retval += sizeof(struct input_event);
 	}
 
@@ -263,7 +273,7 @@
 
 static unsigned int uinput_poll(struct file *file, poll_table *wait)
 {
-        struct uinput_device *udev = file->private_data;
+	struct uinput_device *udev = file->private_data;
 
 	poll_wait(file, &udev->waitq, wait);
 
@@ -275,7 +285,7 @@
 
 static int uinput_burn_device(struct uinput_device *udev)
 {
-	if (udev->state & UIST_CREATED)
+	if (test_bit(UIST_CREATED, &(udev->state)))
 		uinput_destroy_device(udev);
 
 	kfree(udev->dev);
@@ -300,50 +310,52 @@
 
 	udev = (struct uinput_device *)file->private_data;
 
-	if (cmd >= UI_SET_EVBIT && (udev->state & UIST_CREATED))
+	/* device attributes can not be changed after the device is created */
+	if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
 		return -EINVAL;
 
 	switch (cmd) {
 		case UI_DEV_CREATE:
 			retval = uinput_create_device(udev);
-
 			break;
+			
 		case UI_DEV_DESTROY:
 			retval = uinput_destroy_device(udev);
-
 			break;
+
+
 		case UI_SET_EVBIT:
 			set_bit(arg, udev->dev->evbit);
-
-		break;
+			break;
+			
 		case UI_SET_KEYBIT:
 			set_bit(arg, udev->dev->keybit);
-
-		break;
+			break;
+			
 		case UI_SET_RELBIT:
 			set_bit(arg, udev->dev->relbit);
-
-		break;
+			break;
+			
 		case UI_SET_ABSBIT:
 			set_bit(arg, udev->dev->absbit);
-
-		break;
+			break;
+			
 		case UI_SET_MSCBIT:
 			set_bit(arg, udev->dev->mscbit);
-
-		break;
+			break;
+			
 		case UI_SET_LEDBIT:
 			set_bit(arg, udev->dev->ledbit);
-
-		break;
+			break;
+			
 		case UI_SET_SNDBIT:
 			set_bit(arg, udev->dev->sndbit);
-
-		break;
+			break;
+			
 		case UI_SET_FFBIT:
 			set_bit(arg, udev->dev->ffbit);
-
-		break;
+			break;
+			
 		default:
 			retval = -EFAULT;
 	}
diff -Nru a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
--- a/drivers/input/mouse/inport.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/input/mouse/inport.c	Fri Oct 11 21:22:58 2002
@@ -115,6 +115,12 @@
 	.close	= inport_close,
 	.name	= INPORT_NAME,
 	.phys	= "isa023c/input0",
+	.id = { 
+ 		.bustype = BUS_ISA,
+        	.vendor  = INPORT_VENDOR,
+        	.product = 0x0001,
+        	.version = 0x0100,
+	},
 };
 
 static void inport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -158,30 +164,27 @@
 {
 	unsigned char a,b,c;
 
-	if (check_region(INPORT_BASE, INPORT_EXTENT))
+	if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
+		printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
 		return -EBUSY;
+	}
 
 	a = inb(INPORT_SIGNATURE_PORT);
 	b = inb(INPORT_SIGNATURE_PORT);
 	c = inb(INPORT_SIGNATURE_PORT);
-	if (( a == b ) || ( a != c ))
+	if (( a == b ) || ( a != c )) {
+		release_region(INPORT_BASE, INPORT_EXTENT);
+		printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
 		return -ENODEV;
+	}
 
 	outb(INPORT_RESET, INPORT_CONTROL_PORT);
 	outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 	outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 
-	request_region(INPORT_BASE, INPORT_EXTENT, "inport");
-
 	input_register_device(&inport_dev);
-	inport_dev.id.bustype	=BUS_ISA;
-	inport_dev.id.vendor	=INPORT_VENDOR;
-	inport_dev.id.product	=0x0001;
-	inport_dev.id.version	=0x0100;
-
 
-	printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n",
-		INPORT_BASE, inport_irq);
+	printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", INPORT_BASE, inport_irq);
 
 	return 0;
 }
diff -Nru a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
--- a/drivers/input/mouse/logibm.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/input/mouse/logibm.c	Fri Oct 11 21:22:58 2002
@@ -105,6 +105,12 @@
 	.close	= logibm_close,
 	.name	= "Logitech bus mouse",
 	.phys	= "isa023c/input0",
+	.id	= {
+		.bustype = BUS_ISA,
+		.vendor  = 0x0003,
+		.product = 0x0001,
+		.version = 0x0100,
+	},
 };
 
 static void logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -165,11 +171,7 @@
 	outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
 
 	input_register_device(&logibm_dev);
-	logibm_dev.id.bustype	= BUS_ISA;
-	logibm_dev.id.vendor	= 0x0003;
-	logibm_dev.id.product	= 0x0001;
-	logibm_dev.id.version	= 0x0100;
-
+	
 	printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
 
 	return 0;
diff -Nru a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
--- a/drivers/input/mouse/psmouse.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/input/mouse/psmouse.c	Fri Oct 11 21:22:54 2002
@@ -20,8 +20,11 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("PS/2 mouse driver");
+MODULE_PARM(psmouse_noext, "1i");
 MODULE_LICENSE("GPL");
 
+static int psmouse_noext;
+
 #define PSMOUSE_CMD_SETSCALE11	0x00e6
 #define PSMOUSE_CMD_SETRES	0x10e8
 #define PSMOUSE_CMD_GETINFO	0x03e9
@@ -32,6 +35,7 @@
 #define PSMOUSE_CMD_SETRATE	0x10f3
 #define PSMOUSE_CMD_ENABLE	0x00f4
 #define PSMOUSE_CMD_RESET_DIS	0x00f6
+#define PSMOUSE_CMD_RESET_BAT	0x02ff
 
 #define PSMOUSE_RET_BAT		0xaa
 #define PSMOUSE_RET_ACK		0xfa
@@ -197,7 +201,7 @@
 	psmouse->packet[psmouse->pktcnt++] = data;
 
 	if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
-		if ((psmouse->packet[0] & 0x08) == 0x08) psmouse_process_packet(psmouse);
+		psmouse_process_packet(psmouse);
 		psmouse->pktcnt = 0;
 		return;
 	}
@@ -220,7 +224,11 @@
 	psmouse->ack = 0;
 	psmouse->acking = 1;
 
-	serio_write(psmouse->serio, byte);
+	if (serio_write(psmouse->serio, byte)) {
+		psmouse->acking = 0;
+		return -1;
+	}
+
 	while (!psmouse->ack && timeout--) udelay(10);
 
 	return -(psmouse->ack <= 0);
@@ -300,6 +308,9 @@
 	psmouse->name = "Mouse";
 	psmouse->model = 0;
 
+	if (psmouse_noext)
+		return PSMOUSE_PS2;
+
 /*
  * Try Genius NetMouse magic init.
  */
@@ -336,8 +347,8 @@
 	if (param[1]) {
 
 		int i;
-		static int logitech_4btn[] = { 12, 40, 41, 42, 43, 73, 80, -1 };
-		static int logitech_wheel[] = { 75, 76, 80, 81, 83, 88, -1 };
+		static int logitech_4btn[] = { 12, 40, 41, 42, 43, 52, 73, 80, -1 };
+		static int logitech_wheel[] = { 52, 75, 76, 80, 81, 83, 88, -1 };
 		static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
 							76, 80, 81, 83, 88, 96, 97, -1 };
 		psmouse->vendor = "Logitech";
@@ -527,15 +538,24 @@
  * Last, we enable the mouse so that we get reports from it.
  */
 
-	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) {
+	if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
 		printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
-	}
 
 }
 
 /*
- * psmouse_disconnect() cleans up after we don't want talk
- * to the mouse anymore.
+ * psmouse_cleanup() resets the mouse into power-on state.
+ */
+
+static void psmouse_cleanup(struct serio *serio)
+{
+	struct psmouse *psmouse = serio->private;
+	unsigned char param[2];
+	psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT);
+}
+
+/*
+ * psmouse_disconnect() closes and frees.
  */
 
 static void psmouse_disconnect(struct serio *serio)
@@ -563,6 +583,7 @@
 
 	memset(psmouse, 0, sizeof(struct psmouse));
 
+	init_input_dev(&psmouse->dev);
 	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
@@ -605,8 +626,18 @@
 static struct serio_dev psmouse_dev = {
 	.interrupt =	psmouse_interrupt,
 	.connect =	psmouse_connect,
-	.disconnect =	psmouse_disconnect
+	.disconnect =	psmouse_disconnect,
+	.cleanup =	psmouse_cleanup,
 };
+
+#ifndef MODULE
+static int __init psmouse_setup(char *str)
+{
+	psmouse_noext = 1;
+	return 1;
+}
+__setup("psmouse_noext", psmouse_setup);
+#endif
 
 int __init psmouse_init(void)
 {
diff -Nru a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
--- a/drivers/input/mouse/rpcmouse.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/input/mouse/rpcmouse.c	Fri Oct 11 21:22:57 2002
@@ -41,6 +41,12 @@
 	.relbit	= { BIT(REL_X) | BIT(REL_Y) },
 	.name	= "Acorn RiscPC Mouse",
 	.phys	= "rpcmouse/input0",
+	.id	= {
+		.bustype = BUS_HOST,
+		.vendor  = 0x0005,
+		.product = 0x0001,
+		.version = 0x0100,
+	},
 };
 
 static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
@@ -69,6 +75,8 @@
 
 static int __init rpcmouse_init(void)
 {
+	init_input_dev(&rpcmouse_dev);
+
 	rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
 	rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
 
@@ -78,10 +86,6 @@
 	}
 
 	input_register_device(&rpcmouse_dev);
-	rpcmouse.id.bustype	=BUS_HOST,
-	rpcmouse.id.vendor	=0x0005,
-	rpcmouse.id.product	=0x0001,
-	rpcmouse.id.version	=0x0100,
 
 	printk(KERN_INFO "input: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
 
diff -Nru a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
--- a/drivers/input/mouse/sermouse.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/input/mouse/sermouse.c	Fri Oct 11 21:22:54 2002
@@ -155,7 +155,7 @@
 
 				case SERIO_MZ:
 					input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
-					input_report_rel(dev, REL_WHEEL, (data & 7) - (data & 8));
+					input_report_rel(dev, REL_WHEEL,  (data & 8) - (data & 7));
 					break;
 			}
 					
@@ -204,7 +204,7 @@
 {
 	struct sermouse *sermouse = serio->private;
 
-	if (time_after(jiffies, sermouse->last + HZ/20)) sermouse->count = 0;
+	if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
 	sermouse->last = jiffies;
 
 	if (sermouse->type > SERIO_SUN)
@@ -247,6 +247,7 @@
 
 	memset(sermouse, 0, sizeof(struct sermouse));
 
+	init_input_dev(&sermouse->dev);
 	sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
 	sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/input/mousedev.c	Fri Oct 11 21:22:55 2002
@@ -1,29 +1,11 @@
 /*
- * $Id: mousedev.c,v 1.42 2002/04/09 20:51:26 jdeneux Exp $
+ * Input driver to ExplorerPS/2 device driver module.
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
+ * Copyright (c) 1999-2002 Vojtech Pavlik
  *
- *  Input driver to ExplorerPS/2 device driver module.
- */
-
-/*
  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * it under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #define MOUSEDEV_MINOR_BASE 	32
@@ -61,7 +43,7 @@
 	int minor;
 	char name[16];
 	wait_queue_head_t wait;
-	struct mousedev_list *list;
+	struct list_head list;
 	struct input_handle handle;
 	devfs_handle_t devfs;
 };
@@ -69,7 +51,7 @@
 struct mousedev_list {
 	struct fasync_struct *fasync;
 	struct mousedev *mousedev;
-	struct mousedev_list *next;
+	struct list_head node;
 	int dx, dy, dz, oldx, oldy;
 	signed char ps2[6];
 	unsigned long buttons;
@@ -98,9 +80,10 @@
 	int index, size, wake;
 
 	while (*mousedev) {
+
 		wake = 0;
-		list = (*mousedev)->list;
-		while (list) {
+
+		list_for_each_entry(list, &(*mousedev)->list, node)
 			switch (type) {
 				case EV_ABS:
 					if (test_bit(BTN_TRIGGER, handle->dev->keybit))
@@ -116,6 +99,7 @@
 								list->oldx += list->dx;
 							}
 							break;
+
 						case ABS_Y:
 							size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
 							if (size != 0) {
@@ -170,10 +154,10 @@
 							break;
 					}
 			}
-			list = list->next;
-		}
+
 		if (wake)
 			wake_up_interruptible(&((*mousedev)->wait));
+
 		mousedev++;
 	}
 }
@@ -189,21 +173,17 @@
 static int mousedev_release(struct inode * inode, struct file * file)
 {
 	struct mousedev_list *list = file->private_data;
-	struct mousedev_list **listptr;
+	struct input_handle *handle;
+	struct mousedev *mousedev;
 
-	listptr = &list->mousedev->list;
 	mousedev_fasync(-1, file, 0);
 
-	while (*listptr && (*listptr != list))
-		listptr = &((*listptr)->next);
-	*listptr = (*listptr)->next;
+	list_del(&list->node);
 
 	if (!--list->mousedev->open) {
 		if (list->mousedev->minor == MOUSEDEV_MIX) {
-			struct list_head * node;
-			list_for_each(node,&mousedev_handler.h_list) {
-				struct input_handle *handle = to_handle_h(node);
-				struct mousedev *mousedev = handle->private;
+			list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
+				mousedev = handle->private;
 				if (!mousedev->open) {
 					if (mousedev->exist) {
 						input_close_device(&mousedev->handle);
@@ -235,6 +215,8 @@
 static int mousedev_open(struct inode * inode, struct file * file)
 {
 	struct mousedev_list *list;
+	struct input_handle *handle;
+	struct mousedev *mousedev;
 	int i;
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
@@ -252,25 +234,19 @@
 	memset(list, 0, sizeof(struct mousedev_list));
 
 	list->mousedev = mousedev_table[i];
-	list->next = mousedev_table[i]->list;
-	mousedev_table[i]->list = list;
+	list_add_tail(&list->node, &mousedev_table[i]->list);
 	file->private_data = list;
 
 	if (!list->mousedev->open++) {
 		if (list->mousedev->minor == MOUSEDEV_MIX) {
-			struct list_head * node;
-			list_for_each(node,&mousedev_handler.h_list) {
-				struct input_handle *handle = to_handle_h(node);
-				struct mousedev *mousedev = handle->private;
-				if (!mousedev->open)
-					if (mousedev->exist)	
-						input_open_device(handle);
+			list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
+				mousedev = handle->private;
+				if (!mousedev->open && mousedev->exist)	
+					input_open_device(handle);
 			}
-		} else {
-			if (!mousedev_mix.open)
-				if (list->mousedev->exist)	
-					input_open_device(&list->mousedev->handle);
-		}
+		} else 
+			if (!mousedev_mix.open && list->mousedev->exist)	
+				input_open_device(&list->mousedev->handle);
 	}
 
 	return 0;
@@ -373,35 +349,13 @@
 
 static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
 {
-	DECLARE_WAITQUEUE(wait, current);
 	struct mousedev_list *list = file->private_data;
 	int retval = 0;
 
-	if (!list->ready && !list->buffer) {
-
-		add_wait_queue(&list->mousedev->wait, &wait);
+	if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
 
-		for (;;) {
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			retval = 0;
-			if (list->ready || list->buffer)
-				break;
-
-			retval = -EAGAIN;
-			if (file->f_flags & O_NONBLOCK)
-				break;
-
-			retval = -ERESTARTSYS;
-			if (signal_pending(current))
-				break;
-
-			schedule();
-		}
-
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&list->mousedev->wait, &wait);
-	}
+	retval = wait_event_interruptible(list->mousedev->wait, list->ready || list->buffer);
 
 	if (retval)
 		return retval;
@@ -454,23 +408,23 @@
 	if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
 		return NULL;
 	memset(mousedev, 0, sizeof(struct mousedev));
+
+	INIT_LIST_HEAD(&mousedev->list);
 	init_waitqueue_head(&mousedev->wait);
 
 	mousedev->minor = minor;
-	mousedev_table[minor] = mousedev;
-	sprintf(mousedev->name, "mouse%d", minor);
-
+	mousedev->exist = 1;
 	mousedev->handle.dev = dev;
 	mousedev->handle.name = mousedev->name;
 	mousedev->handle.handler = handler;
 	mousedev->handle.private = mousedev;
-
-	mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
+	sprintf(mousedev->name, "mouse%d", minor);
 
 	if (mousedev_mix.open)
 		input_open_device(&mousedev->handle);
 
-	mousedev->exist = 1;
+	mousedev_table[minor] = mousedev;
+	mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
 
 	return &mousedev->handle;
 }
@@ -539,6 +493,7 @@
 	input_register_handler(&mousedev_handler);
 
 	memset(&mousedev_mix, 0, sizeof(struct mousedev));
+	INIT_LIST_HEAD(&mousedev_mix.list);
 	init_waitqueue_head(&mousedev_mix.wait);
 	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
 	mousedev_mix.exist = 1;
diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
--- a/drivers/input/serio/i8042-io.h	Fri Oct 11 21:22:50 2002
+++ b/drivers/input/serio/i8042-io.h	Fri Oct 11 21:22:50 2002
@@ -13,6 +13,7 @@
 
 #define I8042_KBD_PHYS_DESC "isa0060/serio0"
 #define I8042_AUX_PHYS_DESC "isa0060/serio1"
+#define I8042_MUX_PHYS_DESC "isa0060/serio%d"
 
 /*
  * IRQs.
@@ -64,9 +65,13 @@
  */
 #if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__)
 	if (!request_region(I8042_DATA_REG, 16, "i8042"))
-		return 0;
+		return -1;
 #endif
-	return 1;
+
+#if !defined(__i386__) && !defined(__x86_64__)
+        i8042_reset = 1;
+#endif
+	return 0;
 }
 
 static inline void i8042_platform_exit(void)
diff -Nru a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
--- a/drivers/input/serio/i8042-ppcio.h	Fri Oct 11 21:22:54 2002
+++ b/drivers/input/serio/i8042-ppcio.h	Fri Oct 11 21:22:54 2002
@@ -14,6 +14,7 @@
 
 #define I8042_KBD_PHYS_DESC "walnutps2/serio0"
 #define I8042_AUX_PHYS_DESC "walnutps2/serio1"
+#define I8042_MUX_PHYS_DESC "walnutps2/serio%d"
 
 extern void *kb_cs;
 extern void *kb_data;
@@ -34,18 +35,17 @@
 static inline void i8042_write_data(int val)
 {
 	writeb(val, kb_data);
-	return;
 }
 
 static inline void i8042_write_command(int val)
 {
 	writeb(val, kb_cs);
-	return;
 }
 
 static inline int i8042_platform_init(void)
 {
-	return 1;
+	i8042_reset = 1;
+	return 0;
 }
 
 static inline void i8042_platform_exit(void)
@@ -59,6 +59,7 @@
 
 #define I8042_KBD_PHYS_DESC "spruceps2/serio0"
 #define I8042_AUX_PHYS_DESC "spruceps2/serio1"
+#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
 
 #define I8042_COMMAND_REG 0xff810000
 #define I8042_DATA_REG 0xff810001
@@ -109,18 +110,17 @@
 static inline void i8042_write_data(int val)
 {
 	*((unsigned char *)0xff810000) = (char)val;
-	return;
 }
 
 static inline void i8042_write_command(int val)
 {
 	*((unsigned char *)0xff810001) = (char)val;
-	return;
 }
 
 static inline int i8042_platform_init(void)
 {
-	return 1;
+	i8042_reset = 1;
+	return 0;
 }
 
 static inline void i8042_platform_exit(void)
diff -Nru a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
--- a/drivers/input/serio/i8042-sparcio.h	Fri Oct 11 21:23:05 2002
+++ b/drivers/input/serio/i8042-sparcio.h	Fri Oct 11 21:23:05 2002
@@ -11,6 +11,7 @@
 
 #define I8042_KBD_PHYS_DESC "sparcps2/serio0"
 #define I8042_AUX_PHYS_DESC "sparcps2/serio1"
+#define I8042_MUX_PHYS_DESC "sparcps2/serio%d"
 
 static unsigned long kbd_iobase;
 
@@ -50,14 +51,14 @@
 	len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
 	if (len < 0) {
 		printk("i8042: Cannot get name property of root OBP node.\n");
-		return 0;
+		return -1;
 	}
 	if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
 		/* Hardcoded values for MrCoffee.  */
 		i8042_kbd_irq = i8042_aux_irq = 13 | 0x20;
 		kbd_iobase = (unsigned long) ioremap(0x71300060, 8);
 		if (!kbd_iobase)
-			return 0;
+			return -1;
 	} else {
 		struct linux_ebus *ebus;
 		struct linux_ebus_device *edev;
@@ -69,7 +70,7 @@
 					goto edev_found;
 			}
 		}
-		return 0;
+		return -1;
 
 	edev_found:
 		for_each_edevchild(edev, child) {
@@ -87,11 +88,13 @@
 		    i8042_aux_irq == -1) {
 			printk("i8042: Error, 8042 device lacks both kbd and "
 			       "mouse nodes.\n");
-			return 0;
+			return -1;
 		}
 	}
 
-	return 1;
+	i8042_reset = 1;
+
+	return 0;
 }
 
 static inline void i8042_platform_exit(void)
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/input/serio/i8042.c	Fri Oct 11 21:22:53 2002
@@ -19,25 +19,28 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/serio.h>
-#include <linux/sched.h>	/* request/free_irq */
-
-#include "i8042.h"
+#include <linux/sched.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(i8042_noaux, "1i");
+MODULE_PARM(i8042_nomux, "1i");
 MODULE_PARM(i8042_unlock, "1i");
 MODULE_PARM(i8042_reset, "1i");
 MODULE_PARM(i8042_direct, "1i");
-MODULE_PARM(i8042_restore_ctr, "1i");
+MODULE_PARM(i8042_dumbkbd, "1i");
 
+static int i8042_reset;
 static int i8042_noaux;
+static int i8042_nomux;
 static int i8042_unlock;
-static int i8042_reset;
 static int i8042_direct;
-static int i8042_restore_ctr;
+static int i8042_dumbkbd;
+
+#undef DEBUG
+#include "i8042.h"
 
 spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED;
 
@@ -46,6 +49,7 @@
 	unsigned char disable;
 	unsigned char irqen;
 	unsigned char exists;
+	signed char mux;
 	unsigned char *name;
 	unsigned char *phys;
 };
@@ -55,15 +59,12 @@
 static unsigned char i8042_initial_ctr;
 static unsigned char i8042_ctr;
 static unsigned char i8042_last_e0;
+static unsigned char i8042_mux_open;
 struct timer_list i8042_timer;
 
-#ifdef I8042_DEBUG_IO
-static unsigned long i8042_start;
-#endif
-
 extern struct pt_regs *kbd_pt_regs;
 
-static unsigned long i8042_unxlate_seen[128 / BITS_PER_LONG];
+static unsigned long i8042_unxlate_seen[256 / BITS_PER_LONG];
 static unsigned char i8042_unxlate_table[128] = {
 	  0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
 	 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
@@ -110,18 +111,16 @@
 static int i8042_flush(void)
 {
 	unsigned long flags;
+	unsigned char data;
 	int i = 0;
 
 	spin_lock_irqsave(&i8042_lock, flags);
 
-	while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE))
-#ifdef I8042_DEBUG_IO
-		printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush, %s) [%d]\n",
-			i8042_read_data(), i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd",
-			(int) (jiffies - i8042_start));
-#else
-		i8042_read_data();
-#endif
+	while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) {
+		data = i8042_read_data();
+		dbg("%02x <- i8042 (flush, %s)", data,
+			i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd");
+	}
 
 	spin_unlock_irqrestore(&i8042_lock, flags);
 
@@ -145,20 +144,14 @@
 
 	retval = i8042_wait_write();
 	if (!retval) {
-#ifdef I8042_DEBUG_IO
-		printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n",
-			command & 0xff, (int) (jiffies - i8042_start));
-#endif
+		dbg("%02x -> i8042 (command)", command & 0xff);
 		i8042_write_command(command & 0xff);
 	}
 	
 	if (!retval)
 		for (i = 0; i < ((command >> 12) & 0xf); i++) {
 			if ((retval = i8042_wait_write())) break;
-#ifdef I8042_DEBUG_IO
-			printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n",
-				param[i], (int) (jiffies - i8042_start));
-#endif
+			dbg("%02x -> i8042 (parameter)", param[i]);
 			i8042_write_data(param[i]);
 		}
 
@@ -169,19 +162,13 @@
 				param[i] = ~i8042_read_data();
 			else
 				param[i] = i8042_read_data();
-#ifdef I8042_DEBUG_IO
-			printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n",
-				param[i], (int) (jiffies - i8042_start));
-#endif
+			dbg("%02x <- i8042 (return)", param[i]);
 		}
 
 	spin_unlock_irqrestore(&i8042_lock, flags);
 
-#ifdef I8042_DEBUG_IO
 	if (retval)
-		printk(KERN_DEBUG "i8042.c:      -- i8042 (timeout) [%d]\n",
-			(int) (jiffies - i8042_start));
-#endif
+		dbg("     -- i8042 (timeout)");
 
 	return retval;
 }
@@ -198,10 +185,7 @@
 	spin_lock_irqsave(&i8042_lock, flags);
 
 	if(!(retval = i8042_wait_write())) {
-#ifdef I8042_DEBUG_IO
-		printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n",
-			c, (int) (jiffies - i8042_start));
-#endif
+		dbg("%02x -> i8042 (kbd-data)", c);
 		i8042_write_data(c);
 	}
 
@@ -216,21 +200,17 @@
 
 static int i8042_aux_write(struct serio *port, unsigned char c)
 {
+	struct i8042_values *values = port->driver;
 	int retval;
 
 /*
  * Send the byte out.
  */
 
-	retval  = i8042_command(&c, I8042_CMD_AUX_SEND);
-
-/*
- * Here we restore the CTR value if requested. I don't know why, but i8042's in
- * half-AT mode tend to trash their CTR when doing the AUX_SEND command. 
- */
-
-	if (i8042_restore_ctr)
-		retval |= i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR);
+	if (values->mux == -1)
+		retval = i8042_command(&c, I8042_CMD_AUX_SEND);
+	else
+		retval = i8042_command(&c, I8042_CMD_MUX_SEND + values->mux);
 
 /*
  * Make sure the interrupt happens and the character is received even
@@ -253,6 +233,10 @@
 
 	i8042_flush();
 
+	if (values->mux != -1)
+		if (i8042_mux_open++)
+			return 0;
+
 	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) {
 		printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
 		values->exists = 0;
@@ -282,6 +266,10 @@
 {
 	struct i8042_values *values = port->driver;
 
+	if (values->mux != -1)
+		if (--i8042_mux_open)
+			return;
+
 	i8042_ctr &= ~values->irqen;
 
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
@@ -299,11 +287,10 @@
  */
 
 static struct i8042_values i8042_kbd_values = {
-	.irq =		0,
 	.irqen =	I8042_CTR_KBDINT,
 	.disable =	I8042_CTR_KBDDIS,
 	.name =		"KBD",
-	.exists =	0,
+	.mux =		-1,
 };
 
 static struct serio i8042_kbd_port =
@@ -318,11 +305,10 @@
 };
 
 static struct i8042_values i8042_aux_values = {
-	.irq =		0,
 	.irqen =	I8042_CTR_AUXINT,
 	.disable =	I8042_CTR_AUXDIS,
 	.name =		"AUX",
-	.exists =	0,
+	.mux =		-1,
 };
 
 static struct serio i8042_aux_port =
@@ -336,6 +322,12 @@
 	.phys =		I8042_AUX_PHYS_DESC,
 };
 
+static struct i8042_values i8042_mux_values[4];
+static struct serio i8042_mux_port[4];
+static char i8042_mux_names[4][32];
+static char i8042_mux_short[4][16];
+static char i8042_mux_phys[4][32];
+
 /*
  * i8042_interrupt() is the most important function in this driver -
  * it handles the interrupts from the i8042, and sends incoming bytes
@@ -373,34 +365,60 @@
 		dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
 		      ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
 
-#ifdef I8042_DEBUG_IO
-		printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt, %s, %d%s%s) [%d]\n",
+		if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) {
+
+			if (str & I8042_STR_MUXERR) {
+				switch (data) {
+					case 0xfd:
+					case 0xfe: dfl = SERIO_TIMEOUT; break;
+					case 0xff: dfl = SERIO_PARITY; break;
+				}
+				data = 0xfe;
+			} else dfl = 0;
+
+			dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
+				data, (str >> 6), irq, 
+				dfl & SERIO_PARITY ? ", bad parity" : "",
+				dfl & SERIO_TIMEOUT ? ", timeout" : "");
+
+			serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl);
+			continue;
+		}
+
+		dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
 			data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, 
 			dfl & SERIO_PARITY ? ", bad parity" : "",
-			dfl & SERIO_TIMEOUT ? ", timeout" : "",
-			(int) (jiffies - i8042_start));
-#endif
+			dfl & SERIO_TIMEOUT ? ", timeout" : "");
 
-		if (i8042_aux_values.exists && (buffer[i].str & I8042_STR_AUXDATA)) {
-			serio_interrupt(&i8042_aux_port, buffer[i].data, dfl);
-		} else 
-			if (i8042_kbd_values.exists) {
-				if (!i8042_direct) {
-					if (data > 0x7f) {
-						if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) {
-							serio_interrupt(&i8042_kbd_port, 0xf0, dfl);
-							if (i8042_last_e0 && (data == 0xaa || data == 0xb6))
-								set_bit(data & 0x7f, i8042_unxlate_seen);
-							data = i8042_unxlate_table[data & 0x7f];
-						}
-					} else {
-						set_bit(data, i8042_unxlate_seen);
-						data = i8042_unxlate_table[data];
-					}
-					i8042_last_e0 = (data == 0xe0);
-				}
-				serio_interrupt(&i8042_kbd_port, data, dfl);
+		if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
+			serio_interrupt(&i8042_aux_port, data, dfl);
+			continue;
+		}
+
+		if (!i8042_kbd_values.exists)
+			continue;
+
+		if (i8042_direct) {
+			serio_interrupt(&i8042_kbd_port, data, dfl);
+			continue;
+		}
+
+		if (data > 0x7f) {
+			unsigned char index = (data & 0x7f) | (i8042_last_e0 << 7);
+			if (index == 0xaa || index == 0xb6)
+				set_bit(index, i8042_unxlate_seen);
+			if (test_and_clear_bit(index, i8042_unxlate_seen)) {
+				serio_interrupt(&i8042_kbd_port, 0xf0, dfl);
+				data = i8042_unxlate_table[data & 0x7f];
 			}
+		} else {
+			set_bit(data | (i8042_last_e0 << 7), i8042_unxlate_seen);
+			data = i8042_unxlate_table[data];
+		}
+
+		i8042_last_e0 = (data == 0xe0);
+
+		serio_interrupt(&i8042_kbd_port, data, dfl);
 	}
 
 }
@@ -460,17 +478,15 @@
  */
 
 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
-
-		if (i8042_unlock) {
+		if (i8042_unlock)
 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
-		} else {
+		 else
 			printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
-		}
 	}
 
 /*
  * If the chip is configured into nontranslated mode by the BIOS, don't
- * bother enabling translating and just use that happily.
+ * bother enabling translating and be happy.
  */
 
 	if (~i8042_ctr & I8042_CTR_XLATE)
@@ -478,10 +494,9 @@
 
 /*
  * Set nontranslated mode for the kbd interface if requested by an option.
- * This is vital for a working scancode set 3 support. After this the kbd
- * interface becomes a simple serial in/out, like the aux interface is. If
- * the user doesn't wish this, the driver tries to untranslate the values
- * after the i8042 translates them.
+ * After this the kbd interface becomes a simple serial in/out, like the aux
+ * interface is. We don't do this by default, since it can confuse notebook
+ * BIOSes.
  */
 
 	if (i8042_direct)
@@ -506,10 +521,25 @@
 
 void i8042_controller_cleanup(void)
 {
+	int i;
 
 	i8042_flush();
 
 /*
+ * Reset anything that is connected to the ports.
+ */
+
+	if (i8042_kbd_values.exists)
+		serio_cleanup(&i8042_kbd_port);
+
+	if (i8042_aux_values.exists)
+		serio_cleanup(&i8042_aux_port);
+
+	for (i = 0; i < 4; i++)
+		if (i8042_mux_values[i].exists)
+			serio_cleanup(i8042_mux_port + i);
+
+/*
  * Reset the controller.
  */
 
@@ -529,16 +559,78 @@
 	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
 		printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
 
+}
+
 /*
- * Reset anything that is connected to the ports if the ports
- * are enabled in the original config.
+ * i8042_check_mux() checks whether the controller supports the PS/2 Active
+ * Multiplexing specification by Synaptics, Phoenix, Insyde and
+ * LCS/Telegraphics.
  */
 
-	if (i8042_kbd_values.exists)
-		i8042_kbd_write(&i8042_kbd_port, 0xff);
+static int __init i8042_check_mux(struct i8042_values *values)
+{
+	unsigned char param;
+	int i;
 
-	if (i8042_aux_values.exists)
-		i8042_aux_write(&i8042_aux_port, 0xff);
+/*
+ * Check if AUX irq is available.
+ */
+
+	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL))
+                return -1;
+	free_irq(values->irq, NULL);
+
+/*
+ * Get rid of bytes in the queue.
+ */
+
+	i8042_flush();
+
+/*
+ * Internal loopback test - send three bytes, they should come back from the
+ * mouse interface, the last should be version. Note that we negate mouseport
+ * command responses for the i8042_check_aux() routine.
+ */
+
+	param = 0xf0;
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x0f)
+		return -1;
+	param = 0x56;
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
+		return -1;
+	param = 0xa4;
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
+		return -1;
+
+	printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
+		(~param >> 4) & 0xf, ~param & 0xf);
+
+/*
+ * In MUX mode the keyboard translation seems to be always off.
+ */
+ 
+	i8042_direct = 1;
+
+/*
+ * Disable all muxed ports by disabling AUX.
+ */
+
+	i8042_ctr &= I8042_CTR_AUXDIS;
+	i8042_ctr &= ~I8042_CTR_AUXINT;
+
+	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+		return -1;
+
+/*
+ * Enable all muxed ports.
+ */
+
+	for (i = 0; i < 4; i++) {
+		i8042_command(&param, I8042_CMD_MUX_PFX + i);
+		i8042_command(&param, I8042_CMD_AUX_ENABLE);
+	}
+
+	return 0;
 }
 
 /*
@@ -546,7 +638,7 @@
  * the presence of an AUX interface.
  */
 
-static int __init i8042_check_aux(struct i8042_values *values, struct serio *port)
+static int __init i8042_check_aux(struct i8042_values *values)
 {
 	unsigned char param;
 
@@ -566,23 +658,26 @@
 	i8042_flush();
 
 /*
- * Internal loopback test - filters out AT-type i8042's
+ * Internal loopback test - filters out AT-type i8042's. Unfortunately
+ * SiS screwed up and their 5597 doesn't support the LOOP command even
+ * though it has an AUX port.
  */
 
 	param = 0x5a;
-
-	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa5)
-		return -1;
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa5) {
 
 /*
  * External connection test - filters out AT-soldered PS/2 i8042's
  * 0x00 - no error, 0x01-0x03 - clock/data stuck, 0xff - general error
- * We ignore general error, since some chips report it even under normal
- * operation.
+ * 0xfa - no error on some notebooks which ignore the spec
+ * Because it's common for chipsets to return error on perfectly functioning
+ * AUX ports, we test for this only when the LOOP command failed.
  */
 
-	if (i8042_command(&param, I8042_CMD_AUX_TEST) || (param && param != 0xff))
-		return -1;
+		if (i8042_command(&param, I8042_CMD_AUX_TEST)
+		    	|| (param && param != 0xfa && param != 0xff))
+				return -1;
+	}
 
 /*
  * Bit assignment test - filters out PS/2 i8042's in AT mode
@@ -653,6 +748,12 @@
 static int __init i8042_setup_noaux(char *str)
 {
 	i8042_noaux = 1;
+	i8042_nomux = 1;
+	return 1;
+}
+static int __init i8042_setup_nomux(char *str)
+{
+	i8042_nomux = 1;
 	return 1;
 }
 static int __init i8042_setup_unlock(char *str)
@@ -665,17 +766,18 @@
 	i8042_direct = 1;
 	return 1;
 }
-static int __init i8042_setup_restore_ctr(char *str)
+static int __init i8042_setup_dumbkbd(char *str)
 {
-	i8042_restore_ctr = 1;
+	i8042_dumbkbd = 1;
 	return 1;
 }
 
 __setup("i8042_reset", i8042_setup_reset);
 __setup("i8042_noaux", i8042_setup_noaux);
+__setup("i8042_nomux", i8042_setup_nomux);
 __setup("i8042_unlock", i8042_setup_unlock);
 __setup("i8042_direct", i8042_setup_direct);
-__setup("i8042_restore_ctr", i8042_setup_restore_ctr);
+__setup("i8042_dumbkbd", i8042_setup_dumbkbd);
 #endif
 
 /*
@@ -698,27 +800,47 @@
         0
 };
 
+static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index)
+{
+	memcpy(port, &i8042_aux_port, sizeof(struct serio));
+	memcpy(values, &i8042_aux_values, sizeof(struct i8042_values));
+	sprintf(i8042_mux_names[index], "i8042 Aux-%d Port", index);
+	sprintf(i8042_mux_phys[index], I8042_MUX_PHYS_DESC, index + 1);
+	sprintf(i8042_mux_short[index], "AUX%d", index);
+	port->name = i8042_mux_names[index];
+	port->phys = i8042_mux_phys[index];
+	port->driver = values;
+	values->name = i8042_mux_short[index];
+	values->mux = index;
+}
+
 int __init i8042_init(void)
 {
-#ifdef I8042_DEBUG_IO
-	i8042_start = jiffies;
-#endif
+	int i;
 
-#if !defined(__i386__) && !defined(__x86_64__)
-	i8042_reset = 1;
-#endif
+	dbg_init();
 
-	if (!i8042_platform_init())
+	if (i8042_platform_init())
 		return -EBUSY;
 
-	i8042_kbd_values.irq = I8042_KBD_IRQ;
 	i8042_aux_values.irq = I8042_AUX_IRQ;
+	i8042_kbd_values.irq = I8042_KBD_IRQ;
 
 	if (i8042_controller_init())
 		return -ENODEV;
-		
-	if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port))
-		i8042_port_register(&i8042_aux_values, &i8042_aux_port);
+
+	if (i8042_dumbkbd)
+		i8042_kbd_port.write = NULL;
+
+	for (i = 0; i < 4; i++)
+		i8042_init_mux_values(i8042_mux_values + i, i8042_mux_port + i, i);
+
+	if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values))
+		for (i = 0; i < 4; i++)
+			i8042_port_register(i8042_mux_values + i, i8042_mux_port + i);
+	else 
+		if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values))
+			i8042_port_register(&i8042_aux_values, &i8042_aux_port);
 
 	i8042_port_register(&i8042_kbd_values, &i8042_kbd_port);
 
@@ -732,22 +854,26 @@
 
 void __exit i8042_exit(void)
 {
+	int i;
+
 	unregister_reboot_notifier(&i8042_notifier);
 
 	del_timer(&i8042_timer);
+
+	i8042_controller_cleanup();
 	
 	if (i8042_kbd_values.exists)
 		serio_unregister_port(&i8042_kbd_port);
 
 	if (i8042_aux_values.exists)
 		serio_unregister_port(&i8042_aux_port);
-
-	i8042_controller_cleanup();
+	
+	for (i = 0; i < 4; i++)
+		if (i8042_mux_values[i].exists)
+			serio_unregister_port(i8042_mux_port + i);
 
 	i8042_platform_exit();
 }
 
 module_init(i8042_init);
 module_exit(i8042_exit);
-
-
diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
--- a/drivers/input/serio/i8042.h	Fri Oct 11 21:23:02 2002
+++ b/drivers/input/serio/i8042.h	Fri Oct 11 21:23:02 2002
@@ -22,13 +22,6 @@
 #endif
 
 /*
- * If you want to trace all the i/o the i8042 module does for
- * debugging purposes, define this.
- */
-
-#undef I8042_DEBUG_IO
-
-/*
  * This is in 50us units, the time we wait for the i8042 to react. This
  * has to be long enough for the i8042 itself to timeout on sending a byte
  * to a non-existent mouse.
@@ -54,6 +47,7 @@
 #define I8042_STR_AUXDATA	0x20
 #define I8042_STR_KEYLOCK	0x10
 #define I8042_STR_CMDDAT	0x08
+#define I8042_STR_MUXERR	0x04
 #define I8042_STR_IBF		0x02
 #define	I8042_STR_OBF		0x01
 
@@ -87,6 +81,9 @@
 #define I8042_CMD_AUX_SEND	0x10d4
 #define I8042_CMD_AUX_LOOP	0x11d3
 
+#define I8042_CMD_MUX_PFX	0x0090
+#define I8042_CMD_MUX_SEND	0x1090
+
 /*
  * Return codes.
  */
@@ -99,5 +96,19 @@
  */
 
 #define I8042_BUFFER_SIZE	32
+
+/*
+ * Debug.
+ */
+
+#ifdef DEBUG
+static unsigned long i8042_start;
+#define dbg_init() do { i8042_start = jiffies; } while (0);
+#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" ,\
+	 ## arg, (int) (jiffies - i8042_start))
+#else
+#define dbg_init() do { } while (0);
+#define dbg(format, arg...) do {} while (0)
+#endif
 
 #endif /* _I8042_H */
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/input/serio/serio.c	Fri Oct 11 21:22:51 2002
@@ -37,6 +37,7 @@
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/suspend.h>
+#include <linux/slab.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Serio abstraction core");
@@ -51,19 +52,27 @@
 EXPORT_SYMBOL(serio_close);
 EXPORT_SYMBOL(serio_rescan);
 
-static struct serio *serio_list;
-static struct serio_dev *serio_dev;
+struct serio_event {
+	int type;
+	struct serio *serio;
+	struct list_head node;
+};
+
+static LIST_HEAD(serio_list);
+static LIST_HEAD(serio_dev_list);
+static LIST_HEAD(serio_event_list);
 static int serio_pid;
 
 static void serio_find_dev(struct serio *serio)
 {
-        struct serio_dev *dev = serio_dev;
+	struct serio_dev *dev;
 
-        while (dev && !serio->dev) {
+	list_for_each_entry(dev, &serio_dev_list, node) {
+		if (serio->dev)
+			break;
 		if (dev->connect)
-                	dev->connect(serio, dev);
-                dev = dev->next;
-        }
+			dev->connect(serio, dev);
+	}
 }
 
 #define SERIO_RESCAN	1
@@ -73,17 +82,23 @@
 
 void serio_handle_events(void)
 {
-	struct serio *serio = serio_list;
+	struct list_head *node, *next;
+	struct serio_event *event;
 
-	while (serio) {
-		if (serio->event & SERIO_RESCAN) {
-			if (serio->dev && serio->dev->disconnect)
-				serio->dev->disconnect(serio);
-			serio_find_dev(serio);
-		}
+	list_for_each_safe(node, next, &serio_event_list) {
+		event = container_of(node, struct serio_event, node);	
 
-		serio->event = 0;
-		serio = serio->next;
+		switch (event->type) {
+			case SERIO_RESCAN :
+				if (event->serio->dev && event->serio->dev->disconnect)
+					event->serio->dev->disconnect(event->serio);
+				serio_find_dev(event->serio);
+				break;
+			default:
+				break;
+		}
+		list_del_init(node);
+		kfree(event);
 	}
 }
 
@@ -95,7 +110,7 @@
 
 	do {
 		serio_handle_events();
-		interruptible_sleep_on(&serio_wait); 
+		wait_event_interruptible(serio_wait, !list_empty(&serio_event_list)); 
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_IOTHREAD);
 	} while (!signal_pending(current));
@@ -108,7 +123,15 @@
 
 void serio_rescan(struct serio *serio)
 {
-	serio->event |= SERIO_RESCAN;
+	struct serio_event *event;
+
+	if (!(event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC)))
+		return;
+
+	event->type = SERIO_RESCAN;
+	event->serio = serio;
+
+	list_add_tail(&event->node, &serio_event_list);
 	wake_up(&serio_wait);
 }
 
@@ -122,49 +145,36 @@
 
 void serio_register_port(struct serio *serio)
 {
-	serio->next = serio_list;	
-	serio_list = serio;
+	list_add_tail(&serio->node, &serio_list);
 	serio_find_dev(serio);
 }
 
 void serio_unregister_port(struct serio *serio)
 {
-        struct serio **serioptr = &serio_list;
-
-        while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next);
-        *serioptr = (*serioptr)->next;
-
+	list_del_init(&serio->node);
 	if (serio->dev && serio->dev->disconnect)
 		serio->dev->disconnect(serio);
 }
 
 void serio_register_device(struct serio_dev *dev)
 {
-	struct serio *serio = serio_list;
-
-	dev->next = serio_dev;	
-	serio_dev = dev;
-
-	while (serio) {
+	struct serio *serio;
+	list_add_tail(&dev->node, &serio_dev_list);
+	list_for_each_entry(serio, &serio_list, node)
 		if (!serio->dev && dev->connect)
 			dev->connect(serio, dev);
-		serio = serio->next;
-	}
 }
 
 void serio_unregister_device(struct serio_dev *dev)
 {
-        struct serio_dev **devptr = &serio_dev;
-	struct serio *serio = serio_list;
+	struct serio *serio;
 
-        while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
-        *devptr = (*devptr)->next;
+	list_del_init(&dev->node);
 
-	while (serio) {
+	list_for_each_entry(serio, &serio_list, node) {
 		if (serio->dev == dev && dev->disconnect)
 			dev->disconnect(serio);
 		serio_find_dev(serio);
-		serio = serio->next;
 	}
 }
 
diff -Nru a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
--- a/drivers/input/touchscreen/gunze.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/input/touchscreen/gunze.c	Fri Oct 11 21:22:55 2002
@@ -120,6 +120,7 @@
 
 	memset(gunze, 0, sizeof(struct gunze));
 
+	init_input_dev(&gunze->dev);
 	gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
 	gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
 	gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff -Nru a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
--- a/drivers/input/touchscreen/h3600_ts_input.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/input/touchscreen/h3600_ts_input.c	Fri Oct 11 21:23:03 2002
@@ -371,6 +371,8 @@
 
 	memset(ts, 0, sizeof(struct h3600_dev));
 
+	init_input_dev(&ts->dev);
+
 	/* Device specific stuff */
         set_GPIO_IRQ_edge( GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES );
         set_GPIO_IRQ_edge( GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE );
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/input/tsdev.c	Fri Oct 11 21:22:56 2002
@@ -55,7 +55,7 @@
 	int minor;
 	char name[16];
 	wait_queue_head_t wait;
-	struct tsdev_list *list;
+	struct list_head list;
 	struct input_handle handle;
 	devfs_handle_t devfs;
 };
@@ -70,7 +70,7 @@
 
 struct tsdev_list {
 	struct fasync_struct *fasync;
-	struct tsdev_list *next;
+	struct list_head node;
 	struct tsdev *tsdev;
 	int head, tail;
 	int oldx, oldy, pendown;
@@ -106,8 +106,7 @@
 	memset(list, 0, sizeof(struct tsdev_list));
 
 	list->tsdev = tsdev_table[i];
-	list->next = tsdev_table[i]->list;
-	tsdev_table[i]->list = list;
+	list_add_tail(&list->node, &tsdev_table[i]->list);
 	file->private_data = list;
 
 	if (!list->tsdev->open++)
@@ -119,14 +118,9 @@
 static int tsdev_release(struct inode *inode, struct file *file)
 {
 	struct tsdev_list *list = file->private_data;
-	struct tsdev_list **listptr;
 
-	listptr = &list->tsdev->list;
 	tsdev_fasync(-1, file, 0);
-
-	while (*listptr && (*listptr != list))
-		listptr = &((*listptr)->next);
-	*listptr = (*listptr)->next;
+	list_del(&list->node);
 
 	if (!--list->tsdev->open) {
 		if (list->tsdev->exist) {
@@ -144,45 +138,28 @@
 static ssize_t tsdev_read(struct file *file, char *buffer, size_t count,
 			  loff_t * ppos)
 {
-	DECLARE_WAITQUEUE(wait, current);
 	struct tsdev_list *list = file->private_data;
 	int retval = 0;
 
-	if (list->head == list->tail) {
-		add_wait_queue(&list->tsdev->wait, &wait);
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		while (list->head == list->tail) {
-			if (!list->tsdev->exist) {
-				retval = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				retval = -ERESTARTSYS;
-				break;
-			}
-			schedule();
-		}
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&list->tsdev->wait, &wait);
-	}
+	if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	retval = wait_event_interruptible(list->tsdev->wait,
+		(list->head != list->tail) && list->tsdev->exist);
 
 	if (retval)
 		return retval;
 
-	while (list->head != list->tail
-	       && retval + sizeof(TS_EVENT) <= count) {
-		if (copy_to_user
-		    (buffer + retval, list->event + list->tail,
-		     sizeof(TS_EVENT)))
+	if (!list->tsdev->exist)
+		return -ENODEV;
+
+	while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) {
+		if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT)))
 			return -EFAULT;
 		list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
 		retval += sizeof(TS_EVENT);
 	}
+
 	return retval;
 }
 
@@ -232,54 +209,35 @@
 			unsigned int code, int value)
 {
 	struct tsdev *tsdev = handle->private;
-	struct tsdev_list *list = tsdev->list;
+	struct tsdev_list *list;
 	struct timeval time;
 	int size;
 
-	while (list) {
+	list_for_each_entry(list, &tsdev->list, node) {
 		switch (type) {
 		case EV_ABS:
 			switch (code) {
 			case ABS_X:
 				if (!list->pendown)
 					return;
-
-				size =
-				    handle->dev->absmax[ABS_X] -
-				    handle->dev->absmin[ABS_X];
+				size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
 				if (size > 0)
-					list->oldx =
-					    ((value -
-					      handle->dev->absmin[ABS_X]) *
-					     xres / size);
+					list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size);
 				else
-					list->oldx =
-					    ((value -
-					      handle->dev->absmin[ABS_X]));
+					list->oldx = ((value - handle->dev->absmin[ABS_X]));
 				break;
 			case ABS_Y:
 				if (!list->pendown)
 					return;
-
-				size =
-				    handle->dev->absmax[ABS_Y] -
-				    handle->dev->absmin[ABS_Y];
+				size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
 				if (size > 0)
-					list->oldy =
-					    ((value -
-					      handle->dev->absmin[ABS_Y]) *
-					     yres / size);
+					list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size);
 				else
-					list->oldy =
-					    ((value -
-					      handle->dev->absmin[ABS_Y]));
+					list->oldy = ((value - handle->dev->absmin[ABS_Y]));
 				break;
 			case ABS_PRESSURE:
-				list->pendown =
-				    ((value >
-				      handle->dev->
-				      absmin[ABS_PRESSURE])) ? value -
-				    handle->dev->absmin[ABS_PRESSURE] : 0;
+				list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ?
+				    value - handle->dev->absmin[ABS_PRESSURE] : 0;
 				break;
 			}
 			break;
@@ -289,7 +247,6 @@
 			case REL_X:
 				if (!list->pendown)
 					return;
-
 				list->oldx += value;
 				if (list->oldx < 0)
 					list->oldx = 0;
@@ -299,7 +256,6 @@
 			case REL_Y:
 				if (!list->pendown)
 					return;
-
 				list->oldy += value;
 				if (list->oldy < 0)
 					list->oldy = 0;
@@ -333,7 +289,6 @@
 		list->event[list->head].y = list->oldy;
 		list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
-		list = list->next;
 	}
 	wake_up_interruptible(&tsdev->wait);
 }
@@ -356,21 +311,23 @@
 	if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL)))
 		return NULL;
 	memset(tsdev, 0, sizeof(struct tsdev));
+
+	INIT_LIST_HEAD(&tsdev->list);
 	init_waitqueue_head(&tsdev->wait);
 
-	tsdev->minor = minor;
-	tsdev_table[minor] = tsdev;
 	sprintf(tsdev->name, "ts%d", minor);
 
+	tsdev->exist = 1;
+	tsdev->minor = minor;
 	tsdev->handle.dev = dev;
 	tsdev->handle.name = tsdev->name;
 	tsdev->handle.handler = handler;
 	tsdev->handle.private = tsdev;
 
+	tsdev_table[minor] = tsdev;
 	tsdev->devfs =
 	    input_register_minor("ts%d", minor, TSDEV_MINOR_BASE);
 
-	tsdev->exist = 1;
 
 	return &tsdev->handle;
 }
diff -Nru a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
--- a/drivers/isdn/capi/capifs.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/isdn/capi/capifs.c	Fri Oct 11 21:22:54 2002
@@ -61,7 +61,7 @@
 
 static inline struct capifs_sb_info *SBI(struct super_block *sb)
 {
-	return (struct capifs_sb_info *)(sb->u.generic_sbp);
+	return (struct capifs_sb_info *)(sb->s_fs_info);
 }
 
 /* ------------------------------------------------------------------ */
@@ -310,7 +310,7 @@
 	}
 	memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci);
 
-	s->u.generic_sbp = (void *) sbi;
+	s->s_fs_info = (void *) sbi;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = CAPIFS_SUPER_MAGIC;
diff -Nru a/drivers/isdn/eicon/Divas_mod.c b/drivers/isdn/eicon/Divas_mod.c
--- a/drivers/isdn/eicon/Divas_mod.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/isdn/eicon/Divas_mod.c	Fri Oct 11 21:22:53 2002
@@ -10,7 +10,6 @@
 #undef N_DATA
 
 #include <linux/kernel.h>
-#include <linux/tqueue.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
diff -Nru a/drivers/isdn/hardware/Config.in b/drivers/isdn/hardware/Config.in
--- a/drivers/isdn/hardware/Config.in	Fri Oct 11 21:22:56 2002
+++ b/drivers/isdn/hardware/Config.in	Fri Oct 11 21:22:56 2002
@@ -5,6 +5,7 @@
 if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
   comment 'CAPI hardware drivers'
   source drivers/isdn/hardware/avm/Config.in
+  source drivers/isdn/hardware/eicon/Config.in
 fi
 
 if [ "$CONFIG_ISDN" != "n" ]; then
diff -Nru a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile
--- a/drivers/isdn/hardware/Makefile	Fri Oct 11 21:22:55 2002
+++ b/drivers/isdn/hardware/Makefile	Fri Oct 11 21:22:55 2002
@@ -3,6 +3,7 @@
 # Object files in subdirectories
 
 obj-$(CONFIG_CAPI_AVM)		+= avm/
+obj-$(CONFIG_CAPI_EICON)	+= eicon/
 
 # The global Rules.make.
 
diff -Nru a/drivers/isdn/hardware/eicon/Config.help b/drivers/isdn/hardware/eicon/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/Config.help	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,31 @@
+CONFIG_CAPI_EICON
+  Enable support for Eicon Networks active ISDN cards.
+
+CONFIG_ISDN_DIVAS
+  Say Y here if you have an Eicon Networks DIVA Server PCI ISDN card.
+  In order to use this card, additional firmware is necessary, which
+  has to be downloaded into the card using the divactrl utility.
+
+CONFIG_ISDN_DIVAS_BRIPCI
+  Enable support for DIVA Server BRI-PCI.
+
+CONFIG_ISDN_DIVAS_4BRIPCI
+  Enable support for DIVA Server 4BRI-PCI.
+
+CONFIG_ISDN_DIVAS_PRIPCI
+  Enable support for DIVA Server PRI-PCI.
+
+CONFIG_ISDN_DIVAS_MAINT
+  Enable Divas Maintainance driver.
+
+CONFIG_ISDN_DIVAS_USERIDI
+  Enable support for user-mode IDI interface.
+
+CONFIG_ISDN_DIVAS_DIVACAPI
+  You need this to provide the CAPI interface
+  for DIVA Server cards.
+
+CONFIG_ISDN_DIVAS_DIVA2I4L
+  If you want to use the old isdn4linux module, you need
+  this enabled.
+
diff -Nru a/drivers/isdn/hardware/eicon/Config.in b/drivers/isdn/hardware/eicon/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/Config.in	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,20 @@
+#
+# ISDN DIVAS Eicon driver
+#
+
+mainmenu_option next_comment
+comment 'Active Eicon DIVA Server cards'
+
+bool 'Support Eicon cards' CONFIG_CAPI_EICON
+
+if [ "$CONFIG_CAPI_EICON" != "n" ]; then
+ dep_tristate 'Support Eicon DIVA Server cards' CONFIG_ISDN_DIVAS $CONFIG_PROC_FS $CONFIG_PCI m
+ dep_mbool     '   DIVA Server BRI/PCI support' CONFIG_ISDN_DIVAS_BRIPCI $CONFIG_ISDN_DIVAS
+ dep_mbool     '   DIVA Server 4BRI/PCI support' CONFIG_ISDN_DIVAS_4BRIPCI $CONFIG_ISDN_DIVAS
+ dep_mbool     '   DIVA Server PRI/PCI support' CONFIG_ISDN_DIVAS_PRIPCI $CONFIG_ISDN_DIVAS
+ dep_tristate '  DIVA CAPI2.0 interface support' CONFIG_ISDN_DIVAS_DIVACAPI $CONFIG_ISDN_DIVAS $CONFIG_ISDN_CAPI
+ dep_tristate '  DIVA Maint driver support' CONFIG_ISDN_DIVAS_MAINT $CONFIG_ISDN_DIVAS
+ dep_tristate '  DIVA User-IDI interface support' CONFIG_ISDN_DIVAS_USERIDI $CONFIG_ISDN_DIVAS
+fi
+
+endmenu
diff -Nru a/drivers/isdn/hardware/eicon/Makefile b/drivers/isdn/hardware/eicon/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/Makefile	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,31 @@
+# Makefile for the Eicon DIVA ISDN drivers.
+
+# Objects that export symbols.
+
+export-objs     := diva_didd.o
+
+# Multipart objects. 
+
+divas-objs      := divasmain.o divasfunc.o di.o io.o istream.o diva.o dlist.o divasproc.o diva_dma.o
+divacapi-objs   := capimain.o capifunc.o message.o capidtmf.o
+divadidd-objs   := diva_didd.o diddfunc.o dadapter.o
+diva_mnt-objs   := divamnt.o mntfunc.o debug.o maintidi.o
+diva_idi-objs   := divasi.o idifunc.o um_idi.o dqueue.o dlist.o
+
+# Optional parts of multipart objects.
+
+divas-objs-$(CONFIG_ISDN_DIVAS_BRIPCI)  += os_bri.o  s_bri.o
+divas-objs-$(CONFIG_ISDN_DIVAS_4BRIPCI) += os_4bri.o s_4bri.o
+divas-objs-$(CONFIG_ISDN_DIVAS_PRIPCI)  += os_pri.o  s_pri.o
+
+divas-objs += $(sort $(divas-objs-y))
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DIVAS)               += divadidd.o divas.o
+obj-$(CONFIG_ISDN_DIVAS_MAINT)         += diva_mnt.o
+obj-$(CONFIG_ISDN_DIVAS_USERIDI)       += diva_idi.o
+obj-$(CONFIG_ISDN_DIVAS_DIVACAPI)      += divacapi.o
+
+include $(TOPDIR)/Rules.make
+
diff -Nru a/drivers/isdn/hardware/eicon/adapter.h b/drivers/isdn/hardware/eicon/adapter.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/adapter.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,18 @@
+/* $Id: adapter.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#ifndef __DIVA_USER_MODE_IDI_ADAPTER_H__
+#define __DIVA_USER_MODE_IDI_ADAPTER_H__
+
+#define DIVA_UM_IDI_ADAPTER_REMOVED 0x00000001
+
+typedef struct _diva_um_idi_adapter  {
+  diva_entity_link_t          link;
+  DESCRIPTOR                  d;
+  int                         adapter_nr;
+  diva_entity_queue_t         entity_q; /* entities linked to this adapter */
+  dword                       status;
+} diva_um_idi_adapter_t;
+
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/capi20.h b/drivers/isdn/hardware/eicon/capi20.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/capi20.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,699 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef _INC_CAPI20  
+#define _INC_CAPI20
+        /* operations on message queues                             */
+        /* the common device type for CAPI20 drivers */
+#define FILE_DEVICE_CAPI20 0x8001
+        /* DEVICE_CONTROL codes for user and kernel mode applications */
+#define CAPI20_CTL_REGISTER             0x0801
+#define CAPI20_CTL_RELEASE              0x0802
+#define CAPI20_CTL_GET_MANUFACTURER     0x0805
+#define CAPI20_CTL_GET_VERSION          0x0806
+#define CAPI20_CTL_GET_SERIAL           0x0807
+#define CAPI20_CTL_GET_PROFILE          0x0808
+        /* INTERNAL_DEVICE_CONTROL codes for kernel mode applicatios only */
+#define CAPI20_CTL_PUT_MESSAGE          0x0803
+#define CAPI20_CTL_GET_MESSAGE          0x0804
+        /* the wrapped codes as required by the system */
+#define CAPI_CTL_CODE(f,m)              CTL_CODE(FILE_DEVICE_CAPI20,f,m,FILE_ANY_ACCESS)
+#define IOCTL_CAPI_REGISTER             CAPI_CTL_CODE(CAPI20_CTL_REGISTER,METHOD_BUFFERED)
+#define IOCTL_CAPI_RELEASE              CAPI_CTL_CODE(CAPI20_CTL_RELEASE,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_MANUFACTURER     CAPI_CTL_CODE(CAPI20_CTL_GET_MANUFACTURER,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_VERSION          CAPI_CTL_CODE(CAPI20_CTL_GET_VERSION,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_SERIAL           CAPI_CTL_CODE(CAPI20_CTL_GET_SERIAL,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_PROFILE          CAPI_CTL_CODE(CAPI20_CTL_GET_PROFILE,METHOD_BUFFERED)
+#define IOCTL_CAPI_PUT_MESSAGE          CAPI_CTL_CODE(CAPI20_CTL_PUT_MESSAGE,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_MESSAGE          CAPI_CTL_CODE(CAPI20_CTL_GET_MESSAGE,METHOD_BUFFERED)
+struct divas_capi_register_params  {
+  word MessageBufferSize;
+  word maxLogicalConnection;
+  word maxBDataBlocks;
+  word maxBDataLen;
+};
+struct divas_capi_version  {
+  word CapiMajor;
+  word CapiMinor;
+  word ManuMajor;
+  word ManuMinor;
+};
+typedef struct api_profile_s {
+  word          Number;
+  word          Channels;
+  dword         Global_Options;
+  dword         B1_Protocols;
+  dword         B2_Protocols;
+  dword         B3_Protocols;
+} API_PROFILE;
+        /* ISDN Common API message types                            */
+#define _ALERT_R                        0x8001
+#define _CONNECT_R                      0x8002
+#define _CONNECT_I                      0x8202
+#define _CONNECT_ACTIVE_I               0x8203
+#define _DISCONNECT_R                   0x8004
+#define _DISCONNECT_I                   0x8204
+#define _LISTEN_R                       0x8005
+#define _INFO_R                         0x8008
+#define _INFO_I                         0x8208
+#define _SELECT_B_REQ                   0x8041
+#define _FACILITY_R                     0x8080
+#define _FACILITY_I                     0x8280
+#define _CONNECT_B3_R                   0x8082
+#define _CONNECT_B3_I                   0x8282
+#define _CONNECT_B3_ACTIVE_I            0x8283
+#define _DISCONNECT_B3_R                0x8084
+#define _DISCONNECT_B3_I                0x8284
+#define _DATA_B3_R                      0x8086
+#define _DATA_B3_I                      0x8286
+#define _RESET_B3_R                     0x8087
+#define _RESET_B3_I                     0x8287
+#define _CONNECT_B3_T90_ACTIVE_I        0x8288
+#define _MANUFACTURER_R                 0x80ff
+#define _MANUFACTURER_I                 0x82ff
+        /* OR this to convert a REQUEST to a CONFIRM                */
+#define CONFIRM                 0x0100
+        /* OR this to convert a INDICATION to a RESPONSE            */
+#define RESPONSE                0x0100
+/*------------------------------------------------------------------*/
+/* diehl isdn private MANUFACTURER codes                            */
+/*------------------------------------------------------------------*/
+#define _DI_MANU_ID             0x44444944
+#define _DI_ASSIGN_PLCI         0x0001
+#define _DI_ADV_CODEC           0x0002
+#define _DI_DSP_CTRL            0x0003
+#define _DI_SIG_CTRL            0x0004
+#define _DI_RXT_CTRL            0x0005
+#define _DI_IDI_CTRL            0x0006
+#define _DI_CFG_CTRL            0x0007
+#define _DI_REMOVE_CODEC        0x0008
+#define _DI_OPTIONS_REQUEST     0x0009
+#define _DI_SSEXT_CTRL          0x000a
+#define _DI_NEGOTIATE_B3        0x000b
+/*------------------------------------------------------------------*/
+/* parameter structures                                             */
+/*------------------------------------------------------------------*/
+        /* ALERT-REQUEST                                            */
+typedef struct {
+  byte structs[1];      /* Additional Info */
+} _ALT_REQP;
+        /* ALERT-CONFIRM                                            */
+typedef struct {
+  word Info;
+} _ALT_CONP;
+        /* CONNECT-REQUEST                                          */
+typedef struct {
+  word CIP_Value;
+  byte structs[1];      /* Called party number,
+                           Called party subaddress,
+                           Calling party number,
+                           Calling party subaddress,
+                           B_protocol,
+                           BC,
+                           LLC,
+                           HLC,
+                           Additional Info */
+} _CON_REQP;
+        /* CONNECT-CONFIRM                                          */
+typedef struct {
+  word Info;
+} _CON_CONP;
+        /* CONNECT-INDICATION                                       */
+typedef struct {
+  word CIP_Value;
+  byte structs[1];      /* Called party number,
+                           Called party subaddress,
+                           Calling party number,
+                           Calling party subaddress,
+                           BC,
+                           LLC,
+                           HLC,
+                           Additional Info */
+} _CON_INDP;
+        /* CONNECT-RESPONSE                                         */
+typedef struct {
+  word Accept;
+  byte structs[1];      /* B_protocol,
+                           Connected party number,
+                           Connected party subaddress,
+                           LLC */
+} _CON_RESP;
+        /* CONNECT-ACTIVE-INDICATION                                */
+typedef struct {
+  byte structs[1];      /* Connected party number,
+                           Connected party subaddress,
+                           LLC */
+} _CON_A_INDP;
+        /* CONNECT-ACTIVE-RESPONSE                                  */
+typedef struct {
+  byte structs[1];      /* empty */
+} _CON_A_RESP;
+        /* DISCONNECT-REQUEST                                       */
+typedef struct {
+  byte structs[1];      /* Additional Info */
+} _DIS_REQP;
+        /* DISCONNECT-CONFIRM                                       */
+typedef struct {
+  word Info;
+} _DIS_CONP;
+        /* DISCONNECT-INDICATION                                    */
+typedef struct {
+  word Info;
+} _DIS_INDP;
+        /* DISCONNECT-RESPONSE                                      */
+typedef struct {
+  byte structs[1];      /* empty */
+} _DIS_RESP;
+        /* LISTEN-REQUEST                                           */
+typedef struct {
+  dword Info_Mask;
+  dword CIP_Mask;
+  byte structs[1];      /* Calling party number,
+                           Calling party subaddress */
+} _LIS_REQP;
+        /* LISTEN-CONFIRM                                           */
+typedef struct {
+  word Info;
+} _LIS_CONP;
+        /* INFO-REQUEST                                             */
+typedef struct {
+  byte structs[1];      /* Called party number,
+                           Additional Info */
+} _INF_REQP;
+        /* INFO-CONFIRM                                             */
+typedef struct {
+  word Info;
+} _INF_CONP;
+        /* INFO-INDICATION                                          */
+typedef struct {
+  word Number;
+  byte structs[1];      /* Info element */
+} _INF_INDP;
+        /* INFO-RESPONSE                                            */
+typedef struct {
+  byte structs[1];      /* empty */
+} _INF_RESP;
+        /* SELECT-B-REQUEST                                         */
+typedef struct {
+  byte structs[1];      /* B-protocol */
+} _SEL_B_REQP;
+        /* SELECT-B-CONFIRM                                         */
+typedef struct {
+  word Info;
+} _SEL_B_CONP;
+        /* FACILITY-REQUEST */
+typedef struct {
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_REQP;
+        /* FACILITY-CONFIRM STRUCT FOR SUPPLEMENT. SERVICES */
+typedef struct {
+  byte  struct_length;
+  word  function;
+  byte  length;
+  word  SupplementaryServiceInfo;
+  dword SupportedServices;
+} _FAC_CON_STRUCTS;
+        /* FACILITY-CONFIRM */
+typedef struct {
+  word Info;
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_CONP;
+        /* FACILITY-INDICATION */
+typedef struct {
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_INDP;
+        /* FACILITY-RESPONSE */
+typedef struct {
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_RESP;
+        /* CONNECT-B3-REQUEST                                       */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_REQP;
+        /* CONNECT-B3-CONFIRM                                       */
+typedef struct {
+  word Info;
+} _CON_B3_CONP;
+        /* CONNECT-B3-INDICATION                                    */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_INDP;
+        /* CONNECT-B3-RESPONSE                                      */
+typedef struct {
+  word Accept;
+  byte structs[1];      /* NCPI */
+} _CON_B3_RESP;
+        /* CONNECT-B3-ACTIVE-INDICATION                             */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_A_INDP;
+        /* CONNECT-B3-ACTIVE-RESPONSE                               */
+typedef struct {
+  byte structs[1];      /* empty */
+} _CON_B3_A_RESP;
+        /* DISCONNECT-B3-REQUEST                                    */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _DIS_B3_REQP;
+        /* DISCONNECT-B3-CONFIRM                                    */
+typedef struct {
+  word Info;
+} _DIS_B3_CONP;
+        /* DISCONNECT-B3-INDICATION                                 */
+typedef struct {
+  word Info;
+  byte structs[1];      /* NCPI */
+} _DIS_B3_INDP;
+        /* DISCONNECT-B3-RESPONSE                                   */
+typedef struct {
+  byte structs[1];      /* empty */
+} _DIS_B3_RESP;
+        /* DATA-B3-REQUEST                                          */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+} _DAT_B3_REQP;
+        /* DATA-B3-REQUEST 64 BIT Systems                           */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+  void          *pData;
+} _DAT_B3_REQ64P;
+        /* DATA-B3-CONFIRM                                          */
+typedef struct {
+  word          Number;
+  word          Info;
+} _DAT_B3_CONP;
+        /* DATA-B3-INDICATION                                       */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+} _DAT_B3_INDP;
+        /* DATA-B3-INDICATION  64 BIT Systems                       */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+  void          *pData;
+} _DAT_B3_IND64P;
+        /* DATA-B3-RESPONSE                                         */
+typedef struct {
+  word          Number;
+} _DAT_B3_RESP;
+        /* RESET-B3-REQUEST                                         */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _RES_B3_REQP;
+        /* RESET-B3-CONFIRM                                         */
+typedef struct {
+  word Info;
+} _RES_B3_CONP;
+        /* RESET-B3-INDICATION                                      */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _RES_B3_INDP;
+        /* RESET-B3-RESPONSE                                        */
+typedef struct {
+  byte structs[1];      /* empty */
+} _RES_B3_RESP;
+        /* CONNECT-B3-T90-ACTIVE-INDICATION                         */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_T90_A_INDP;
+        /* CONNECT-B3-T90-ACTIVE-RESPONSE                           */
+typedef struct {
+  word Reject;
+  byte structs[1];      /* NCPI */
+} _CON_B3_T90_A_RESP;
+/*------------------------------------------------------------------*/
+/* message structure                                                */
+/*------------------------------------------------------------------*/
+typedef struct _API_MSG CAPI_MSG;
+typedef struct _MSG_HEADER CAPI_MSG_HEADER;
+struct _API_MSG {
+  struct _MSG_HEADER {
+    word        length;
+    word        appl_id;
+    word        command;
+    word        number;
+    byte        controller;
+    byte        plci;
+    word        ncci;
+  } header;
+  union {
+    _ALT_REQP           alert_req;
+    _ALT_CONP           alert_con;
+    _CON_REQP           connect_req;
+    _CON_CONP           connect_con;
+    _CON_INDP           connect_ind;
+    _CON_RESP           connect_res;
+    _CON_A_INDP         connect_a_ind;
+    _CON_A_RESP         connect_a_res;
+    _DIS_REQP           disconnect_req;
+    _DIS_CONP           disconnect_con;
+    _DIS_INDP           disconnect_ind;
+    _DIS_RESP           disconnect_res;
+    _LIS_REQP           listen_req;
+    _LIS_CONP           listen_con;
+    _INF_REQP           info_req;
+    _INF_CONP           info_con;
+    _INF_INDP           info_ind;
+    _INF_RESP           info_res;
+    _SEL_B_REQP         select_b_req;
+    _SEL_B_CONP         select_b_con;
+    _FAC_REQP           facility_req;
+    _FAC_CONP           facility_con;
+    _FAC_INDP           facility_ind;
+    _FAC_RESP           facility_res;
+    _CON_B3_REQP        connect_b3_req;
+    _CON_B3_CONP        connect_b3_con;
+    _CON_B3_INDP        connect_b3_ind;
+    _CON_B3_RESP        connect_b3_res;
+    _CON_B3_A_INDP      connect_b3_a_ind;
+    _CON_B3_A_RESP      connect_b3_a_res;
+    _DIS_B3_REQP        disconnect_b3_req;
+    _DIS_B3_CONP        disconnect_b3_con;
+    _DIS_B3_INDP        disconnect_b3_ind;
+    _DIS_B3_RESP        disconnect_b3_res;
+    _DAT_B3_REQP        data_b3_req;
+    _DAT_B3_REQ64P      data_b3_req64;
+    _DAT_B3_CONP        data_b3_con;
+    _DAT_B3_INDP        data_b3_ind;
+    _DAT_B3_IND64P      data_b3_ind64;
+    _DAT_B3_RESP        data_b3_res;
+    _RES_B3_REQP        reset_b3_req;
+    _RES_B3_CONP        reset_b3_con;
+    _RES_B3_INDP        reset_b3_ind;
+    _RES_B3_RESP        reset_b3_res;
+    _CON_B3_T90_A_INDP  connect_b3_t90_a_ind;
+    _CON_B3_T90_A_RESP  connect_b3_t90_a_res;
+    byte                b[200];
+  } info;
+};
+/*------------------------------------------------------------------*/
+/* non-fatal errors                                                 */
+/*------------------------------------------------------------------*/
+#define _NCPI_IGNORED           0x0001
+#define _FLAGS_IGNORED          0x0002
+#define _ALERT_IGNORED          0x0003
+/*------------------------------------------------------------------*/
+/* API function error codes                                         */
+/*------------------------------------------------------------------*/
+#define GOOD                            0x0000
+#define _TOO_MANY_APPLICATIONS          0x1001
+#define _BLOCK_TOO_SMALL                0x1002
+#define _BUFFER_TOO_BIG                 0x1003
+#define _MSG_BUFFER_TOO_SMALL           0x1004
+#define _TOO_MANY_CONNECTIONS           0x1005
+#define _REG_CAPI_BUSY                  0x1007
+#define _REG_RESOURCE_ERROR             0x1008
+#define _REG_CAPI_NOT_INSTALLED         0x1009
+#define _WRONG_APPL_ID                  0x1101
+#define _BAD_MSG                        0x1102
+#define _QUEUE_FULL                     0x1103
+#define _GET_NO_MSG                     0x1104
+#define _MSG_LOST                       0x1105
+#define _WRONG_NOTIFY                   0x1106
+#define _CAPI_BUSY                      0x1107
+#define _RESOURCE_ERROR                 0x1108
+#define _CAPI_NOT_INSTALLED             0x1109
+#define _NO_EXTERNAL_EQUIPMENT          0x110a
+#define _ONLY_EXTERNAL_EQUIPMENT        0x110b
+/*------------------------------------------------------------------*/
+/* addressing/coding error codes                                    */
+/*------------------------------------------------------------------*/
+#define _WRONG_STATE                    0x2001
+#define _WRONG_IDENTIFIER               0x2002
+#define _OUT_OF_PLCI                    0x2003
+#define _OUT_OF_NCCI                    0x2004
+#define _OUT_OF_LISTEN                  0x2005
+#define _OUT_OF_FAX                     0x2006
+#define _WRONG_MESSAGE_FORMAT           0x2007
+#define _OUT_OF_INTERCONNECT_RESOURCES  0x2008
+/*------------------------------------------------------------------*/
+/* configuration error codes                                        */
+/*------------------------------------------------------------------*/
+#define _B1_NOT_SUPPORTED                    0x3001
+#define _B2_NOT_SUPPORTED                    0x3002
+#define _B3_NOT_SUPPORTED                    0x3003
+#define _B1_PARM_NOT_SUPPORTED               0x3004
+#define _B2_PARM_NOT_SUPPORTED               0x3005
+#define _B3_PARM_NOT_SUPPORTED               0x3006
+#define _B_STACK_NOT_SUPPORTED               0x3007
+#define _NCPI_NOT_SUPPORTED                  0x3008
+#define _CIP_NOT_SUPPORTED                   0x3009
+#define _FLAGS_NOT_SUPPORTED                 0x300a
+#define _FACILITY_NOT_SUPPORTED              0x300b
+#define _DATA_LEN_NOT_SUPPORTED              0x300c
+#define _RESET_NOT_SUPPORTED                 0x300d
+#define _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED 0x300e
+#define _REQUEST_NOT_ALLOWED_IN_THIS_STATE   0x3010
+#define _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP 0x3011
+/*------------------------------------------------------------------*/
+/* reason codes                                                     */
+/*------------------------------------------------------------------*/
+#define _L1_ERROR                       0x3301
+#define _L2_ERROR                       0x3302
+#define _L3_ERROR                       0x3303
+#define _OTHER_APPL_CONNECTED           0x3304
+#define _CAPI_GUARD_ERROR               0x3305
+#define _L3_CAUSE                       0x3400
+/*------------------------------------------------------------------*/
+/* b3 reason codes                                                  */
+/*------------------------------------------------------------------*/
+#define _B_CHANNEL_LOST                 0x3301
+#define _B2_ERROR                       0x3302
+#define _B3_ERROR                       0x3303
+/*------------------------------------------------------------------*/
+/* fax error codes                                                  */
+/*------------------------------------------------------------------*/
+#define _FAX_NO_CONNECTION              0x3311
+#define _FAX_TRAINING_ERROR             0x3312
+#define _FAX_REMOTE_REJECT              0x3313
+#define _FAX_REMOTE_ABORT               0x3314
+#define _FAX_PROTOCOL_ERROR             0x3315
+#define _FAX_TX_UNDERRUN                0x3316
+#define _FAX_RX_OVERFLOW                0x3317
+#define _FAX_LOCAL_ABORT                0x3318
+#define _FAX_PARAMETER_ERROR            0x3319
+/*------------------------------------------------------------------*/
+/* line interconnect error codes                                    */
+/*------------------------------------------------------------------*/
+#define _LI_USER_INITIATED               0x0000
+#define _LI_LINE_NO_LONGER_AVAILABLE     0x3805
+#define _LI_INTERCONNECT_NOT_ESTABLISHED 0x3806
+#define _LI_LINES_NOT_COMPATIBLE         0x3807
+#define _LI2_USER_INITIATED              0x0000
+#define _LI2_PLCI_HAS_NO_BCHANNEL        0x3800
+#define _LI2_LINES_NOT_COMPATIBLE        0x3801
+#define _LI2_NOT_IN_SAME_INTERCONNECTION 0x3802
+/*------------------------------------------------------------------*/
+/* global options                                                   */
+/*------------------------------------------------------------------*/
+#define GL_INTERNAL_CONTROLLER_SUPPORTED     0x00000001L
+#define GL_EXTERNAL_EQUIPMENT_SUPPORTED      0x00000002L
+#define GL_HANDSET_SUPPORTED                 0x00000004L
+#define GL_DTMF_SUPPORTED                    0x00000008L
+#define GL_SUPPLEMENTARY_SERVICES_SUPPORTED  0x00000010L
+#define GL_CHANNEL_ALLOCATION_SUPPORTED      0x00000020L
+#define GL_BCHANNEL_OPERATION_SUPPORTED      0x00000040L
+#define GL_LINE_INTERCONNECT_SUPPORTED       0x00000080L
+#define GL_ECHO_CANCELLER_SUPPORTED          0x00000100L
+/*------------------------------------------------------------------*/
+/* protocol selection                                               */
+/*------------------------------------------------------------------*/
+#define B1_HDLC                 0
+#define B1_TRANSPARENT          1
+#define B1_V110_ASYNC           2
+#define B1_V110_SYNC            3
+#define B1_T30                  4
+#define B1_HDLC_INVERTED        5
+#define B1_TRANSPARENT_R        6
+#define B1_MODEM_ALL_NEGOTIATE  7
+#define B1_MODEM_ASYNC          8
+#define B1_MODEM_SYNC_HDLC      9
+#define B2_X75                  0
+#define B2_TRANSPARENT          1
+#define B2_SDLC                 2
+#define B2_LAPD                 3
+#define B2_T30                  4
+#define B2_PPP                  5
+#define B2_TRANSPARENT_NO_CRC   6
+#define B2_MODEM_EC_COMPRESSION 7
+#define B2_X75_V42BIS           8
+#define B2_V120_ASYNC           9
+#define B2_V120_ASYNC_V42BIS    10
+#define B2_V120_BIT_TRANSPARENT 11
+#define B2_LAPD_FREE_SAPI_SEL   12
+#define B3_TRANSPARENT          0
+#define B3_T90NL                1
+#define B3_ISO8208              2
+#define B3_X25_DCE              3
+#define B3_T30                  4
+#define B3_T30_WITH_EXTENSIONS  5
+#define B3_RESERVED             6
+#define B3_MODEM                7
+/*------------------------------------------------------------------*/
+/*  facility definitions                                            */
+/*------------------------------------------------------------------*/
+#define SELECTOR_HANDSET            0
+#define SELECTOR_DTMF               1
+#define SELECTOR_V42BIS             2
+#define SELECTOR_SU_SERV            3
+#define SELECTOR_POWER_MANAGEMENT   4
+#define SELECTOR_LINE_INTERCONNECT  5
+#define SELECTOR_ECHO_CANCELLER     6
+/*------------------------------------------------------------------*/
+/*  supplementary services definitions                              */
+/*------------------------------------------------------------------*/
+#define S_GET_SUPPORTED_SERVICES  0x0000
+#define S_LISTEN                  0x0001
+#define S_HOLD                    0x0002
+#define S_RETRIEVE                0x0003
+#define S_SUSPEND                 0x0004
+#define S_RESUME                  0x0005
+#define S_ECT                     0x0006
+#define S_3PTY_BEGIN              0x0007
+#define S_3PTY_END                0x0008
+#define S_CALL_DEFLECTION         0x000d
+#define S_CALL_FORWARDING_START   0x0009
+#define S_CALL_FORWARDING_STOP    0x000a
+#define S_INTERROGATE_DIVERSION   0x000b /* or interrogate parameters */
+#define S_INTERROGATE_NUMBERS     0x000c
+#define S_CCBS_REQUEST            0x000f
+#define S_CCBS_DEACTIVATE         0x0010
+#define S_CCBS_INTERROGATE        0x0011
+#define S_CCBS_CALL               0x0012
+#define S_MWI_ACTIVATE            0x0013
+#define S_MWI_DEACTIVATE          0x0014
+#define S_CONF_BEGIN           0x0017
+#define S_CONF_ADD                0x0018
+#define S_CONF_SPLIT           0x0019
+#define S_CONF_DROP               0x001a
+#define S_CONF_ISOLATE           0x001b
+#define S_CONF_REATTACH           0x001c
+#define S_CCBS_ERASECALLLINKAGEID 0x800d
+#define S_CCBS_STOP_ALERTING      0x8012
+#define S_CCBS_INFO_RETAIN        0x8013
+#define S_MWI_INDICATE            0x8014
+#define S_CONF_PARTYDISC          0x8016
+#define S_CONF_NOTIFICATION       0x8017
+/* Service Masks */
+#define MASK_HOLD_RETRIEVE        0x00000001
+#define MASK_TERMINAL_PORTABILITY 0x00000002
+#define MASK_ECT                  0x00000004
+#define MASK_3PTY                 0x00000008
+#define MASK_CALL_FORWARDING      0x00000010
+#define MASK_CALL_DEFLECTION      0x00000020
+#define MASK_MWI                  0x00000100
+#define MASK_CCNR                 0x00000200
+#define MASK_CONF                 0x00000400
+/*------------------------------------------------------------------*/
+/*  dtmf definitions                                                */
+/*------------------------------------------------------------------*/
+#define DTMF_LISTEN_START     1
+#define DTMF_LISTEN_STOP      2
+#define DTMF_DIGITS_SEND      3
+#define DTMF_SUCCESS          0
+#define DTMF_INCORRECT_DIGIT  1
+#define DTMF_UNKNOWN_REQUEST  2
+/*------------------------------------------------------------------*/
+/*  line interconnect definitions                                   */
+/*------------------------------------------------------------------*/
+#define LI_GET_SUPPORTED_SERVICES       0
+#define LI_REQ_CONNECT                  1
+#define LI_REQ_DISCONNECT               2
+#define LI_IND_CONNECT_ACTIVE           1
+#define LI_IND_DISCONNECT               2
+#define LI_FLAG_CONFERENCE_A_B          ((dword) 0x00000001L)
+#define LI_FLAG_CONFERENCE_B_A          ((dword) 0x00000002L)
+#define LI_FLAG_MONITOR_A               ((dword) 0x00000004L)
+#define LI_FLAG_MONITOR_B               ((dword) 0x00000008L)
+#define LI_FLAG_ANNOUNCEMENT_A          ((dword) 0x00000010L)
+#define LI_FLAG_ANNOUNCEMENT_B          ((dword) 0x00000020L)
+#define LI_FLAG_MIX_A                   ((dword) 0x00000040L)
+#define LI_FLAG_MIX_B                   ((dword) 0x00000080L)
+#define LI_CONFERENCING_SUPPORTED       ((dword) 0x00000001L)
+#define LI_MONITORING_SUPPORTED         ((dword) 0x00000002L)
+#define LI_ANNOUNCEMENTS_SUPPORTED      ((dword) 0x00000004L)
+#define LI_MIXING_SUPPORTED             ((dword) 0x00000008L)
+#define LI_CROSS_CONTROLLER_SUPPORTED   ((dword) 0x00000010L)
+#define LI2_GET_SUPPORTED_SERVICES      0
+#define LI2_REQ_CONNECT                 1
+#define LI2_REQ_DISCONNECT              2
+#define LI2_IND_CONNECT_ACTIVE          1
+#define LI2_IND_DISCONNECT              2
+#define LI2_FLAG_INTERCONNECT_A_B       ((dword) 0x00000001L)
+#define LI2_FLAG_INTERCONNECT_B_A       ((dword) 0x00000002L)
+#define LI2_FLAG_MONITOR_B              ((dword) 0x00000004L)
+#define LI2_FLAG_MIX_B                  ((dword) 0x00000008L)
+#define LI2_FLAG_MONITOR_X              ((dword) 0x00000010L)
+#define LI2_FLAG_MIX_X                  ((dword) 0x00000020L)
+#define LI2_FLAG_LOOP_B                 ((dword) 0x00000040L)
+#define LI2_FLAG_LOOP_PC                ((dword) 0x00000080L)
+#define LI2_FLAG_LOOP_X                 ((dword) 0x00000100L)
+#define LI2_CROSS_CONTROLLER_SUPPORTED  ((dword) 0x00000001L)
+#define LI2_ASYMMETRIC_SUPPORTED        ((dword) 0x00000002L)
+#define LI2_MONITORING_SUPPORTED        ((dword) 0x00000004L)
+#define LI2_MIXING_SUPPORTED            ((dword) 0x00000008L)
+#define LI2_REMOTE_MONITORING_SUPPORTED ((dword) 0x00000010L)
+#define LI2_REMOTE_MIXING_SUPPORTED     ((dword) 0x00000020L)
+#define LI2_B_LOOPING_SUPPORTED         ((dword) 0x00000040L)
+#define LI2_PC_LOOPING_SUPPORTED        ((dword) 0x00000080L)
+#define LI2_X_LOOPING_SUPPORTED         ((dword) 0x00000100L)
+/*------------------------------------------------------------------*/
+/* echo canceller definitions                                       */
+/*------------------------------------------------------------------*/
+#define EC_GET_SUPPORTED_SERVICES            0
+#define EC_ENABLE_OPERATION                  1
+#define EC_DISABLE_OPERATION                 2
+#define EC_ENABLE_NON_LINEAR_PROCESSING      0x0001
+#define EC_DO_NOT_REQUIRE_REVERSALS          0x0002
+#define EC_DETECT_DISABLE_TONE               0x0004
+#define EC_ENABLE_ADAPTIVE_PREDELAY          0x0008
+#define EC_NON_LINEAR_PROCESSING_SUPPORTED   0x0001
+#define EC_BYPASS_ON_ANY_2100HZ_SUPPORTED    0x0002
+#define EC_BYPASS_ON_REV_2100HZ_SUPPORTED    0x0004
+#define EC_ADAPTIVE_PREDELAY_SUPPORTED       0x0008
+#define EC_BYPASS_INDICATION                 1
+#define EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ   1
+#define EC_BYPASS_DUE_TO_REVERSED_2100HZ     2
+#define EC_BYPASS_RELEASED                   3
+/*------------------------------------------------------------------*/
+/* function prototypes                                              */
+/*------------------------------------------------------------------*/
+/*------------------------------------------------------------------*/
+#endif /* _INC_CAPI20 */  
diff -Nru a/drivers/isdn/hardware/eicon/capidtmf.c b/drivers/isdn/hardware/eicon/capidtmf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/capidtmf.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,685 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "platform.h"
+
+
+  
+  
+
+
+
+
+
+#include "capidtmf.h"
+
+/* #define TRACE_ */
+
+#define FILE_ "CAPIDTMF.C"
+
+/*---------------------------------------------------------------------------*/
+
+
+#define trace(a)
+
+
+
+/*---------------------------------------------------------------------------*/
+
+static short capidtmf_expand_table_alaw[0x0100] =
+{
+   -5504,   5504,   -344,    344, -22016,  22016,  -1376,   1376,
+   -2752,   2752,    -88,     88, -11008,  11008,   -688,    688,
+   -7552,   7552,   -472,    472, -30208,  30208,  -1888,   1888,
+   -3776,   3776,   -216,    216, -15104,  15104,   -944,    944,
+   -4480,   4480,   -280,    280, -17920,  17920,  -1120,   1120,
+   -2240,   2240,    -24,     24,  -8960,   8960,   -560,    560,
+   -6528,   6528,   -408,    408, -26112,  26112,  -1632,   1632,
+   -3264,   3264,   -152,    152, -13056,  13056,   -816,    816,
+   -6016,   6016,   -376,    376, -24064,  24064,  -1504,   1504,
+   -3008,   3008,   -120,    120, -12032,  12032,   -752,    752,
+   -8064,   8064,   -504,    504, -32256,  32256,  -2016,   2016,
+   -4032,   4032,   -248,    248, -16128,  16128,  -1008,   1008,
+   -4992,   4992,   -312,    312, -19968,  19968,  -1248,   1248,
+   -2496,   2496,    -56,     56,  -9984,   9984,   -624,    624,
+   -7040,   7040,   -440,    440, -28160,  28160,  -1760,   1760,
+   -3520,   3520,   -184,    184, -14080,  14080,   -880,    880,
+   -5248,   5248,   -328,    328, -20992,  20992,  -1312,   1312,
+   -2624,   2624,    -72,     72, -10496,  10496,   -656,    656,
+   -7296,   7296,   -456,    456, -29184,  29184,  -1824,   1824,
+   -3648,   3648,   -200,    200, -14592,  14592,   -912,    912,
+   -4224,   4224,   -264,    264, -16896,  16896,  -1056,   1056,
+   -2112,   2112,     -8,      8,  -8448,   8448,   -528,    528,
+   -6272,   6272,   -392,    392, -25088,  25088,  -1568,   1568,
+   -3136,   3136,   -136,    136, -12544,  12544,   -784,    784,
+   -5760,   5760,   -360,    360, -23040,  23040,  -1440,   1440,
+   -2880,   2880,   -104,    104, -11520,  11520,   -720,    720,
+   -7808,   7808,   -488,    488, -31232,  31232,  -1952,   1952,
+   -3904,   3904,   -232,    232, -15616,  15616,   -976,    976,
+   -4736,   4736,   -296,    296, -18944,  18944,  -1184,   1184,
+   -2368,   2368,    -40,     40,  -9472,   9472,   -592,    592,
+   -6784,   6784,   -424,    424, -27136,  27136,  -1696,   1696,
+   -3392,   3392,   -168,    168, -13568,  13568,   -848,    848
+};
+
+static short capidtmf_expand_table_ulaw[0x0100] =
+{
+  -32124,  32124,  -1884,   1884,  -7932,   7932,   -372,    372,
+  -15996,  15996,   -876,    876,  -3900,   3900,   -120,    120,
+  -23932,  23932,  -1372,   1372,  -5884,   5884,   -244,    244,
+  -11900,  11900,   -620,    620,  -2876,   2876,    -56,     56,
+  -28028,  28028,  -1628,   1628,  -6908,   6908,   -308,    308,
+  -13948,  13948,   -748,    748,  -3388,   3388,    -88,     88,
+  -19836,  19836,  -1116,   1116,  -4860,   4860,   -180,    180,
+   -9852,   9852,   -492,    492,  -2364,   2364,    -24,     24,
+  -30076,  30076,  -1756,   1756,  -7420,   7420,   -340,    340,
+  -14972,  14972,   -812,    812,  -3644,   3644,   -104,    104,
+  -21884,  21884,  -1244,   1244,  -5372,   5372,   -212,    212,
+  -10876,  10876,   -556,    556,  -2620,   2620,    -40,     40,
+  -25980,  25980,  -1500,   1500,  -6396,   6396,   -276,    276,
+  -12924,  12924,   -684,    684,  -3132,   3132,    -72,     72,
+  -17788,  17788,   -988,    988,  -4348,   4348,   -148,    148,
+   -8828,   8828,   -428,    428,  -2108,   2108,     -8,      8,
+  -31100,  31100,  -1820,   1820,  -7676,   7676,   -356,    356,
+  -15484,  15484,   -844,    844,  -3772,   3772,   -112,    112,
+  -22908,  22908,  -1308,   1308,  -5628,   5628,   -228,    228,
+  -11388,  11388,   -588,    588,  -2748,   2748,    -48,     48,
+  -27004,  27004,  -1564,   1564,  -6652,   6652,   -292,    292,
+  -13436,  13436,   -716,    716,  -3260,   3260,    -80,     80,
+  -18812,  18812,  -1052,   1052,  -4604,   4604,   -164,    164,
+   -9340,   9340,   -460,    460,  -2236,   2236,    -16,     16,
+  -29052,  29052,  -1692,   1692,  -7164,   7164,   -324,    324,
+  -14460,  14460,   -780,    780,  -3516,   3516,    -96,     96,
+  -20860,  20860,  -1180,   1180,  -5116,   5116,   -196,    196,
+  -10364,  10364,   -524,    524,  -2492,   2492,    -32,     32,
+  -24956,  24956,  -1436,   1436,  -6140,   6140,   -260,    260,
+  -12412,  12412,   -652,    652,  -3004,   3004,    -64,     64,
+  -16764,  16764,   -924,    924,  -4092,   4092,   -132,    132,
+   -8316,   8316,   -396,    396,  -1980,   1980,      0,      0
+};
+
+
+/*---------------------------------------------------------------------------*/
+
+static short capidtmf_recv_window_function[CAPIDTMF_RECV_ACCUMULATE_CYCLES] =
+{
+    -500L,   -999L,  -1499L,  -1998L,  -2496L,  -2994L,  -3491L,  -3988L,
+   -4483L,  -4978L,  -5471L,  -5963L,  -6454L,  -6943L,  -7431L,  -7917L,
+   -8401L,  -8883L,  -9363L,  -9840L, -10316L, -10789L, -11259L, -11727L,
+  -12193L, -12655L, -13115L, -13571L, -14024L, -14474L, -14921L, -15364L,
+  -15804L, -16240L, -16672L, -17100L, -17524L, -17944L, -18360L, -18772L,
+  -19180L, -19583L, -19981L, -20375L, -20764L, -21148L, -21527L, -21901L,
+  -22270L, -22634L, -22993L, -23346L, -23694L, -24037L, -24374L, -24705L,
+  -25030L, -25350L, -25664L, -25971L, -26273L, -26568L, -26858L, -27141L,
+  -27418L, -27688L, -27952L, -28210L, -28461L, -28705L, -28943L, -29174L,
+  -29398L, -29615L, -29826L, -30029L, -30226L, -30415L, -30598L, -30773L,
+  -30941L, -31102L, -31256L, -31402L, -31541L, -31673L, -31797L, -31914L,
+  -32024L, -32126L, -32221L, -32308L, -32388L, -32460L, -32524L, -32581L,
+  -32631L, -32673L, -32707L, -32734L, -32753L, -32764L, -32768L, -32764L,
+  -32753L, -32734L, -32707L, -32673L, -32631L, -32581L, -32524L, -32460L,
+  -32388L, -32308L, -32221L, -32126L, -32024L, -31914L, -31797L, -31673L,
+  -31541L, -31402L, -31256L, -31102L, -30941L, -30773L, -30598L, -30415L,
+  -30226L, -30029L, -29826L, -29615L, -29398L, -29174L, -28943L, -28705L,
+  -28461L, -28210L, -27952L, -27688L, -27418L, -27141L, -26858L, -26568L,
+  -26273L, -25971L, -25664L, -25350L, -25030L, -24705L, -24374L, -24037L,
+  -23694L, -23346L, -22993L, -22634L, -22270L, -21901L, -21527L, -21148L,
+  -20764L, -20375L, -19981L, -19583L, -19180L, -18772L, -18360L, -17944L,
+  -17524L, -17100L, -16672L, -16240L, -15804L, -15364L, -14921L, -14474L,
+  -14024L, -13571L, -13115L, -12655L, -12193L, -11727L, -11259L, -10789L,
+  -10316L,  -9840L,  -9363L,  -8883L,  -8401L,  -7917L,  -7431L,  -6943L,
+   -6454L,  -5963L,  -5471L,  -4978L,  -4483L,  -3988L,  -3491L,  -2994L,
+   -2496L,  -1998L,  -1499L,   -999L,   -500L, 
+};
+
+static byte capidtmf_leading_zeroes_table[0x100] =
+{
+  8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#define capidtmf_byte_leading_zeroes(b)  (capidtmf_leading_zeroes_table[(BYTE)(b)])
+#define capidtmf_word_leading_zeroes(w)  (((w) & 0xff00) ? capidtmf_leading_zeroes_table[(w) >> 8] : 8 + capidtmf_leading_zeroes_table[(w)])
+#define capidtmf_dword_leading_zeroes(d)  (((d) & 0xffff0000L) ?    (((d) & 0xff000000L) ? capidtmf_leading_zeroes_table[(d) >> 24] : 8 + capidtmf_leading_zeroes_table[(d) >> 16]) :    (((d) & 0xff00) ? 16 + capidtmf_leading_zeroes_table[(d) >> 8] : 24 + capidtmf_leading_zeroes_table[(d)]))
+
+
+/*---------------------------------------------------------------------------*/
+
+
+static void capidtmf_goertzel_loop (long *buffer, long *coeffs, short *sample, long count)
+{
+  int i, j;
+  long c, d, q0, q1, q2;
+
+  for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - 1; i++)
+  {
+    q1 = buffer[i];
+    q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+    d = coeffs[i] >> 1;
+    c = d << 1;
+    if (c >= 0)
+    {
+      for (j = 0; j < count; j++)
+      {
+        q0 = sample[j] - q2 + (c * (q1 >> 16)) + (((dword)(((dword) d) * ((dword)(q1 & 0xffff)))) >> 15);
+        q2 = q1;
+        q1 = q0;
+      }
+    }
+    else
+    {
+      c = -c;
+      d = -d;
+      for (j = 0; j < count; j++)
+      {
+        q0 = sample[j] - q2 - ((c * (q1 >> 16)) + (((dword)(((dword) d) * ((dword)(q1 & 0xffff)))) >> 15));
+        q2 = q1;
+        q1 = q0;
+      }
+    }
+    buffer[i] = q1;
+    buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = q2;
+  }
+  q1 = buffer[i];
+  q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+  c = (coeffs[i] >> 1) << 1;
+  if (c >= 0)
+  {
+    for (j = 0; j < count; j++)
+    {
+      q0 = sample[j] - q2 + (c * (q1 >> 16)) + (((dword)(((dword)(c >> 1)) * ((dword)(q1 & 0xffff)))) >> 15);
+      q2 = q1;
+      q1 = q0;
+      c -= CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT;
+    }
+  }
+  else
+  {
+    c = -c;
+    for (j = 0; j < count; j++)
+    {
+      q0 = sample[j] - q2 - ((c * (q1 >> 16)) + (((dword)(((dword)(c >> 1)) * ((dword)(q1 & 0xffff)))) >> 15));
+      q2 = q1;
+      q1 = q0;
+      c += CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT;
+    }
+  }
+  coeffs[i] = c;
+  buffer[i] = q1;
+  buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = q2;
+}
+
+
+static void capidtmf_goertzel_result (long *buffer, long *coeffs)
+{
+  int i;
+  long d, e, q1, q2, lo, mid, hi;
+  dword k;
+
+  for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+  {
+    q1 = buffer[i];
+    q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+    d = coeffs[i] >> 1;
+    if (d >= 0)
+      d = ((d << 1) * (-q1 >> 16)) + (((dword)(((dword) d) * ((dword)(-q1 & 0xffff)))) >> 15);
+    else
+      d = ((-d << 1) * (-q1 >> 16)) + (((dword)(((dword) -d) * ((dword)(-q1 & 0xffff)))) >> 15);
+    e = (q2 >= 0) ? q2 : -q2;
+    if (d >= 0)
+    {
+      k = ((dword)(d & 0xffff)) * ((dword)(e & 0xffff));
+      lo = k & 0xffff;
+      mid = k >> 16;
+      k = ((dword)(d >> 16)) * ((dword)(e & 0xffff));
+      mid += k & 0xffff;
+      hi = k >> 16;
+      k = ((dword)(d & 0xffff)) * ((dword)(e >> 16));
+      mid += k & 0xffff;
+      hi += k >> 16;
+      hi += ((dword)(d >> 16)) * ((dword)(e >> 16));
+    }
+    else
+    {
+      d = -d;
+      k = ((dword)(d & 0xffff)) * ((dword)(e & 0xffff));
+      lo = -((long)(k & 0xffff));
+      mid = -((long)(k >> 16));
+      k = ((dword)(d >> 16)) * ((dword)(e & 0xffff));
+      mid -= k & 0xffff;
+      hi = -((long)(k >> 16));
+      k = ((dword)(d & 0xffff)) * ((dword)(e >> 16));
+      mid -= k & 0xffff;
+      hi -= k >> 16;
+      hi -= ((dword)(d >> 16)) * ((dword)(e >> 16));
+    }
+    if (q2 < 0)
+    {
+      lo = -lo;
+      mid = -mid;
+      hi = -hi;
+    }
+    d = (q1 >= 0) ? q1 : -q1;
+    k = ((dword)(d & 0xffff)) * ((dword)(d & 0xffff));
+    lo += k & 0xffff;
+    mid += k >> 16;
+    k = ((dword)(d >> 16)) * ((dword)(d & 0xffff));
+    mid += (k & 0xffff) << 1;
+    hi += (k >> 16) << 1;
+    hi += ((dword)(d >> 16)) * ((dword)(d >> 16));
+    d = (q2 >= 0) ? q2 : -q2;
+    k = ((dword)(d & 0xffff)) * ((dword)(d & 0xffff));
+    lo += k & 0xffff;
+    mid += k >> 16;
+    k = ((dword)(d >> 16)) * ((dword)(d & 0xffff));
+    mid += (k & 0xffff) << 1;
+    hi += (k >> 16) << 1;
+    hi += ((dword)(d >> 16)) * ((dword)(d >> 16));
+    mid += lo >> 16;
+    hi += mid >> 16;
+    buffer[i] = (lo & 0xffff) | (mid << 16);
+    buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = hi;
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_697     0
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_770     1
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_852     2
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_941     3
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1209    4
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1336    5
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1477    6
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1633    7
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_635     8
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1010    9
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1140    10
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1272    11
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1405    12
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1555    13
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1715    14
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1875    15
+
+#define CAPIDTMF_RECV_GUARD_SNR_DONTCARE      0xc000
+#define CAPIDTMF_RECV_NO_DIGIT                0xff
+#define CAPIDTMF_RECV_TIME_GRANULARITY        (CAPIDTMF_RECV_ACCUMULATE_CYCLES + 1)
+
+#define CAPIDTMF_RECV_INDICATION_DIGIT        0x0001
+
+static long capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
+{
+  0xda97L * 2,  /* 697 Hz (Low group 697 Hz) */
+  0xd299L * 2,  /* 770 Hz (Low group 770 Hz) */
+  0xc8cbL * 2,  /* 852 Hz (Low group 852 Hz) */
+  0xbd36L * 2,  /* 941 Hz (Low group 941 Hz) */
+  0x9501L * 2,  /* 1209 Hz (High group 1209 Hz) */
+  0x7f89L * 2,  /* 1336 Hz (High group 1336 Hz) */
+  0x6639L * 2,  /* 1477 Hz (High group 1477 Hz) */
+  0x48c6L * 2,  /* 1633 Hz (High group 1633 Hz) */
+  0xe14cL * 2,  /* 630 Hz (Lower guard of low group 631 Hz) */
+  0xb2e0L * 2,  /* 1015 Hz (Upper guard of low group 1039 Hz) */
+  0xa1a0L * 2,  /* 1130 Hz (Lower guard of high group 1140 Hz) */
+  0x8a87L * 2,  /* 1272 Hz (Guard between 1209 Hz and 1336 Hz: 1271 Hz) */
+  0x7353L * 2,  /* 1405 Hz (2nd harmonics of 697 Hz and guard between 1336 Hz and 1477 Hz: 1405 Hz) */
+  0x583bL * 2,  /* 1552 Hz (2nd harmonics of 770 Hz and guard between 1477 Hz and 1633 Hz: 1553 Hz) */
+  0x37d8L * 2,  /* 1720 Hz (2nd harmonics of 852 Hz and upper guard of high group: 1715 Hz) */
+  0x0000L * 2   /* 100-630 Hz (fundamentals) */
+};
+
+
+static word capidtmf_recv_guard_snr_low_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
+{
+  14,                                    /* Low group peak versus 697 Hz */
+  14,                                    /* Low group peak versus 770 Hz */
+  16,                                    /* Low group peak versus 852 Hz */
+  16,                                    /* Low group peak versus 941 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1209 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1336 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1477 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1633 Hz */
+  14,                                    /* Low group peak versus 635 Hz */
+  16,                                    /* Low group peak versus 1010 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1140 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1272 Hz */
+  DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 8,  /* Low group peak versus 1405 Hz */
+  DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4,  /* Low group peak versus 1555 Hz */
+  DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4,  /* Low group peak versus 1715 Hz */
+  12                                     /* Low group peak versus 100-630 Hz */
+};
+
+
+static word capidtmf_recv_guard_snr_high_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
+{
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 697 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 770 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 852 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 941 Hz */
+  20,                                    /* High group peak versus 1209 Hz */
+  20,                                    /* High group peak versus 1336 Hz */
+  20,                                    /* High group peak versus 1477 Hz */
+  20,                                    /* High group peak versus 1633 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 635 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 1010 Hz */
+  16,                                    /* High group peak versus 1140 Hz */
+  4,                                     /* High group peak versus 1272 Hz */
+  6,                                     /* High group peak versus 1405 Hz */
+  8,                                     /* High group peak versus 1555 Hz */
+  16,                                    /* High group peak versus 1715 Hz */
+  12                                     /* High group peak versus 100-630 Hz */
+};
+
+
+/*---------------------------------------------------------------------------*/
+
+static void capidtmf_recv_init (t_capidtmf_state   *p_state)
+{
+  p_state->recv.min_gap_duration = 1;
+  p_state->recv.min_digit_duration = 1;
+
+  p_state->recv.cycle_counter = 0;
+  p_state->recv.current_digit_on_time = 0;
+  p_state->recv.current_digit_off_time = 0;
+  p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT;
+
+  p_state->recv.digit_write_pos = 0;
+  p_state->recv.digit_read_pos = 0;
+  p_state->recv.indication_state = 0;
+  p_state->recv.indication_state_ack = 0;
+  p_state->recv.state = CAPIDTMF_RECV_STATE_IDLE;
+}
+
+
+void capidtmf_recv_enable (t_capidtmf_state   *p_state, word min_digit_duration, word min_gap_duration)
+{
+  p_state->recv.indication_state_ack &= CAPIDTMF_RECV_INDICATION_DIGIT;
+  p_state->recv.min_digit_duration = (word)(((((dword) min_digit_duration) * 8) +
+    ((dword)(CAPIDTMF_RECV_TIME_GRANULARITY / 2))) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY));
+  if (p_state->recv.min_digit_duration <= 1)
+    p_state->recv.min_digit_duration = 1;
+  else
+    (p_state->recv.min_digit_duration)--;
+  p_state->recv.min_gap_duration =
+    (word)((((dword) min_gap_duration) * 8) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY));
+  if (p_state->recv.min_gap_duration <= 1)
+    p_state->recv.min_gap_duration = 1;
+  else
+    (p_state->recv.min_gap_duration)--;
+  p_state->recv.state |= CAPIDTMF_RECV_STATE_DTMF_ACTIVE;
+}
+
+
+void capidtmf_recv_disable (t_capidtmf_state   *p_state)
+{
+  p_state->recv.state &= ~CAPIDTMF_RECV_STATE_DTMF_ACTIVE;
+  if (p_state->recv.state == CAPIDTMF_RECV_STATE_IDLE)
+    capidtmf_recv_init (p_state);
+  else
+  {
+    p_state->recv.cycle_counter = 0;
+    p_state->recv.current_digit_on_time = 0;
+    p_state->recv.current_digit_off_time = 0;
+    p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT;
+  }
+}
+
+
+word capidtmf_recv_indication (t_capidtmf_state   *p_state, byte *buffer)
+{
+  word i, j, k, flags;
+
+  flags = p_state->recv.indication_state ^ p_state->recv.indication_state_ack;
+  p_state->recv.indication_state_ack ^= flags & CAPIDTMF_RECV_INDICATION_DIGIT;
+  if (p_state->recv.digit_write_pos != p_state->recv.digit_read_pos)
+  {
+    i = 0;
+    k = p_state->recv.digit_write_pos;
+    j = p_state->recv.digit_read_pos;
+    do
+    {
+      buffer[i++] = p_state->recv.digit_buffer[j];
+      j = (j == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ? 0 : j + 1;
+    } while (j != k);
+    p_state->recv.digit_read_pos = k;
+    return (i);
+  }
+  p_state->recv.indication_state_ack ^= flags;
+  return (0);
+}
+
+
+#define CAPIDTMF_RECV_WINDOWED_SAMPLES  32
+
+void capidtmf_recv_block (t_capidtmf_state   *p_state, byte   *buffer, word length)
+{
+  byte result_digit;
+  word sample_number, cycle_counter, n, i;
+  word low_peak, high_peak;
+  dword lo, hi;
+  byte   *p;
+  short *q;
+  byte goertzel_result_buffer[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+    short windowed_sample_buffer[CAPIDTMF_RECV_WINDOWED_SAMPLES];
+
+
+  if (p_state->recv.state & CAPIDTMF_RECV_STATE_DTMF_ACTIVE)
+  {
+    cycle_counter = p_state->recv.cycle_counter;
+    sample_number = 0;
+    while (sample_number < length)
+    {
+      if (cycle_counter < CAPIDTMF_RECV_ACCUMULATE_CYCLES)
+      {
+        if (cycle_counter == 0)
+        {
+          for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+          {
+            p_state->recv.goertzel_buffer[0][i] = 0;
+            p_state->recv.goertzel_buffer[1][i] = 0;
+          }
+        }
+        n = CAPIDTMF_RECV_ACCUMULATE_CYCLES - cycle_counter;
+        if (n > length - sample_number)
+          n = length - sample_number;
+        if (n > CAPIDTMF_RECV_WINDOWED_SAMPLES)
+          n = CAPIDTMF_RECV_WINDOWED_SAMPLES;
+        p = buffer + sample_number;
+        q = capidtmf_recv_window_function + cycle_counter;
+        if (p_state->ulaw)
+        {
+          for (i = 0; i < n; i++)
+          {
+            windowed_sample_buffer[i] =
+              (short)((capidtmf_expand_table_ulaw[p[i]] * ((long)(q[i]))) >> 15);
+	  }
+        }
+        else
+        {
+          for (i = 0; i < n; i++)
+          {
+            windowed_sample_buffer[i] =
+              (short)((capidtmf_expand_table_alaw[p[i]] * ((long)(q[i]))) >> 15);
+	  }
+        }
+        capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - 1] = CAPIDTMF_RECV_FUNDAMENTAL_OFFSET;
+        capidtmf_goertzel_loop (p_state->recv.goertzel_buffer[0],
+          capidtmf_recv_goertzel_coef_table, windowed_sample_buffer, n);
+        cycle_counter += n;
+        sample_number += n;
+      }
+      else
+      {
+        capidtmf_goertzel_result (p_state->recv.goertzel_buffer[0],
+          capidtmf_recv_goertzel_coef_table);
+        for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+        {
+          lo = (dword)(p_state->recv.goertzel_buffer[0][i]);
+          hi = (dword)(p_state->recv.goertzel_buffer[1][i]);
+          if (hi != 0)
+          {
+            n = capidtmf_dword_leading_zeroes (hi);
+            hi = (hi << n) | (lo >> (32 - n));
+          }
+          else
+          {
+            n = capidtmf_dword_leading_zeroes (lo);
+            hi = lo << n;
+	    n += 32;
+          }
+          n = 195 - 3 * n;
+          if (hi >= 0xcb300000L)
+            n += 2;
+          else if (hi >= 0xa1450000L)
+            n++;
+	  goertzel_result_buffer[i] = (byte) n;
+        }
+        low_peak = DSPDTMF_RX_SENSITIVITY_LOW_DEFAULT;
+        result_digit = CAPIDTMF_RECV_NO_DIGIT;
+        for (i = 0; i < CAPIDTMF_LOW_GROUP_FREQUENCIES; i++)
+        {
+          if (goertzel_result_buffer[i] > low_peak)
+	  {
+	    low_peak = goertzel_result_buffer[i];
+	    result_digit = (byte) i;
+	  }
+        }
+        high_peak = DSPDTMF_RX_SENSITIVITY_HIGH_DEFAULT;
+        n = CAPIDTMF_RECV_NO_DIGIT;
+        for (i = CAPIDTMF_LOW_GROUP_FREQUENCIES; i < CAPIDTMF_RECV_BASE_FREQUENCY_COUNT; i++)
+        {
+          if (goertzel_result_buffer[i] > high_peak)
+	  {
+	    high_peak = goertzel_result_buffer[i];
+	    n = (i - CAPIDTMF_LOW_GROUP_FREQUENCIES) << 2;
+	  }
+        }
+        result_digit |= (byte) n;
+        if (low_peak + DSPDTMF_RX_HIGH_EXCEEDING_LOW_DEFAULT < high_peak)
+          result_digit = CAPIDTMF_RECV_NO_DIGIT;
+        if (high_peak + DSPDTMF_RX_LOW_EXCEEDING_HIGH_DEFAULT < low_peak)
+          result_digit = CAPIDTMF_RECV_NO_DIGIT;
+        n = 0;
+        for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+        {
+          if ((((short)(low_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_low_table[i])) < 0)
+           || (((short)(high_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_high_table[i])) < 0))
+	  {
+	    n++;
+	  }
+        }
+        if (n != 2)
+          result_digit = CAPIDTMF_RECV_NO_DIGIT;
+
+        if (result_digit == CAPIDTMF_RECV_NO_DIGIT)
+        {
+          if (p_state->recv.current_digit_on_time != 0)
+          {
+            if (++(p_state->recv.current_digit_off_time) >= p_state->recv.min_gap_duration)
+            {
+              p_state->recv.current_digit_on_time = 0;
+              p_state->recv.current_digit_off_time = 0;
+            }
+          }
+          else
+          {
+            if (p_state->recv.current_digit_off_time != 0)
+              (p_state->recv.current_digit_off_time)--;
+          }
+        }
+        else
+        {
+          if ((p_state->recv.current_digit_on_time == 0)
+           && (p_state->recv.current_digit_off_time != 0))
+          {
+            (p_state->recv.current_digit_off_time)--;
+          }
+          else
+          {
+            n = p_state->recv.current_digit_off_time;
+            if ((p_state->recv.current_digit_on_time != 0)
+             && (result_digit != p_state->recv.current_digit_value))
+            {
+              p_state->recv.current_digit_on_time = 0;
+              n = 0;
+            }
+            p_state->recv.current_digit_value = result_digit;
+            p_state->recv.current_digit_off_time = 0;
+            if (p_state->recv.current_digit_on_time != 0xffff)
+            {
+              p_state->recv.current_digit_on_time += n + 1;
+              if (p_state->recv.current_digit_on_time >= p_state->recv.min_digit_duration)
+              {
+                p_state->recv.current_digit_on_time = 0xffff;
+                i = (p_state->recv.digit_write_pos == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ?
+                  0 : p_state->recv.digit_write_pos + 1;
+                if (i == p_state->recv.digit_read_pos)
+                {
+                  trace (dprintf ("%s,%d: Receive digit overrun",
+                    (char   *)(FILE_), __LINE__));
+                }
+                else
+                {
+                  p_state->recv.digit_buffer[p_state->recv.digit_write_pos] = result_digit;
+                  p_state->recv.digit_write_pos = i;
+                  p_state->recv.indication_state =
+                    (p_state->recv.indication_state & ~CAPIDTMF_RECV_INDICATION_DIGIT) |
+                    (~p_state->recv.indication_state_ack & CAPIDTMF_RECV_INDICATION_DIGIT);
+                }
+              }
+            }
+          }
+        }
+        cycle_counter = 0;
+        sample_number++;
+      }
+    }
+    p_state->recv.cycle_counter = cycle_counter;
+  }
+}
+
+
+void capidtmf_init (t_capidtmf_state   *p_state, byte ulaw)
+{
+  p_state->ulaw = ulaw;
+  capidtmf_recv_init (p_state);
+}
+
+
+/*---------------------------------------------------------------------------*/
diff -Nru a/drivers/isdn/hardware/eicon/capidtmf.h b/drivers/isdn/hardware/eicon/capidtmf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/capidtmf.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,79 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef CAPIDTMF_H_  
+#define CAPIDTMF_H_
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+#define CAPIDTMF_TONE_GROUP_COUNT            2
+#define CAPIDTMF_LOW_GROUP_FREQUENCIES       4
+#define CAPIDTMF_HIGH_GROUP_FREQUENCIES      4
+#define DSPDTMF_RX_SENSITIVITY_LOW_DEFAULT	50	/* -52 dBm */
+#define DSPDTMF_RX_SENSITIVITY_HIGH_DEFAULT	50	/* -52 dBm */
+#define DSPDTMF_RX_HIGH_EXCEEDING_LOW_DEFAULT	10	/* dB */
+#define DSPDTMF_RX_LOW_EXCEEDING_HIGH_DEFAULT	10	/* dB */
+#define DSPDTMF_RX_HARMONICS_SEL_DEFAULT	12	/* dB */
+#define CAPIDTMF_RECV_BASE_FREQUENCY_COUNT   (CAPIDTMF_LOW_GROUP_FREQUENCIES + CAPIDTMF_HIGH_GROUP_FREQUENCIES)
+#define CAPIDTMF_RECV_GUARD_FREQUENCY_COUNT  8
+#define CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT  (CAPIDTMF_RECV_BASE_FREQUENCY_COUNT + CAPIDTMF_RECV_GUARD_FREQUENCY_COUNT)
+#define CAPIDTMF_RECV_POSITIVE_COEFF_COUNT   16
+#define CAPIDTMF_RECV_NEGATIVE_COEFF_COUNT   (CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - CAPIDTMF_RECV_POSITIVE_COEFF_COUNT)
+#define CAPIDTMF_RECV_ACCUMULATE_CYCLES      205
+#define CAPIDTMF_RECV_FUNDAMENTAL_OFFSET     (0xff35L * 2)
+#define CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT  (0x0028L * 2)
+#define CAPIDTMF_RECV_DIGIT_BUFFER_SIZE      32
+#define CAPIDTMF_RECV_STATE_IDLE             0x00
+#define CAPIDTMF_RECV_STATE_DTMF_ACTIVE      0x01
+typedef struct tag_capidtmf_recv_state
+{
+  byte digit_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE];
+  word digit_write_pos;
+  word digit_read_pos;
+  word indication_state;
+  word indication_state_ack;
+  long goertzel_buffer[2][CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+  word min_gap_duration;
+  word min_digit_duration;
+  word cycle_counter;
+  word current_digit_on_time;
+  word current_digit_off_time;
+  byte current_digit_value;
+  byte state;
+} t_capidtmf_recv_state;
+typedef struct tag_capidtmf_state
+{
+  byte ulaw;
+  t_capidtmf_recv_state recv;
+} t_capidtmf_state;
+word capidtmf_recv_indication (t_capidtmf_state   *p_state, byte *buffer);
+void capidtmf_recv_block (t_capidtmf_state   *p_state, byte   *buffer, word length);
+void capidtmf_init (t_capidtmf_state   *p_state, byte ulaw);
+void capidtmf_recv_enable (t_capidtmf_state   *p_state, word min_digit_duration, word min_gap_duration);
+void capidtmf_recv_disable (t_capidtmf_state   *p_state);
+#define capidtmf_indication(p_state,buffer)  (((p_state)->recv.indication_state != (p_state)->recv.indication_state_ack) ?    capidtmf_recv_indication (p_state, buffer) : 0)
+#define capidtmf_recv_process_block(p_state,buffer,length)  { if ((p_state)->recv.state != CAPIDTMF_RECV_STATE_IDLE) capidtmf_recv_block (p_state, buffer, length); }
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+#endif  
diff -Nru a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/capifunc.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1290 @@
+/* $Id: capifunc.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface common functions
+ * 
+ * Copyright 2000-2002 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "platform.h"
+#include "os_capi.h"
+#include "di_defs.h"
+#include "capi20.h"
+#include "divacapi.h"
+#include "divasync.h"
+#include "capifunc.h"
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+static DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL;
+static APPL *application = (APPL *) NULL;
+byte max_appl = MAX_APPL;
+static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL;
+
+byte UnMapController(byte);
+char DRIVERRELEASE[32];
+
+extern void AutomaticLaw(DIVA_CAPI_ADAPTER *);
+extern void callback (ENTITY *);
+extern word api_remove_start(void);
+extern word CapiRelease(word);
+extern word CapiRegister(word);
+extern word api_put (APPL *, CAPI_MSG *);
+
+static diva_os_spin_lock_t api_lock;
+static diva_os_spin_lock_t ll_lock;
+
+static diva_card *cards;
+static dword notify_handle;
+static void DIRequest (ENTITY* e);
+static DESCRIPTOR MAdapter;
+static DESCRIPTOR DAdapter;
+static byte max_adapter = 0;
+static byte ControllerMap[MAX_DESCRIPTORS + 1];
+
+
+static void diva_register_appl(struct capi_ctr *, __u16 , capi_register_params *);
+static void diva_release_appl(struct capi_ctr *, __u16);
+static char *diva_procinfo(struct capi_ctr *);
+static u16 diva_send_message(struct capi_ctr *, diva_os_message_buffer_s *);
+extern void diva_os_set_controller_struct(struct capi_ctr *);
+
+extern void DIVA_DIDD_Read(DESCRIPTOR *, int);
+
+static void no_printf (unsigned char *, ...);
+
+DIVA_DI_PRINTF dprintf = no_printf;
+
+/*
+ * debug
+ */
+#include "debuglib.c"
+void xlog (char * x, ...)
+{
+  va_list ap;
+  if ( myDriverDebugHandle.dbgMask & DL_XLOG )
+  {
+    va_start (ap, x) ;
+    if ( myDriverDebugHandle.dbg_irq )
+    {
+      myDriverDebugHandle.dbg_irq (myDriverDebugHandle.id, DLI_XLOG, x, ap);
+    }
+    else if ( myDriverDebugHandle.dbg_old )
+    {
+      myDriverDebugHandle.dbg_old (myDriverDebugHandle.id, x, ap) ;
+    }
+    va_end (ap) ;
+  }
+}
+
+/*
+ * info for proc
+ */
+static char *diva_procinfo(struct capi_ctr *ctrl)
+{
+		return(ctrl->serial);
+} 
+
+/*
+ * stop debugging
+ */
+static void stop_dbg(void)
+{
+		DbgDeregister();
+		memset(&MAdapter, 0, sizeof(MAdapter));
+		dprintf = no_printf;
+}
+
+/*
+ * dummy debug function
+ */
+static void no_printf (unsigned char * x ,...)
+{
+}
+
+/*
+ * Controller mapping
+ */
+static byte MapController(byte Controller)
+{
+  byte i;
+  byte MappedController = 0;
+  byte ctrl = Controller & 0x7f;  /* mask external controller bit off */
+
+  for (i = 1; i < max_adapter + 1; i++)
+  {
+    if (ctrl == ControllerMap[i])
+    {
+      MappedController = (byte) i;
+      break;
+    }
+  }
+  if (i > max_adapter)
+  {
+    ControllerMap[0] = ctrl;
+    MappedController = 0;
+  }
+  return (MappedController | (Controller & 0x80)); /* put back external controller bit */
+}
+
+/*
+ * Controller unmapping
+ */
+byte UnMapController(byte MappedController)
+{
+  byte Controller;
+  byte ctrl = MappedController & 0x7f;  /* mask external controller bit off */
+
+  if (ctrl <= max_adapter)
+  {
+    Controller = ControllerMap[ctrl];
+  }
+  else
+  {
+    Controller = 0;
+  }
+
+  return (Controller | (MappedController & 0x80)); /* put back external controller bit */
+}
+
+/*
+ * find a new free id
+ */
+static int find_free_id(void)
+{
+  int num = 0;
+  diva_card *p;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "find free id");
+  while(num < 100) {
+    num++;
+    p = cards;
+    while (p) {
+      if (p->Id == num)
+        goto next_id;
+      p = p->next;
+    }
+		diva_os_leave_spin_lock (&ll_lock, &old_irql, "find free id");
+    return(num);
+next_id:
+  }
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "find free id");
+  return(999);
+}
+
+/*
+ * find a card structure by controller number
+ */
+static diva_card * find_card_by_ctrl(word controller)
+{
+  diva_card *p;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "find card ctrl");
+  p = cards;
+
+  while (p) {
+    if (ControllerMap[p->Id] == controller) {
+			diva_os_leave_spin_lock (&ll_lock, &old_irql, "find card ctrl");
+      return p;
+    }
+    p = p->next;
+  }
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "find card ctrl");
+  return (diva_card *) 0;
+}
+
+/*
+ * Buffer RX/TX 
+ */
+void *TransmitBufferSet(APPL *appl, dword ref)
+{
+  appl->xbuffer_used[ref] = TRUE;
+  DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1))
+  return (void *) ref;
+}
+
+void *TransmitBufferGet(APPL *appl, void *p)
+{
+  if(appl->xbuffer_internal[(dword)p])
+    return appl->xbuffer_internal[(dword)p];
+
+  return appl->xbuffer_ptr[(dword)p];
+}
+
+void TransmitBufferFree(APPL *appl, void *p)
+{
+  appl->xbuffer_used[(dword) p] = FALSE;
+  DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword) p) + 1))
+}
+
+void *ReceiveBufferGet(APPL *appl, int Num)
+{
+  return &appl->ReceiveBuffer[Num * appl->MaxDataLength];
+}
+
+/*
+ * api_remove_start/complete for cleanup
+ */
+void api_remove_complete(void)
+{
+    DBG_PRV1(("api_remove_complete"))
+}
+
+/*
+ * main function called by message.c
+ */
+void sendf(APPL *appl, word command, dword Id, word Number, byte *format, ...)
+{
+  word i, j;
+  word length = 12, dlength = 0;
+  byte *write;
+  CAPI_MSG msg;
+  byte *string = 0;
+  va_list ap;
+  diva_os_message_buffer_s *dmb;
+  diva_card *card = NULL;
+  dword tmp;
+
+  if(!appl) return;
+
+  DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)",
+             appl->Id,command,(byte *)format))
+
+  WRITE_WORD(&msg.header.appl_id, appl->Id);
+  WRITE_WORD(&msg.header.command, command);
+  if((byte)(command>>8) == 0x82)
+    Number = appl->Number++;
+  WRITE_WORD(&msg.header.number, Number);
+
+  WRITE_DWORD(((byte *)&msg.header.controller), Id);
+  write = (byte *) &msg;
+  write += 12;
+
+  va_start(ap,format);
+  for(i=0; format[i]; i++) {
+    switch(format[i]) {
+      case 'b':
+        tmp = va_arg(ap,dword);
+        *(byte *)write = (byte)(tmp & 0xff);
+        write += 1;
+        length += 1;
+        break;
+      case 'w':
+        tmp = va_arg(ap,dword);
+        WRITE_WORD (write, (tmp & 0xffff));
+        write += 2;
+        length += 2;
+        break;
+      case 'd':
+        tmp = va_arg(ap,dword);
+        WRITE_DWORD(write, tmp);
+        write += 4;
+        length += 4;
+        break;
+      case 's':
+      case 'S':
+        string = va_arg(ap,byte *);
+        length += string[0]+1;
+        for(j = 0; j <= string[0]; j++)
+          *write++ = string[j];
+        break;
+    }
+  }
+  va_end(ap);
+
+  WRITE_WORD(&msg.header.length, length);
+  msg.header.controller = UnMapController(msg.header.controller);
+
+  if (command == _DATA_B3_I)
+    dlength = READ_WORD(((byte*)&msg.info.data_b3_ind.Data_Length));
+
+	if (!(dmb = diva_os_alloc_message_buffer(length + dlength, (void **)&write))) {
+    DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped."))
+    return;
+  }
+	
+  /* copy msg header to sk_buff */
+  memcpy(write, (byte *)&msg, length);
+
+  /* if DATA_B3_IND, copy data too */
+  if (command == _DATA_B3_I) {
+    dword data = READ_DWORD(((byte*)&msg.info.data_b3_ind.Data));
+    memcpy (write + length, (void *)data, dlength);
+  }
+
+  if ( myDriverDebugHandle.dbgMask & DL_XLOG )
+  {
+    switch ( command )
+    {
+      default:
+        xlog ("\x00\x02", &msg, 0x81, length) ;
+        break ;
+       case _DATA_B3_R|CONFIRM:
+        if ( myDriverDebugHandle.dbgMask & DL_BLK)
+          xlog ("\x00\x02", &msg, 0x81, length) ;
+        break ;
+       case _DATA_B3_I:
+        if ( myDriverDebugHandle.dbgMask & DL_BLK)
+        {
+          xlog ("\x00\x02", &msg, 0x81, length) ;
+          for (i = 0; i < dlength; i += 256)
+          {
+            DBG_BLK((((char *)msg.info.data_b3_ind.Data) + i,
+              ((dlength - i) < 256) ?
+               (dlength - i) : 256  ))
+            if ( !(myDriverDebugHandle.dbgMask & DL_PRV0) )
+              break ; // not more if not explicitely requested
+          }
+        }
+        break ;
+    }
+  }
+
+  /* find the card structure for this controller */
+  if(!(card = find_card_by_ctrl(write[8] & 0x7f))) {
+    DBG_ERR(("sendf - controller %d not found, incoming msg dropped", write[8] & 0x7f))
+    diva_os_free_message_buffer(dmb);
+    return;
+  }
+    
+  /* send capi msg to capi layer */
+	capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb);
+}
+
+/*
+ * cleanup adapter
+ */
+static void clean_adapter(int id)
+{
+  DIVA_CAPI_ADAPTER *a;
+#if IMPLEMENT_LINE_INTERCONNECT2
+  int i, k;
+#endif /* IMPLEMENT_LINE_INTERCONNECT2 */
+
+  a = &adapter[id];
+#if IMPLEMENT_LINE_INTERCONNECT
+  if (a->li_pri)
+    {
+      if(a->li_config.pri)
+        diva_os_free(0, a->li_config.pri);
+    }
+  else
+    {
+      if(a->li_config.bri)
+        diva_os_free(0, a->li_config.bri);
+    }
+#endif /* IMPLEMENT_LINE_INTERCONNECT */
+#if IMPLEMENT_LINE_INTERCONNECT2
+  k = li_total_channels - a->li_channels;
+  if (k == 0)
+  {
+    diva_os_free(0, li_config_table);
+    li_config_table = NULL;
+  }
+  else
+  {
+    if (a->li_base < k)
+    {
+      memmove(&li_config_table[a->li_base],
+              &li_config_table[a->li_base + a->li_channels],
+              (k - a->li_base) * sizeof(LI_CONFIG));
+      for (i = 0; i < k; i++)
+      {
+        memmove(&li_config_table[i].flag_table[a->li_base],
+                &li_config_table[i].flag_table[a->li_base + a->li_channels],
+                k - a->li_base);
+        memmove(&li_config_table[i].coef_table[a->li_base],
+                &li_config_table[i].coef_table[a->li_base + a->li_channels],
+                k - a->li_base);
+      }
+    }
+  }
+  li_total_channels = k;
+  for (i = id; i < max_adapter; i++)
+  {
+    if (adapter[i].request)
+      adapter[i].li_base -= a->li_channels;
+  }
+#endif /* IMPLEMENT_LINE_INTERCONNECT2 */
+  if(a->plci)
+    diva_os_free(0, a->plci);
+
+  memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER));
+  while ((max_adapter != 0) && !adapter[max_adapter - 1].request)
+    max_adapter--;
+}
+
+/*
+ * remove cards
+ */
+static void DIVA_EXIT_FUNCTION divacapi_remove_cards(void)
+{
+  diva_card *last;
+  diva_card *card;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "remove cards");
+  card = cards;
+
+  while(card) {
+		detach_capi_ctr(&card->capi_ctrl);
+    clean_adapter(card->Id - 1);
+    DBG_TRC(("adapter remove, max_adapter=%d", max_adapter));
+    card = card->next;
+  }
+
+  card = cards;
+  while (card) {
+    last = card;
+    card = card->next;
+    diva_os_free(0, last);
+  }
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "remove cards");
+}
+
+/*
+ * remove a card
+ */
+static void divacapi_remove_card(DESCRIPTOR *d)
+{
+  diva_card *last;
+  diva_card *card;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "remove card");
+  last = card = cards;
+  while(card) {
+    if (card->d.request == d->request)
+    {
+			detach_capi_ctr(&card->capi_ctrl);
+      clean_adapter(card->Id - 1);
+      DBG_TRC(("DelAdapterMap (%d) -> (%d)", ControllerMap[card->Id], card->Id))
+      ControllerMap[card->Id] = 0;
+      DBG_TRC(("adapter remove, max_adapter=%d", max_adapter));
+      if (card == last)
+        cards = card->next;
+      else
+        last->next = card->next;
+
+      diva_os_free(0, card);
+      break;
+    }
+    last = card;
+    card = card->next;
+  }
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "remove card");
+}
+
+/*
+ * sync_callback
+ */
+static void sync_callback(ENTITY *e)
+{
+	diva_os_spin_lock_magic_t old_irql;
+
+	DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind))
+
+	diva_os_enter_spin_lock (&api_lock, &old_irql, "sync_callback");
+	callback(e);
+	diva_os_leave_spin_lock (&api_lock, &old_irql, "sync_callback");
+} 
+
+/*
+ * add a new card
+ */
+static int diva_add_card(DESCRIPTOR *d)
+{
+  int k = 0, i = 0;
+	diva_os_spin_lock_magic_t old_irql;
+  diva_card *card = NULL;
+  struct capi_ctr *ctrl = NULL;
+  DIVA_CAPI_ADAPTER *a = NULL;
+  IDI_SYNC_REQ sync_req;
+  char serial[16];
+#if IMPLEMENT_LINE_INTERCONNECT2
+  LI_CONFIG *new_li_config_table;
+  int j;
+#endif /* IMPLEMENT_LINE_INTERCONNECT2 */
+
+  if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) {
+    DBG_ERR(("diva_add_card: failed to allocate card struct."))
+    return(0);
+  }
+  memset((char *)card, 0x00, sizeof(diva_card));
+  memcpy(&card->d, d, sizeof(DESCRIPTOR));
+  sync_req.GetName.Req = 0;
+  sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
+  card->d.request((ENTITY *)&sync_req);
+  strncpy(card->name, sync_req.GetName.name, sizeof(card->name));
+  ctrl = &card->capi_ctrl;
+	strcpy(ctrl->name, card->name);
+	ctrl->register_appl = diva_register_appl;
+	ctrl->release_appl  = diva_release_appl;
+	ctrl->send_message  = diva_send_message;
+	ctrl->procinfo      = diva_procinfo;
+	ctrl->driverdata    = card;
+	diva_os_set_controller_struct(ctrl);
+
+	if (attach_capi_ctr(ctrl)) {
+			DBG_ERR(("diva_add_card: failed to attach controller."))
+			diva_os_free(0, card);
+			return(0);
+	}
+  card->Id = find_free_id();
+  strncpy(ctrl->manu, M_COMPANY, CAPI_MANUFACTURER_LEN);
+  ctrl->version.majorversion = 2;
+  ctrl->version.minorversion = 0;
+  ctrl->version.majormanuversion = DRRELMAJOR;
+  ctrl->version.minormanuversion = DRRELMINOR;
+  sync_req.GetSerial.Req = 0;
+  sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
+  sync_req.GetSerial.serial = 0;
+  card->d.request((ENTITY *)&sync_req);
+  if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) {
+    sprintf(serial, "%ld-%d",
+            sync_req.GetSerial.serial & 0x00ffffff, i + 1);
+  } else {
+    sprintf(serial, "%ld", sync_req.GetSerial.serial);
+  }
+  serial[CAPI_SERIAL_LEN-1] = 0;
+  strncpy(ctrl->serial, serial, CAPI_SERIAL_LEN);
+
+  a = &adapter[card->Id - 1];
+  card->adapter = a;
+  a->os_card = card;
+  ControllerMap[card->Id] = (byte)(ctrl->cnr);
+
+  DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id))
+
+  sync_req.xdi_capi_prms.Req = 0;
+  sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS;
+  sync_req.xdi_capi_prms.info.structure_length = sizeof(diva_xdi_get_capi_parameters_t);
+  card->d.request((ENTITY *)&sync_req);
+  a->flag_dynamic_l1_down = sync_req.xdi_capi_prms.info.flag_dynamic_l1_down;
+  a->group_optimization_enabled = sync_req.xdi_capi_prms.info.group_optimization_enabled;
+  a->request = DIRequest; /* card->d.request; */
+  a->max_plci = card->d.channels + 30;
+  a->max_listen = (card->d.channels > 2) ? 8 : 2;
+  if (!(a->plci = (PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) {
+    DBG_ERR(("diva_add_card: failed alloc plci struct."))
+    memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
+    return(0);
+  }
+  memset(a->plci, 0, sizeof(PLCI) * a->max_plci);
+
+  for (k = 0; k < a->max_plci; k++)
+    {
+      a->Id = (byte)card->Id;
+      a->plci[k].Sig.callback = sync_callback;
+      a->plci[k].Sig.XNum = 1;
+      a->plci[k].Sig.X = a->plci[k].XData;
+      a->plci[k].Sig.user[0] = (word) (card->Id - 1);
+      a->plci[k].Sig.user[1] = (word) k;
+      a->plci[k].NL.callback = sync_callback;
+      a->plci[k].NL.XNum = 1;
+      a->plci[k].NL.X = a->plci[k].XData;
+      a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000);
+      a->plci[k].NL.user[1] = (word) k;
+      a->plci[k].adapter = a;
+    }
+
+  a->profile.Number = card->Id;
+  a->profile.Channels = card->d.channels;
+  if (card->d.features & DI_FAX3)
+    {
+      a->profile.Global_Options = 0x71;
+      if (card->d.features & DI_CODEC)
+        a->profile.Global_Options |= 0x6;
+#if IMPLEMENT_DTMF
+      a->profile.Global_Options |= 0x8;
+#endif /* IMPLEMENT_DTMF */
+#if (IMPLEMENT_LINE_INTERCONNECT || IMPLEMENT_LINE_INTERCONNECT2)
+      a->profile.Global_Options |= 0x80;
+#endif /* (IMPLEMENT_LINE_INTERCONNECT || IMPLEMENT_LINE_INTERCONNECT2) */
+#if IMPLEMENT_ECHO_CANCELLER
+      a->profile.Global_Options |= 0x100;
+#endif /* IMPLEMENT_ECHO_CANCELLER */
+      a->profile.B1_Protocols = 0xdf;
+      a->profile.B2_Protocols = 0x1fdb;
+      a->profile.B3_Protocols = 0xb7;
+      a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF;
+    }
+  else
+    {
+      a->profile.Global_Options = 0x71;
+      if (card->d.features & DI_CODEC)
+        a->profile.Global_Options |= 0x2;
+      a->profile.B1_Protocols = 0x43;
+      a->profile.B2_Protocols = 0x1f0f;
+      a->profile.B3_Protocols = 0x07;
+      a->manufacturer_features = 0;
+    }
+
+#if IMPLEMENT_LINE_INTERCONNECT
+  a->li_pri = (a->profile.Channels > 2);
+  if (a->li_pri)
+    {
+      if (!(a->li_config.pri = (LI_CONFIG_PRI *) diva_os_malloc(0, sizeof(LI_CONFIG_PRI)))) {
+        DBG_ERR(("diva_add_card: failed alloc li_config.pri struct."))
+        memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
+        return(0);
+      }
+      memset(a->li_config.pri, 0, sizeof(LI_CONFIG_PRI));
+    }
+  else
+    {
+      if (!(a->li_config.bri = (LI_CONFIG_BRI *) diva_os_malloc(0, sizeof(LI_CONFIG_BRI)))) {
+        DBG_ERR(("diva_add_card: failed alloc li_config.bri struct."))
+        memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
+        return(0);
+      }
+      memset(a->li_config.bri, 0, sizeof(LI_CONFIG_BRI));
+    }
+#endif /* IMPLEMENT_LINE_INTERCONNECT */
+#if IMPLEMENT_LINE_INTERCONNECT2
+  a->li_pri = (a->profile.Channels > 2);
+  a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI;
+  a->li_base = 0;
+  for (i = 0; &adapter[i] != a; i++)
+  {
+    if (adapter[i].request)
+      a->li_base = adapter[i].li_base + adapter[i].li_channels;
+  }
+  k = li_total_channels + a->li_channels;
+  new_li_config_table = (LI_CONFIG *) diva_os_malloc(0,
+    ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3));
+  if (new_li_config_table == NULL)
+  {
+    DBG_ERR(("diva_add_card: failed alloc li_config table."))
+    memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
+    return(0);
+  }
+  j = 0;
+  for (i = 0; i < k; i++)
+  {
+    if ((i >= a->li_base) && (i < a->li_base + a->li_channels))
+      memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG));
+    else
+      memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG));
+    new_li_config_table[i].flag_table = ((byte *) new_li_config_table) +
+      (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3));
+    new_li_config_table[i].coef_table = ((byte *) new_li_config_table) +
+      (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3));
+    if ((i >= a->li_base) && (i < a->li_base + a->li_channels))
+    {
+      new_li_config_table[i].adapter = a;
+      memset(&new_li_config_table[i].flag_table[0], 0, k);
+      memset(&new_li_config_table[i].coef_table[0], 0, k);
+    }
+    else
+    {
+      if (a->li_base != 0)
+      {
+        memcpy(&new_li_config_table[i].flag_table[0],
+               &li_config_table[j].flag_table[0],
+               a->li_base);
+        memcpy(&new_li_config_table[i].coef_table[0],
+               &li_config_table[j].coef_table[0],
+               a->li_base);
+      }
+      memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels);
+      memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels);
+      if (a->li_base + a->li_channels < k)
+      {
+        memcpy(&new_li_config_table[i].flag_table[a->li_base + a->li_channels],
+               &li_config_table[j].flag_table[a->li_base],
+               k - (a->li_base + a->li_channels));
+        memcpy(&new_li_config_table[i].coef_table[a->li_base + a->li_channels],
+               &li_config_table[j].coef_table[a->li_base],
+               k - (a->li_base + a->li_channels));
+      }
+      j++;
+    }
+  }
+  li_total_channels = k;
+
+  if (li_config_table != NULL)
+    diva_os_free(0, li_config_table);
+		
+  li_config_table = new_li_config_table;
+  for (i = card->Id; i < max_adapter; i++)
+  {
+    if (adapter[i].request)
+      adapter[i].li_base += a->li_channels;
+  }
+#endif /* IMPLEMENT_LINE_INTERCONNECT2 */
+
+  if (a == &adapter[max_adapter])
+    max_adapter++;
+		
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "add card");
+	card->next = cards;
+	cards = card;
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "add card");
+
+  AutomaticLaw(a);
+	i = 0;
+  while(i++ < 30) {
+    if (a->automatic_law > 3)
+      break;
+		diva_os_sleep(10);
+  }
+
+  /* profile information */
+  ctrl->profile.nbchannel = card->d.channels;
+  ctrl->profile.goptions = a->profile.Global_Options;
+  ctrl->profile.support1 = a->profile.B1_Protocols;
+  ctrl->profile.support2 = a->profile.B2_Protocols;
+  ctrl->profile.support3 = a->profile.B3_Protocols;
+  /* manufacturer profile information */
+  ctrl->profile.manu[0] = a->man_profile.private_options;
+  ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads;
+  ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads;
+  ctrl->profile.manu[3] = 0;
+  ctrl->profile.manu[4] = 0;
+
+  capi_ctr_ready(ctrl);
+
+  DBG_TRC(("adapter added, max_adapter=%d", max_adapter));
+  return(1);
+}
+
+/*
+ *  register appl
+ */
+static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
+{
+  APPL *this;
+  word bnum, xnum;
+  int i = 0, j = 0;
+  void * DataNCCI, * DataFlags, * ReceiveBuffer, * xbuffer_used; 
+  void ** xbuffer_ptr, ** xbuffer_internal;
+	diva_os_spin_lock_magic_t old_irql;
+
+  DIVA_LOCK_MODULE;
+
+  if(diva_os_in_irq()) {
+    DBG_ERR(("CAPI_REGISTER - in irq context !"))
+    return;
+  }
+
+  DBG_TRC(("application register"))
+
+  if(appl > MAX_APPL) {
+    DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL"))
+    return; 
+  }
+
+  if (rp->level3cnt < 1 ||
+      rp->level3cnt > 255 ||
+      rp->datablklen < 80 ||
+      rp->datablklen > 2150 ||
+      rp->datablkcnt > 255)
+  {
+    DBG_ERR(("CAPI_REGISTER - invalid parameters"))
+    return; 
+  }
+
+  if (application[appl - 1].Id == appl) {
+    DBG_ERR(("CAPI_REGISTER - appl already registered"))
+    return; /* appl already registered */
+  }
+
+  /* alloc memory */
+
+  bnum = rp->level3cnt * rp->datablkcnt;
+  xnum = rp->level3cnt * MAX_DATA_B3;
+
+  if(!(DataNCCI = diva_os_malloc(0, bnum * sizeof(word)))) {
+    DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+    return;
+  }
+  memset(DataNCCI, 0, bnum * sizeof(word));
+
+  if(!(DataFlags = diva_os_malloc(0, bnum * sizeof(word)))) {
+    DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+    diva_os_free(0, DataNCCI);
+    return;
+  }
+  memset(DataFlags, 0, bnum * sizeof(word));
+
+  if(!(ReceiveBuffer = diva_os_malloc(0, bnum * rp->datablklen))) {
+    DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+    diva_os_free(0, DataNCCI);
+    diva_os_free(0, DataFlags);
+    return;
+  }
+  memset(ReceiveBuffer, 0, bnum * rp->datablklen);
+
+  if(!(xbuffer_used = (byte *) diva_os_malloc(0, xnum))) {
+    DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+    diva_os_free(0, DataNCCI);
+    diva_os_free(0, DataFlags);
+    diva_os_free(0, ReceiveBuffer);
+    return;
+  }
+  memset(xbuffer_used, 0, xnum);
+
+  if(!(xbuffer_ptr = (void **) diva_os_malloc(0, xnum * sizeof(void *)))) {
+    DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+    diva_os_free(0, DataNCCI);
+    diva_os_free(0, DataFlags);
+    diva_os_free(0, ReceiveBuffer);
+    diva_os_free(0, xbuffer_used);
+    return;
+  }
+  memset(xbuffer_ptr, 0, xnum * sizeof(void *));
+
+  if(!(xbuffer_internal = (void **) diva_os_malloc(0, xnum * sizeof(void *)))) {
+    DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+    diva_os_free(0, DataNCCI);
+    diva_os_free(0, DataFlags);
+    diva_os_free(0, ReceiveBuffer);
+    diva_os_free(0, xbuffer_used);
+    diva_os_free(0, xbuffer_ptr);
+    return;
+  }
+  memset(xbuffer_internal, 0, xnum * sizeof(void *));
+
+  for ( i = 0 ; i < xnum ; i++ )
+  {
+    xbuffer_ptr[i] = diva_os_malloc(0, rp->datablklen) ;
+    if ( !xbuffer_ptr[i] )
+    {
+      DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+      if (i) {
+        for(j = 0; j < i; j++)
+          if(xbuffer_ptr[j])
+            diva_os_free(0, xbuffer_ptr[j]);
+      }
+      diva_os_free(0, DataNCCI);
+      diva_os_free(0, DataFlags);
+      diva_os_free(0, ReceiveBuffer);
+      diva_os_free(0, xbuffer_used);
+      diva_os_free(0, xbuffer_ptr);
+      diva_os_free(0, xbuffer_internal);
+      return;  
+    }
+  }
+
+  DBG_LOG(("CAPI_REGISTER - Id = %d", appl))
+  DBG_LOG(("  MaxLogicalConnections = %d", rp->level3cnt))
+  DBG_LOG(("  MaxBDataBuffers       = %d", rp->datablkcnt))
+  DBG_LOG(("  MaxBDataLength        = %d", rp->datablklen))
+
+  /* initialize application data */
+
+	diva_os_enter_spin_lock (&api_lock, &old_irql, "register_appl");
+
+  this = &application[appl - 1] ;
+  memset(this, 0, sizeof (APPL));
+
+  this->Id = appl;
+
+  /* We do not need a list */
+  /* InitializeListHead(&this->s_function); */
+
+  for (i = 0; i < max_adapter; i++)
+  {
+    adapter[i].CIP_Mask[appl - 1] = 0;
+  }
+
+  this->queue_size = 1000;
+
+  this->MaxNCCI = (byte) rp->level3cnt;
+  this->MaxNCCIData = (byte) rp->datablkcnt;
+  this->MaxBuffer = bnum;
+  this->MaxDataLength = rp->datablklen;
+
+  this->DataNCCI         = DataNCCI;
+  this->DataFlags        = DataFlags;
+  this->ReceiveBuffer    = ReceiveBuffer;
+  this->xbuffer_used     = xbuffer_used;
+  this->xbuffer_ptr      = xbuffer_ptr;
+  this->xbuffer_internal = xbuffer_internal;
+  for ( i = 0 ; i < xnum ; i++ ) {
+    this->xbuffer_ptr[i] = xbuffer_ptr[i];
+  }
+
+  CapiRegister(this->Id);
+	diva_os_leave_spin_lock (&api_lock, &old_irql, "register_appl");
+	
+} 
+
+/*
+ *  release appl
+ */
+static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+	diva_os_spin_lock_magic_t old_irql;
+  APPL *this = &application[appl - 1] ;
+  int i = 0;
+
+  if(diva_os_in_irq()) {
+    DBG_ERR(("CAPI_RELEASE - in irq context !"))
+    return;
+  }
+  if (this->Id) {
+    DBG_TRC(("application %d cleanup", this->Id))
+  }
+
+	diva_os_enter_spin_lock (&api_lock, &old_irql, "release_appl");
+  if (this->Id)
+  {
+    CapiRelease(this->Id);
+    if (this->DataNCCI) diva_os_free(0, this->DataNCCI);
+    if (this->DataFlags) diva_os_free(0, this->DataFlags);
+    if (this->ReceiveBuffer) diva_os_free(0, this->ReceiveBuffer);
+    if (this->xbuffer_ptr)
+    {
+      for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI); i++)
+      {
+        if (this->xbuffer_ptr[i]) diva_os_free(0, this->xbuffer_ptr[i]);
+      }
+      diva_os_free(0, this->xbuffer_ptr);
+    }
+    if (this->xbuffer_internal) diva_os_free(0, this->xbuffer_internal);
+    if (this->xbuffer_used) diva_os_free(0, this->xbuffer_used);
+    this->Id = 0;
+  }
+	diva_os_leave_spin_lock (&api_lock, &old_irql, "release_appl");
+
+  DIVA_UNLOCK_MODULE;
+} 
+
+/*
+ *  send message
+ */
+static u16 diva_send_message(struct capi_ctr *ctrl, diva_os_message_buffer_s *dmb)
+{
+  int i = 0, j = 0;
+  word ret = 0;
+	diva_os_spin_lock_magic_t old_irql;
+  CAPI_MSG *msg = (CAPI_MSG *)DIVA_MESSAGE_BUFFER_DATA(dmb);
+  APPL *this = &application[READ_WORD(&msg->header.appl_id) - 1];
+  diva_card *card = ctrl->driverdata;
+  __u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb);
+	word clength = READ_WORD(&msg->header.length);
+	word command = READ_WORD(&msg->header.command);
+
+  if(diva_os_in_irq()) {
+    DBG_ERR(("CAPI_SEND_MSG - in irq context !"))
+		return CAPI_REGOSRESOURCEERR;
+  }
+  DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command))
+
+  /* patch controller number */
+  msg->header.controller = ControllerMap[card->Id]
+												| (msg->header.controller &0x80);  /* preserve external controller bit */
+
+	diva_os_enter_spin_lock (&api_lock, &old_irql, "send message");
+
+  switch ( command )
+  {
+    default:
+      xlog ("\x00\x02", msg, 0x80, clength) ;
+      break;
+
+    case _DATA_B3_I|RESPONSE:
+      if ( myDriverDebugHandle.dbgMask & DL_BLK )
+        xlog ("\x00\x02", msg, 0x80, clength) ;
+      break;
+
+    case _DATA_B3_R:
+      if ( myDriverDebugHandle.dbgMask & DL_BLK )
+        xlog ("\x00\x02", msg, 0x80, clength) ;
+
+      if (clength == 24) clength = 22; /* workaround for PPcom bug */
+                                      /* header is always 22      */
+      if (READ_WORD(&msg->info.data_b3_req.Data_Length) > this->MaxDataLength ||
+          READ_WORD(&msg->info.data_b3_req.Data_Length) > (length - clength))
+      {
+        DBG_ERR(("Write - invalid message size"))
+        goto write_end;
+      }
+
+      for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI) && this->xbuffer_used[i]; i++);
+      if (i == (MAX_DATA_B3 * this->MaxNCCI))
+      {
+        DBG_ERR(("Write - too many data pending"))
+        goto write_end;
+      }
+      msg->info.data_b3_req.Data = i;
+
+      this->xbuffer_internal[i] = NULL;
+      memcpy (this->xbuffer_ptr[i],
+					&((__u8 *)msg)[clength],
+					READ_WORD(&msg->info.data_b3_req.Data_Length));
+
+      if ( (myDriverDebugHandle.dbgMask & DL_BLK)
+        && (myDriverDebugHandle.dbgMask & DL_XLOG))
+      {
+        for ( j = 0 ; j < READ_WORD(&msg->info.data_b3_req.Data_Length) ; j += 256 )
+        {
+          DBG_BLK((((char *)this->xbuffer_ptr[i]) + j,
+            ((READ_WORD(&msg->info.data_b3_req.Data_Length) - j) < 256) ?
+             (READ_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256  ))
+          if ( !(myDriverDebugHandle.dbgMask & DL_PRV0) )
+            break ; // not more if not explicitely requested
+        }
+      }
+      break ;
+  }
+
+  memcpy (mapped_msg, msg, (__u32)clength);
+  mapped_msg->header.controller = MapController (mapped_msg->header.controller);
+  mapped_msg->header.length = clength;
+  mapped_msg->header.command = command;
+	mapped_msg->header.number = READ_WORD(&msg->header.number);
+
+  ret = api_put (this, mapped_msg);
+  switch (ret)
+  {
+    case 0:
+      break;
+    case _BAD_MSG:
+      DBG_ERR(("Write - bad message"))
+      break;
+    case _QUEUE_FULL:
+      DBG_ERR(("Write - queue full"))
+      break;
+    default:
+      DBG_ERR(("Write - api_put returned unknown error"))
+      break;
+  }
+
+write_end:
+	diva_os_leave_spin_lock (&api_lock, &old_irql, "send message");
+  diva_os_free_message_buffer(dmb);
+	return CAPI_NOERROR;
+}
+
+
+/*
+ * cards request function
+ */
+static void DIRequest (ENTITY* e)
+{
+  DIVA_CAPI_ADAPTER *a = &(adapter[(byte)e->user[0]]);
+  diva_card* os_card = (diva_card*)a->os_card;
+
+  if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) {
+    a->FlowControlSkipTable[e->ReqCh] = 1;
+  }
+
+  (*(os_card->d.request))(e);
+}
+
+/*
+ * callback function from didd
+ */
+static void didd_callback(void *context, DESCRIPTOR* adapter, int removal)
+{
+  if (adapter->type == IDI_DADAPTER)
+  {
+    DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
+    return;
+  }
+  else if (adapter->type == IDI_DIMAINT)
+  {
+    if (removal)
+    {
+				stop_dbg();
+    }
+    else
+    {
+      memcpy(&MAdapter, adapter, sizeof(MAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      DbgRegister("CAPI20", DRIVERRELEASE, DBG_DEFAULT);
+    }
+  }
+  else if ((adapter->type > 0) &&
+           (adapter->type < 16))
+  {  /* IDI Adapter */
+    if (removal)
+    {
+      divacapi_remove_card(adapter);
+    }
+    else
+    {
+      diva_add_card(adapter);
+    }
+  }
+  return;
+}
+
+/*
+ * connect to didd
+ */
+static int divacapi_connect_didd(void)
+{
+  int x = 0;
+  int dadapter = 0;
+  IDI_SYNC_REQ req;
+  DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+  DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+	for (x = 0; x < MAX_DESCRIPTORS; x++)
+	{
+			if (DIDD_Table[x].type == IDI_DIMAINT)
+			{	/* MAINT found */
+					memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
+					dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+					DbgRegister("CAPI20", DRIVERRELEASE, DBG_DEFAULT);
+					break;
+			}
+	}
+  for (x = 0; x < MAX_DESCRIPTORS; x++)
+  {
+    if (DIDD_Table[x].type == IDI_DADAPTER)
+    {  /* DADAPTER found */
+      dadapter = 1;
+      memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      req.didd_notify.e.Req = 0;
+      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+      req.didd_notify.info.callback = didd_callback;
+      req.didd_notify.info.context = 0;
+      DAdapter.request((ENTITY *)&req);
+      if (req.didd_notify.e.Rc != 0xff)
+			{
+					stop_dbg();
+					return(0);
+			}
+			notify_handle = req.didd_notify.info.handle;
+    }
+    else if ((DIDD_Table[x].type > 0) &&
+             (DIDD_Table[x].type < 16))
+    {  /* IDI Adapter found */
+      diva_add_card(&DIDD_Table[x]);
+    }
+  }
+
+	if (!dadapter)
+	{
+			stop_dbg();
+	}
+
+  return(dadapter);
+}
+
+/*
+ * diconnect from didd
+ */
+static void divacapi_disconnect_didd(void)
+{
+  IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+  req.didd_notify.e.Req = 0;
+  req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+  req.didd_notify.info.handle = notify_handle;
+  DAdapter.request((ENTITY *)&req);
+}
+
+/*
+ * we do not provide date/time here,
+ * the application should do this. 
+ */
+int fax_head_line_time (char *buffer)
+{
+  return (0);
+}
+
+/*
+ * init (alloc) main structures
+ */
+static int DIVA_INIT_FUNCTION init_main_structs(void)
+{
+  if(!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) {
+    DBG_ERR(("init: failed alloc mapped_msg."))
+    return 0;
+  }
+
+  if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) {
+    DBG_ERR(("init: failed alloc adapter struct."))
+    diva_os_free(0, mapped_msg);
+    return 0;
+  }
+  memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS);
+
+  if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) {
+    DBG_ERR(("init: failed alloc application struct."))
+    diva_os_free(0, mapped_msg);
+    diva_os_free(0, adapter);
+    return 0;
+  }
+  memset(application, 0, sizeof(APPL) * MAX_APPL);
+
+  return(1);
+}
+
+/*
+ * remove (free) main structures
+ */
+static void remove_main_structs(void)
+{
+		if (application)
+			diva_os_free(0, application);
+		if (adapter)
+			diva_os_free(0, adapter);
+		if (mapped_msg)
+			diva_os_free(0, mapped_msg);
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION init_capifunc(void)
+{
+		diva_os_initialize_spin_lock (&ll_lock, "capifunc");
+		diva_os_initialize_spin_lock (&api_lock, "capifunc");
+		memset(ControllerMap, 0, MAX_DESCRIPTORS + 1);
+		max_adapter = 0;
+
+
+		if(!init_main_structs()) {
+			DBG_ERR(("init: failed to init main structs."))
+			return(0);
+		}
+
+		if(!divacapi_connect_didd()) {
+			DBG_ERR(("init: failed to connect to DIDD."))
+			remove_main_structs();
+			return(0);
+		}
+
+		return(1);
+}
+
+/*
+ * finit
+ */
+void DIVA_EXIT_FUNCTION finit_capifunc(void)
+{
+		int count = 100;
+		word ret = 1;
+
+		while(ret && count--)
+		{
+    		ret = api_remove_start();
+				diva_os_sleep(10);
+		}
+		if (ret)
+				DBG_ERR(("could not remove signaling ID's"))
+		
+	  divacapi_disconnect_didd();
+	  divacapi_remove_cards();
+
+		remove_main_structs();
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/capifunc.h b/drivers/isdn/hardware/eicon/capifunc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/capifunc.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,41 @@
+/* $Id: capifunc.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface common functions
+ * 
+ * Copyright 2000-2002 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef __CAPIFUNC_H__ 
+#define __CAPIFUNC_H__
+
+#define MAX_DESCRIPTORS  32
+
+#define DRRELMAJOR  2
+#define DRRELMINOR  0
+#define DRRELEXTRA  ""
+
+#define M_COMPANY "Eicon Networks"
+
+extern char DRIVERRELEASE[];
+
+typedef struct _diva_card {
+	int Id;
+	struct _diva_card *next;
+	struct capi_ctr capi_ctrl;
+	DIVA_CAPI_ADAPTER *adapter;
+	DESCRIPTOR d;
+	char name[32];
+} diva_card;
+
+/*
+ * prototypes
+ */
+int init_capifunc(void);
+void finit_capifunc(void);
+
+#endif /* __CAPIFUNC_H__ */
diff -Nru a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/capimain.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,198 @@
+/* $Id: capimain.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface
+ * 
+ * Copyright 2000-2002 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+#include "os_capi.h"
+
+#include "platform.h"
+#include "di_defs.h"
+#include "capi20.h"
+#include "divacapi.h"
+#include "cp_vers.h"
+#include "capifunc.h"
+
+EXPORT_NO_SYMBOLS;
+
+static char *main_revision = "$Revision: 1.1.2.2 $";
+static char *DRIVERNAME = "Eicon DIVA - CAPI Interface driver (http://www.melware.net)";
+static char *DRIVERLNAME = "divacapi";
+
+MODULE_DESCRIPTION(             "CAPI driver for Eicon DIVA cards");
+MODULE_AUTHOR(                  "Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE(        "CAPI and DIVA card drivers");
+MODULE_LICENSE("GPL");
+
+/*
+ * get revision number from revision string
+ */
+static char *
+getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else rev = "1.0";
+	return rev;
+
+}
+
+/*
+ * sleep for some milliseconds
+ */
+void
+diva_os_sleep (dword mSec)
+{
+	unsigned long timeout = HZ * mSec / 1000 + 1;
+			 
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(timeout);
+}
+
+/*
+ * wait for some milliseconds
+ */ 
+void
+diva_os_wait (dword mSec)
+{
+	mdelay (mSec);
+} 
+
+/*
+ * alloc memory
+ */
+void* diva_os_malloc (unsigned long flags, unsigned long size)
+{
+		void* ret = NULL;
+		if (size) {
+				ret = (void *)vmalloc((unsigned int)size);
+		}
+		return(ret);
+}
+
+/*
+ * free memory
+ */
+void diva_os_free(unsigned long unused, void* ptr)
+{
+		if (ptr) {
+				vfree(ptr);
+		}
+}
+
+/*
+ * alloc a message buffer
+ */
+diva_os_message_buffer_s *
+diva_os_alloc_message_buffer(unsigned long size, void **data_buf)
+{
+		diva_os_message_buffer_s *dmb = alloc_skb(size, GFP_ATOMIC);
+		if (dmb) {
+				*data_buf = skb_put(dmb, size);
+		}
+		return(dmb);
+}
+
+/*
+ * free a message buffer
+ */
+void diva_os_free_message_buffer(diva_os_message_buffer_s *dmb)
+{
+		kfree_skb(dmb);
+} 
+
+/*
+ * proc function for controller info
+ */
+static int diva_ctl_read_proc(char *page, char **start, off_t off,int count, int *eof, struct capi_ctr *ctrl)
+{
+  diva_card *card = (diva_card *)ctrl->driverdata;
+  int len = 0;
+
+  len += sprintf(page+len, "%s\n", ctrl->name);
+  len += sprintf(page+len, "Serial No. : %s\n", ctrl->serial);
+  len += sprintf(page+len, "Id         : %d\n", card->Id);
+  len += sprintf(page+len, "Channels   : %d\n", card->d.channels);
+
+  if (off + count >= len)
+    *eof = 1;
+  if (len < off)
+    return 0;
+  *start = page + off;
+  return((count < len-off) ? count : len-off);
+}
+
+/*
+ * set additional os settings in capi_ctr struct
+ */
+void diva_os_set_controller_struct(struct capi_ctr *ctrl)
+{
+		ctrl->driver_name    = DRIVERLNAME;
+		ctrl->load_firmware  = 0;
+		ctrl->reset_ctr      = 0;
+		ctrl->ctr_read_proc  = diva_ctl_read_proc;
+		SET_MODULE_OWNER(ctrl);
+}
+
+/*
+ * module init
+ */
+static int DIVA_INIT_FUNCTION
+divacapi_init(void)
+{
+  char tmprev[32];
+  int ret = 0;      
+
+  MOD_INC_USE_COUNT;
+
+  sprintf(DRIVERRELEASE, "%d.%d%s", DRRELMAJOR, DRRELMINOR, DRRELEXTRA);
+
+  printk(KERN_INFO "%s\n", DRIVERNAME);
+  printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE);
+  strcpy(tmprev, main_revision);
+  printk("%s  Build: %s(%s)\n", getrev(tmprev),
+        diva_capi_common_code_build, DIVA_BUILD);
+
+	if (!(init_capifunc()))
+	{
+    printk(KERN_ERR "%s: failed init capi_driver.\n", DRIVERLNAME);
+    ret = -EIO;
+	}
+
+  MOD_DEC_USE_COUNT;
+  return ret;
+}
+
+/*
+ * module exit
+ */
+static void DIVA_EXIT_FUNCTION
+divacapi_exit(void)
+{
+  finit_capifunc();
+  printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divacapi_init);
+module_exit(divacapi_exit);
+
diff -Nru a/drivers/isdn/hardware/eicon/cardtype.h b/drivers/isdn/hardware/eicon/cardtype.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/cardtype.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,1098 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef _CARDTYPE_H_
+#define _CARDTYPE_H_
+#ifndef CARDTYPE_H_WANT_DATA
+#define CARDTYPE_H_WANT_DATA   0
+#endif
+#ifndef CARDTYPE_H_WANT_IDI_DATA
+#define CARDTYPE_H_WANT_IDI_DATA  0
+#endif
+#ifndef CARDTYPE_H_WANT_RESOURCE_DATA
+#define CARDTYPE_H_WANT_RESOURCE_DATA 1
+#endif
+#ifndef CARDTYPE_H_WANT_FILE_DATA
+#define CARDTYPE_H_WANT_FILE_DATA  1
+#endif
+/*
+ * D-channel protocol identifiers
+ *
+ * Attention: Unfortunately the identifiers defined here differ from
+ *      the identifiers used in Protocol/1/Common/prot/q931.h .
+ *     The only reason for this is that q931.h has not a global
+ *     scope and we did not know about the definitions there.
+ *     But the definitions here cannot be changed easily because
+ *     they are used in setup scripts and programs.
+ *     Thus the definitions here have to be mapped if they are
+ *     used in the protocol code context !
+ *
+ * Now the identifiers are defined in the q931lib/constant.h file.
+ * Unfortunately this file has also not a global scope.
+ * But beginning with PROTTYPE_US any new identifier will get the same
+ * value as the corresponding PROT_* definition in q931lib/constant.h !
+ */
+#define PROTTYPE_MINVAL     0
+#define PROTTYPE_ETSI       0
+#define PROTTYPE_1TR6       1
+#define PROTTYPE_BELG       2
+#define PROTTYPE_FRANC      3
+#define PROTTYPE_ATEL       4
+#define PROTTYPE_NI         5  /* DMS 100, Nortel, National ISDN */
+#define PROTTYPE_5ESS       6  /* 5ESS   , AT&T,   5ESS Custom   */
+#define PROTTYPE_JAPAN      7
+#define PROTTYPE_SWED       8
+#define PROTTYPE_US         9  /* US autodetect */
+#define PROTTYPE_ITALY      10
+#define PROTTYPE_TWAN       11
+#define PROTTYPE_AUSTRAL    12
+#define PROTTYPE_4ESDN      13
+#define PROTTYPE_4ESDS      14
+#define PROTTYPE_4ELDS      15
+#define PROTTYPE_4EMGC      16
+#define PROTTYPE_4EMGI      17
+#define PROTTYPE_HONGKONG   18
+#define PROTTYPE_RBSCAS     19
+#define PROTTYPE_CORNETN    20
+#define PROTTYPE_QSIG       21
+#define PROTTYPE_NI_EWSD    22 /* EWSD, Siemens, National ISDN   */
+#define PROTTYPE_5ESS_NI    23 /* 5ESS, Lucent, National ISDN    */
+#define PROTTYPE_T1CORNETN  24
+#define PROTTYPE_CORNETNQ   25
+#define PROTTYPE_T1CORNETNQ 26
+#define PROTTYPE_T1QSIG     27
+#define PROTTYPE_E1UNCH     28
+#define PROTTYPE_T1UNCH     29
+#define PROTTYPE_E1CHAN     30
+#define PROTTYPE_T1CHAN     31
+#define PROTTYPE_R2CAS      32
+#define PROTTYPE_MAXVAL     32
+/*
+ * Card type identifiers
+ */
+#define CARD_UNKNOWN                      0
+#define CARD_NONE                         0
+  /* DIVA cards */
+#define CARDTYPE_DIVA_MCA                 0
+#define CARDTYPE_DIVA_ISA                 1
+#define CARDTYPE_DIVA_PCM                 2
+#define CARDTYPE_DIVAPRO_ISA              3
+#define CARDTYPE_DIVAPRO_PCM              4
+#define CARDTYPE_DIVAPICO_ISA             5
+#define CARDTYPE_DIVAPICO_PCM             6
+  /* DIVA 2.0 cards */
+#define CARDTYPE_DIVAPRO20_PCI            7
+#define CARDTYPE_DIVA20_PCI               8
+  /* S cards */
+#define CARDTYPE_QUADRO_ISA               9
+#define CARDTYPE_S_ISA                    10
+#define CARDTYPE_S_MCA                    11
+#define CARDTYPE_SX_ISA                   12
+#define CARDTYPE_SX_MCA                   13
+#define CARDTYPE_SXN_ISA                  14
+#define CARDTYPE_SXN_MCA                  15
+#define CARDTYPE_SCOM_ISA                 16
+#define CARDTYPE_SCOM_MCA                 17
+#define CARDTYPE_PR_ISA                   18
+#define CARDTYPE_PR_MCA                   19
+  /* Diva Server cards (formerly called Maestra, later Amadeo) */
+#define CARDTYPE_MAESTRA_ISA              20
+#define CARDTYPE_MAESTRA_PCI              21
+  /* Diva Server cards to be developed (Quadro, Primary rate) */
+#define CARDTYPE_DIVASRV_Q_8M_PCI         22
+#define CARDTYPE_DIVASRV_P_30M_PCI        23
+#define CARDTYPE_DIVASRV_P_2M_PCI         24
+#define CARDTYPE_DIVASRV_P_9M_PCI         25
+  /* DIVA 2.0 cards */
+#define CARDTYPE_DIVA20_ISA               26
+#define CARDTYPE_DIVA20U_ISA              27
+#define CARDTYPE_DIVA20U_PCI              28
+#define CARDTYPE_DIVAPRO20_ISA            29
+#define CARDTYPE_DIVAPRO20U_ISA           30
+#define CARDTYPE_DIVAPRO20U_PCI           31
+  /* DIVA combi cards (piccola ISDN + rockwell V.34 modem) */
+#define CARDTYPE_DIVAMOBILE_PCM           32
+#define CARDTYPE_TDKGLOBALPRO_PCM         33
+  /* DIVA Pro PC OEM card for 'New Media Corporation' */
+#define CARDTYPE_NMC_DIVAPRO_PCM          34
+  /* DIVA Pro 2.0 OEM cards for 'British Telecom' */
+#define CARDTYPE_BT_EXLANE_PCI            35
+#define CARDTYPE_BT_EXLANE_ISA            36
+  /* DIVA low cost cards, 1st name DIVA 3.0, 2nd DIVA 2.01, 3rd ??? */
+#define CARDTYPE_DIVALOW_ISA              37
+#define CARDTYPE_DIVALOWU_ISA             38
+#define CARDTYPE_DIVALOW_PCI              39
+#define CARDTYPE_DIVALOWU_PCI             40
+  /* DIVA combi cards (piccola ISDN + rockwell V.90 modem) */
+#define CARDTYPE_DIVAMOBILE_V90_PCM       41
+#define CARDTYPE_TDKGLOBPRO_V90_PCM       42
+#define CARDTYPE_DIVASRV_P_23M_PCI        43
+#define CARDTYPE_DIVALOW_USB              44
+  /* DIVA Audio (CT) family */
+#define CARDTYPE_DIVA_CT_ST               45
+#define CARDTYPE_DIVA_CT_U                46
+#define CARDTYPE_DIVA_CTLITE_ST           47
+#define CARDTYPE_DIVA_CTLITE_U            48
+  /* DIVA ISDN plus V.90 series */
+#define CARDTYPE_DIVAISDN_V90_PCM         49
+#define CARDTYPE_DIVAISDN_V90_PCI         50
+#define CARDTYPE_DIVAISDN_TA              51
+  /* DIVA Server Voice cards */
+#define CARDTYPE_DIVASRV_VOICE_Q_8M_PCI   52
+  /* DIVA Server V2 cards */
+#define CARDTYPE_DIVASRV_Q_8M_V2_PCI      53
+#define CARDTYPE_DIVASRV_P_30M_V2_PCI     54
+  /* DIVA Server Voice V2 cards */
+#define CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI 55
+#define CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI 56
+    /* Diva LAN */
+#define CARDTYPE_DIVAISDN_LAN             57
+#define CARDTYPE_DIVA_202_PCI_ST          58
+#define CARDTYPE_DIVA_202_PCI_U           59
+#define CARDTYPE_DIVASRV_B_2M_V2_PCI      60
+#define CARDTYPE_DIVASRV_B_2F_PCI         61
+#define CARDTYPE_DIVALOW_USBV2            62
+#define CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI 63
+#define CARDTYPE_DIVA_PRO_30_PCI_ST       64
+#define CARDTYPE_DIVA_CT_ST_V20           65
+/* Diva Mobile V.90 PC Card and Diva ISDN PC Card */
+#define CARDTYPE_DIVAMOBILE_V2_PCM        66
+#define CARDTYPE_DIVA_V2_PCM              67
+/* Re-badged Diva Pro PC Card */
+#define CARDTYPE_DIVA_PC_CARD             68
+  /* next free card type identifier */
+#define CARDTYPE_MAX                      69
+/*
+ * The card families
+ */
+#define FAMILY_DIVA   1
+#define FAMILY_S   2
+#define FAMILY_MAESTRA  3
+#define FAMILY_MAX   4
+/*
+ * The basic card types
+ */
+#define CARD_DIVA           1  /* DSP based, old DSP */
+#define CARD_PRO            2  /* DSP based, new DSP */
+#define CARD_PICO           3  /* HSCX based   */
+#define CARD_S    4  /* IDI on board based */
+#define CARD_SX    5  /* IDI on board based */
+#define CARD_SXN   6  /* IDI on board based */
+#define CARD_SCOM   7  /* IDI on board based */
+#define CARD_QUAD   8  /* IDI on board based */
+#define CARD_PR    9  /* IDI on board based */
+#define CARD_MAE         10  /* IDI on board based */
+#define CARD_MAEQ        11  /* IDI on board based */
+#define CARD_MAEP        12  /* IDI on board based */
+#define CARD_DIVALOW  13  /* IPAC based   */
+#define CARD_CT    14  /* SCOUT based          */
+#define CARD_DIVATA   15  /* DIVA TA */
+#define CARD_DIVALAN  16  /* DIVA LAN */
+#define CARD_MAE2         17  /* IDI on board based */
+#define CARD_MAX   18
+/*
+ * The internal card types of the S family
+ */
+#define CARD_I_NONE   0
+#define CARD_I_S   0
+#define CARD_I_SX   1
+#define CARD_I_SCOM   2
+#define CARD_I_QUAD   3
+#define CARD_I_PR   4
+/*
+ * The bus types we support
+ */
+#define BUS_ISA             1
+#define BUS_PCM             2
+#define BUS_PCI             3
+#define BUS_MCA             4
+#define BUS_USB             5
+#define BUS_COM    6
+#define BUS_LAN    7
+/*
+ * The chips we use for B-channel traffic
+ */
+#define CHIP_NONE           0
+#define CHIP_DSP            1
+#define CHIP_HSCX           2
+#define CHIP_IPAC           3
+#define CHIP_SCOUT          4
+#define CHIP_EXTERN         5
+#define CHIP_IPACX          6
+/*
+ * The structures where the card properties are aggregated by id
+ */
+typedef struct CARD_PROPERTIES
+{   char     *Name;  /* official marketing name     */
+ unsigned short PnPId;  /* plug and play ID (for non PCMIA cards) */
+ unsigned short Version; /* major and minor version no of the card */
+ unsigned char DescType; /* card type to set in the IDI descriptor */
+ unsigned char  Family;  /* basic family of the card     */
+ unsigned short  Features; /* features bits to set in the IDI desc. */
+ unsigned char Card;  /* basic card type       */
+ unsigned char IType;  /* internal type of S cards (read from ram) */
+ unsigned char  Bus;  /* bus type this card is designed for  */
+ unsigned char  Chip;  /* chipset used on card      */
+ unsigned char Adapters; /* number of adapters on card    */
+ unsigned char Channels; /* # of channels per adapter    */
+ unsigned short E_info;  /* # of ram entity info structs per adapter */
+ unsigned short SizeIo;  /* size of IO window per adapter   */
+ unsigned short SizeMem; /* size of memory window per adapter  */
+} CARD_PROPERTIES;
+typedef struct CARD_RESOURCE
+{ unsigned char Int [10];
+ unsigned short IoFirst;
+ unsigned short IoStep;
+ unsigned short IoCnt;
+ unsigned long MemFirst;
+ unsigned long MemStep;
+ unsigned short MemCnt;
+} CARD_RESOURCE;
+/* test if the card of type 't' is a plug & play card */
+#define IS_PNP(t) \
+( \
+ ( \
+  CardProperties[t].Bus != BUS_ISA \
+  && \
+  CardProperties[t].Bus != BUS_MCA \
+ ) \
+ || \
+ ( \
+  CardProperties[t].Family != FAMILY_S \
+  && \
+  CardProperties[t].Card != CARD_DIVA \
+ ) \
+)
+/* extract IDI Descriptor info for card type 't' (p == DescType/Features) */
+#define IDI_PROP(t,p) (CardProperties[t].p)
+#if CARDTYPE_H_WANT_DATA
+#if CARDTYPE_H_WANT_IDI_DATA
+/* include "di_defs.h" for IDI adapter type and feature flag definitions */
+#include "di_defs.h"
+#else /*!CARDTYPE_H_WANT_IDI_DATA*/
+/* define IDI adapter types and feature flags here to prevent inclusion  */
+#ifndef IDI_ADAPTER_S
+#define IDI_ADAPTER_S           1
+#define IDI_ADAPTER_PR          2
+#define IDI_ADAPTER_DIVA        3
+#define IDI_ADAPTER_MAESTRA     4
+#endif
+#ifndef DI_VOICE
+#define DI_VOICE          0x0 /* obsolete define */
+#define DI_FAX3           0x1
+#define DI_MODEM          0x2
+#define DI_POST           0x4
+#define DI_V110           0x8
+#define DI_V120           0x10
+#define DI_POTS           0x20
+#define DI_CODEC          0x40
+#define DI_MANAGE         0x80
+#define DI_V_42           0x0100
+#define DI_EXTD_FAX       0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
+#define DI_AT_PARSER      0x0400 /* Build-in AT Parser in the L2 */
+#define DI_VOICE_OVER_IP  0x0800 /* Voice over IP support */
+#endif
+#endif /*CARDTYPE_H_WANT_IDI_DATA*/
+#define DI_V1x0         (DI_V110 | DI_V120)
+#define DI_NULL         0x0000
+#if defined(SOFT_DSP_SUPPORT)
+#define SOFT_DSP_ADD_FEATURES  (DI_MODEM | DI_FAX3 | DI_AT_PARSER)
+#else
+#define SOFT_DSP_ADD_FEATURES  0
+#endif
+#if defined(SOFT_V110_SUPPORT)
+#define DI_SOFT_V110  DI_V110
+#else
+#define DI_SOFT_V110  0
+#endif
+/*--- CardProperties [Index=CARDTYPE_....] ---------------------------------*/
+CARD_PROPERTIES CardProperties [ ] =
+{
+{ /*  0  */
+ "Diva MCA",       0x6336,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
+ CARD_DIVA,   CARD_I_NONE, BUS_MCA, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  1  */
+ "Diva ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
+ CARD_DIVA,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  2  */
+ "Diva/PCM",       0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
+ CARD_DIVA,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  3  */
+ "Diva PRO ISA",      0x0031,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  4  */
+ "Diva PRO PC-Card",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_PRO,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,   0,   8,      0
+},
+{ /*  5  */
+ "Diva PICCOLA ISA",     0x0051,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_ISA, CHIP_HSCX,
+ 1, 2,   0,   8,      0
+},
+{ /*  6  */
+ "Diva PICCOLA PCM",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,   0,   8,      0
+},
+{ /*  7  */
+ "Diva PRO 2.0 S/T PCI",    0xe001,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   0,   8,      0
+},
+{ /*  8  */
+ "Diva 2.0 S/T PCI",     0xe002,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCI, CHIP_HSCX,
+ 1, 2,   0,   8,      0
+},
+{ /*  9  */
+ "QUADRO ISA",      0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_QUAD,   CARD_I_QUAD, BUS_ISA, CHIP_NONE,
+ 4, 2,   16,  0,  0x800
+},
+{ /* 10  */
+ "S ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_S,    CARD_I_S,  BUS_ISA, CHIP_NONE,
+ 1, 1,   16,  0,  0x800
+},
+{ /* 11  */
+ "S MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_S,    CARD_I_S,  BUS_MCA, CHIP_NONE,
+ 1, 1,   16,  16,  0x400
+},
+{ /* 12 */
+ "SX ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SX,   CARD_I_SX,  BUS_ISA, CHIP_NONE,
+ 1, 2,  16,  0,  0x800
+},
+{ /* 13 */
+ "SX MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SX,   CARD_I_SX,  BUS_MCA, CHIP_NONE,
+ 1, 2,  16,  16,  0x400
+},
+{ /* 14 */
+ "SXN ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SXN,   CARD_I_SCOM, BUS_ISA, CHIP_NONE,
+ 1, 2,   16,  0,   0x800
+},
+{ /* 15 */
+ "SXN MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SXN,   CARD_I_SCOM, BUS_MCA, CHIP_NONE,
+ 1, 2,  16,  16,  0x400
+},
+{ /* 16 */
+ "SCOM ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_SCOM,   CARD_I_SCOM, BUS_ISA, CHIP_NONE,
+ 1, 2,   16,  0,   0x800
+},
+{ /* 17 */
+ "SCOM MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_SCOM,   CARD_I_SCOM, BUS_MCA, CHIP_NONE,
+ 1, 2,  16,  16,  0x400
+},
+{ /* 18 */
+ "S2M ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_PR,  FAMILY_S,  DI_NULL,
+ CARD_PR,   CARD_I_PR,  BUS_ISA, CHIP_NONE,
+ 1, 30,  256, 0,   0x4000
+},
+{ /* 19 */
+ "S2M MCA",       0x6abb,  0x0100,
+ IDI_ADAPTER_PR,  FAMILY_S,  DI_NULL,
+ CARD_PR,   CARD_I_PR,  BUS_MCA, CHIP_NONE,
+ 1, 30,  256, 16,  0x4000
+},
+{ /* 20 */
+ "Diva Server BRI-2M ISA",   0x0041,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAE,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,   16,  8,  0
+},
+{ /* 21 */
+ "Diva Server BRI-2M PCI",   0xE010,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAE,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   16,  8,   0
+},
+{ /* 22 */
+ "Diva Server 4BRI-8M PCI",   0xE012,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 23 */
+ "Diva Server PRI-30M PCI",   0xE014,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 24 */
+ "Diva Server PRI-2M PCI",   0xe014,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 25 */
+ "Diva Server PRI-9M PCI",   0x0000,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,     256,  8,   0
+},
+{ /* 26 */
+ "Diva 2.0 S/T ISA",     0x0071,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_ISA, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 27 */
+ "Diva 2.0 U ISA",     0x0091,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_ISA, CHIP_HSCX,
+ 1, 2,   0,   8,   0
+},
+{ /* 28 */
+ "Diva 2.0 U PCI",     0xe004,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCI, CHIP_HSCX,
+ 1, 2,   0,   8,   0
+},
+{ /* 29 */
+ "Diva PRO 2.0 S/T ISA",    0x0061,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,   0
+},
+{ /* 30 */
+ "Diva PRO 2.0 U ISA",    0x0081,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,   0
+},
+{ /* 31 */
+ "Diva PRO 2.0 U PCI",    0xe003,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 32 */
+ "Diva MOBILE",      0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 33 */
+ "TDK DFI3600",      0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 34 (OEM version of 4 - "Diva PRO PC-Card") */
+ "New Media ISDN",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_PRO,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 35 (OEM version of 7 - "Diva PRO 2.0 S/T PCI") */
+ "BT ExLane PCI",     0xe101,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 36 (OEM version of 29 - "Diva PRO 2.0 S/T ISA") */
+ "BT ExLane ISA",     0x1061,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 37 */
+ "Diva 2.01 S/T ISA",    0x00A1,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_ISA, CHIP_IPAC,
+ 1, 2,   0,   8,      0
+},
+{ /* 38 */
+ "Diva 2.01 U ISA",     0x00B1,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_ISA, CHIP_IPAC,
+ 1, 2,   0,   8,      0
+},
+{ /* 39 */
+ "Diva 2.01 S/T PCI",    0xe005,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPAC,
+ 1, 2,   0,   8,   0
+},
+{ /* 40        no ID yet */
+ "Diva 2.01 U PCI",     0x0000,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPAC,
+ 1, 2,   0,   8,   0
+},
+{ /* 41 */
+ "Diva MOBILE V.90",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 42 */
+ "TDK DFI3600 V.90",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 43 */
+ "Diva Server PRI-23M PCI",   0xe014,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 44 */
+ "Diva 2.01 S/T USB",    0x1000,     0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_USB, CHIP_IPAC,
+ 1,  2,  0,  8,   0
+},
+{ /* 45 */
+ "Diva CT S/T PCI",    0xe006,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 46 */
+ "Diva CT U PCI",     0xe007,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 47 */
+ "Diva CT Lite S/T PCI",   0xe008,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 48 */
+ "Diva CT Lite U PCI",   0xe009,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 49 */
+ "Diva ISDN+V.90 PC Card", 0x8D8C, 0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_DIVALOW, CARD_I_NONE, BUS_PCM, CHIP_IPAC,
+ 1, 2,  0,   8,   0
+},
+{ /* 50 */
+ "Diva ISDN+V.90 PCI",    0xe00A,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120  | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPAC,
+ 1, 2,   0,   8,   0
+},
+{ /* 51 (DivaTA)      no ID */
+ "Diva TA",       0x0000,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V110 | DI_FAX3 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVATA,  CARD_I_NONE, BUS_COM, CHIP_EXTERN,
+ 1, 1,   0,   8,   0
+},
+{ /* 52 (Diva Server 4BRI-8M PCI adapter enabled for Voice) */
+ "Diva Server Voice 4BRI-8M PCI", 0xE016,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 53 (Diva Server 4BRI 2.0 adapter) */
+ "Diva Server 4BRI-8M 2.0 PCI",  0xE013,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 54 (Diva Server PRI 2.0 adapter) */
+ "Diva Server PRI 2.0 PCI",   0xE015,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 55 (Diva Server 4BRI-8M 2.0 PCI adapter enabled for Voice) */
+ "Diva Server Voice 4BRI-8M 2.0 PCI", 0xE017,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 56 (Diva Server PRI 2.0 PCI adapter enabled for Voice) */
+ "Diva Server Voice PRI 2.0 PCI",  0xE019,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{
+ /* 57 (DivaLan )      no ID */
+ "Diva LAN",       0x0000,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V110 | DI_FAX3 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALAN,  CARD_I_NONE, BUS_LAN, CHIP_EXTERN,
+ 1, 1,   0,   8,   0
+},
+{ /* 58 */
+ "Diva 2.02 PCI S/T",    0xE00B,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES | DI_SOFT_V110,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPACX,
+ 1, 2,   0,   8,   0
+},
+{ /* 59 */
+ "Diva 2.02 PCI U",     0xE00C,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPACX,
+ 1, 2,   0,   8,   0
+},
+{ /* 60 */
+ "Diva Server BRI-2M 2.0 PCI",     0xE018,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAE2,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   16,  8,   0
+},
+{ /* 61  (the previous name was Diva Server BRI-2F 2.0 PCI) */
+ "Diva Server 2FX",                      0xE01A,     0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_SOFT_V110,
+ CARD_MAE2,          CARD_I_NONE,    BUS_PCI,    CHIP_IPACX,
+ 1,  2,      16,     8,   0
+},
+{ /* 62 */
+ " Diva ISDN USB 2.0",    0x1003,     0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_USB, CHIP_IPACX,
+ 1, 2,  0,  8,   0
+},
+{ /* 63 (Diva Server BRI-2M 2.0 PCI adapter enabled for Voice) */
+ "Diva Server Voice BRI-2M 2.0 PCI", 0xE01B,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAE2,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   16,  8,   0
+},
+{ /* 64 */
+ "Diva Pro 3.0 PCI",    0xe00d,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_PRO,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 65 */
+ "Diva ISDN + CT 2.0",    0xE00E,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 66 */
+ "Diva Mobile V.90 PC Card",  0x8331,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_IPACX,
+ 1, 2,  0,   8,   0
+},
+{ /* 67 */
+ "Diva ISDN PC Card",  0x8311,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_IPACX,
+ 1, 2,  0,   8,   0
+},
+{ /* 68 */
+ "Diva ISDN PC Card",  0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PRO,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,   0,   8,      0
+},
+} ;
+#if CARDTYPE_H_WANT_RESOURCE_DATA
+/*--- CardResource [Index=CARDTYPE_....]   ---------------------------(GEI)-*/
+CARD_RESOURCE CardResource [ ] =  {
+/*   Interrupts     IO-Address   Mem-Address */
+/* 0*/ {  3,4,9,0,0,0,0,0,0,0,   0x200,0x20,16,   0x0,0x0,0   }, // DIVA MCA
+/* 1*/ {  3,4,9,10,11,12,0,0,0,0,  0x200,0x20,16,   0x0,0x0,0   }, // DIVA ISA
+/* 2*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PCMCIA
+/* 3*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // DIVA PRO ISA
+/* 4*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PRO PCMCIA
+/* 5*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA PICCOLA ISA
+/* 6*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA PICCOLA PCMCIA
+/* 7*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PRO 2.0 PCI
+/* 8*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.0 PCI
+/* 9*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0x80000,0x2000,64 }, // QUADRO ISA
+/*10*/ {  3,4,9,10,11,12,0,0,0,0,  0x0,0x0,0,   0xc0000,0x2000,16 }, // S ISA
+/*11*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // S MCA
+/*12*/ {  3,4,9,10,11,12,0,0,0,0,  0x0,0x0,0,   0xc0000,0x2000,16 }, // SX ISA
+/*13*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // SX MCA
+/*14*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0x80000,0x0800,256 }, // SXN ISA
+/*15*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // SXN MCA
+/*16*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0x80000,0x0800,256 }, // SCOM ISA
+/*17*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // SCOM MCA
+/*18*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0xc0000,0x4000,16 }, // S2M ISA
+/*19*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x4000,16 }, // S2M MCA
+/*20*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // MAESTRA ISA
+/*21*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA PCI
+/*22*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // MAESTRA QUADRO ISA
+/*23*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA QUADRO PCI
+/*24*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // MAESTRA PRIMARY ISA
+/*25*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA PRIMARY PCI
+/*26*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.0 ISA
+/*27*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.0 /U ISA
+/*28*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.0 /U PCI
+/*29*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // DIVA PRO 2.0 ISA
+/*30*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // DIVA PRO 2.0 /U ISA
+/*31*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PRO 2.0 /U PCI
+/*32*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA MOBILE
+/*33*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // TDK DFI3600 (same as DIVA MOBILE [32])
+/*34*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // New Media ISDN (same as DIVA PRO PCMCIA [4])
+/*35*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // BT ExLane PCI (same as DIVA PRO 2.0 PCI [7])
+/*36*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // BT ExLane ISA (same as DIVA PRO 2.0 ISA [29])
+/*37*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.01 S/T ISA
+/*38*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.01 U ISA
+/*39*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.01 S/T PCI
+/*40*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.01 U PCI
+/*41*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA MOBILE V.90
+/*42*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // TDK DFI3600 V.90 (same as DIVA MOBILE V.90 [39])
+/*43*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // DIVA Server PRI-23M PCI
+/*44*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA 2.01 S/T USB
+/*45*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT S/T PCI
+/*46*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT U PCI
+/*47*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT Lite S/T PCI
+/*48*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT Lite U PCI
+/*49*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA ISDN+V.90 PC Card
+/*50*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA ISDN+V.90 PCI
+/*51*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA TA
+/*52*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA VOICE QUADRO PCI
+/*53*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA VOICE QUADRO PCI
+/*54*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA VOICE PRIMARY PCI
+/*55*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA VOICE QUADRO PCI
+/*56*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA VOICE PRIMARY PCI
+/*57*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA LAN
+/*58*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.02 S/T PCI
+/*59*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.02 U PCI
+/*60*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // Diva Server BRI-2M 2.0 PCI
+/*61*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // Diva Server BRI-2F PCI
+/*62*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA 2.01 S/T USB
+/*63*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // Diva Server Voice BRI-2M 2.0 PCI
+/*64*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 3.0 PCI
+/*65*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT S/T PCI V2.0
+/*66*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA Mobile V.90 PC Card
+/*67*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA ISDN PC Card
+/*68*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA ISDN PC Card
+};
+#endif /*CARDTYPE_H_WANT_RESOURCE_DATA*/
+#else /*!CARDTYPE_H_WANT_DATA*/
+extern CARD_PROPERTIES  CardProperties [] ;
+extern CARD_RESOURCE  CardResource [] ;
+#endif /*CARDTYPE_H_WANT_DATA*/
+/*
+ * all existing download files
+ */
+#define CARD_DSP_CNT  5
+#define CARD_PROT_CNT  9
+#define CARD_FT_UNKNOWN     0
+#define CARD_FT_B   1
+#define CARD_FT_D   2
+#define CARD_FT_S   3
+#define CARD_FT_M   4
+#define CARD_FT_NEW_DSP_COMBIFILE 5  /* File format of new DSP code (the DSP code powered by Telindus) */
+#define CARD_FILE_NONE      0
+#define CARD_B_S   1
+#define CARD_B_P   2
+#define CARD_D_K1   3
+#define CARD_D_K2   4
+#define CARD_D_H   5
+#define CARD_D_V   6
+#define CARD_D_M   7
+#define CARD_D_F   8
+#define CARD_P_S_E   9
+#define CARD_P_S_1   10
+#define CARD_P_S_B   11
+#define CARD_P_S_F   12
+#define CARD_P_S_A   13
+#define CARD_P_S_N   14
+#define CARD_P_S_5   15
+#define CARD_P_S_J   16
+#define CARD_P_SX_E   17
+#define CARD_P_SX_1   18
+#define CARD_P_SX_B   19
+#define CARD_P_SX_F   20
+#define CARD_P_SX_A   21
+#define CARD_P_SX_N   22
+#define CARD_P_SX_5   23
+#define CARD_P_SX_J   24
+#define CARD_P_SY_E   25
+#define CARD_P_SY_1   26
+#define CARD_P_SY_B   27
+#define CARD_P_SY_F   28
+#define CARD_P_SY_A   29
+#define CARD_P_SY_N   30
+#define CARD_P_SY_5   31
+#define CARD_P_SY_J   32
+#define CARD_P_SQ_E   33
+#define CARD_P_SQ_1   34
+#define CARD_P_SQ_B   35
+#define CARD_P_SQ_F   36
+#define CARD_P_SQ_A   37
+#define CARD_P_SQ_N   38
+#define CARD_P_SQ_5   39
+#define CARD_P_SQ_J   40
+#define CARD_P_P_E   41
+#define CARD_P_P_1   42
+#define CARD_P_P_B   43
+#define CARD_P_P_F   44
+#define CARD_P_P_A   45
+#define CARD_P_P_N   46
+#define CARD_P_P_5   47
+#define CARD_P_P_J   48
+#define CARD_P_M_E   49
+#define CARD_P_M_1   50
+#define CARD_P_M_B   51
+#define CARD_P_M_F   52
+#define CARD_P_M_A   53
+#define CARD_P_M_N   54
+#define CARD_P_M_5   55
+#define CARD_P_M_J   56
+#define CARD_P_S_S   57
+#define CARD_P_SX_S   58
+#define CARD_P_SY_S   59
+#define CARD_P_SQ_S   60
+#define CARD_P_P_S   61
+#define CARD_P_M_S   62
+#define CARD_D_NEW_DSP_COMBIFILE 63
+typedef struct CARD_FILES_DATA
+{
+ char *    Name;
+ unsigned char  Type;
+}
+CARD_FILES_DATA;
+typedef struct CARD_FILES
+{
+ unsigned char  Boot;
+ unsigned char  Dsp  [CARD_DSP_CNT];
+ unsigned char  DspTelindus;
+ unsigned char  Prot [CARD_PROT_CNT];
+}
+CARD_FILES;
+#if CARDTYPE_H_WANT_DATA
+#if CARDTYPE_H_WANT_FILE_DATA
+CARD_FILES_DATA CardFData [] =  {
+// Filename   Filetype
+ 0,     CARD_FT_UNKNOWN,
+ "didnload.bin",  CARD_FT_B,
+ "diprload.bin",  CARD_FT_B,
+ "didiva.bin",  CARD_FT_D,
+ "didivapp.bin",  CARD_FT_D,
+ "dihscx.bin",  CARD_FT_D,
+ "div110.bin",  CARD_FT_D,
+ "dimodem.bin",  CARD_FT_D,
+ "difax.bin",  CARD_FT_D,
+ "di_etsi.bin",  CARD_FT_S,
+ "di_1tr6.bin",  CARD_FT_S,
+ "di_belg.bin",  CARD_FT_S,
+ "di_franc.bin",  CARD_FT_S,
+ "di_atel.bin",  CARD_FT_S,
+ "di_ni.bin",  CARD_FT_S,
+ "di_5ess.bin",  CARD_FT_S,
+ "di_japan.bin",  CARD_FT_S,
+ "di_etsi.sx",  CARD_FT_S,
+ "di_1tr6.sx",  CARD_FT_S,
+ "di_belg.sx",  CARD_FT_S,
+ "di_franc.sx",  CARD_FT_S,
+ "di_atel.sx",  CARD_FT_S,
+ "di_ni.sx",   CARD_FT_S,
+ "di_5ess.sx",  CARD_FT_S,
+ "di_japan.sx",  CARD_FT_S,
+ "di_etsi.sy",  CARD_FT_S,
+ "di_1tr6.sy",  CARD_FT_S,
+ "di_belg.sy",  CARD_FT_S,
+ "di_franc.sy",  CARD_FT_S,
+ "di_atel.sy",  CARD_FT_S,
+ "di_ni.sy",   CARD_FT_S,
+ "di_5ess.sy",  CARD_FT_S,
+ "di_japan.sy",  CARD_FT_S,
+ "di_etsi.sq",  CARD_FT_S,
+ "di_1tr6.sq",  CARD_FT_S,
+ "di_belg.sq",  CARD_FT_S,
+ "di_franc.sq",  CARD_FT_S,
+ "di_atel.sq",  CARD_FT_S,
+ "di_ni.sq",   CARD_FT_S,
+ "di_5ess.sq",  CARD_FT_S,
+ "di_japan.sq",  CARD_FT_S,
+ "di_etsi.p",  CARD_FT_S,
+ "di_1tr6.p",  CARD_FT_S,
+ "di_belg.p",  CARD_FT_S,
+ "di_franc.p",  CARD_FT_S,
+ "di_atel.p",  CARD_FT_S,
+ "di_ni.p",   CARD_FT_S,
+ "di_5ess.p",  CARD_FT_S,
+ "di_japan.p",  CARD_FT_S,
+ "di_etsi.sm",  CARD_FT_M,
+ "di_1tr6.sm",  CARD_FT_M,
+ "di_belg.sm",  CARD_FT_M,
+ "di_franc.sm",  CARD_FT_M,
+ "di_atel.sm",  CARD_FT_M,
+ "di_ni.sm",   CARD_FT_M,
+ "di_5ess.sm",  CARD_FT_M,
+ "di_japan.sm",  CARD_FT_M,
+ "di_swed.bin",  CARD_FT_S,
+ "di_swed.sx",  CARD_FT_S,
+ "di_swed.sy",  CARD_FT_S,
+ "di_swed.sq",  CARD_FT_S,
+ "di_swed.p",  CARD_FT_S,
+ "di_swed.sm",  CARD_FT_M,
+    "didspdld.bin",     CARD_FT_NEW_DSP_COMBIFILE
+};
+CARD_FILES CardFiles [] =
+{
+ { /* CARD_UNKNOWN */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_DIVA */
+  CARD_FILE_NONE,
+  CARD_D_K1, CARD_D_H, CARD_D_V, CARD_FILE_NONE, CARD_D_F,
+  CARD_D_NEW_DSP_COMBIFILE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_PRO  */
+  CARD_FILE_NONE,
+  CARD_D_K2, CARD_D_H, CARD_D_V, CARD_D_M, CARD_D_F,
+  CARD_D_NEW_DSP_COMBIFILE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_PICO */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_S    */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_S_E, CARD_P_S_1, CARD_P_S_B, CARD_P_S_F,
+  CARD_P_S_A, CARD_P_S_N, CARD_P_S_5, CARD_P_S_J,
+  CARD_P_S_S
+ },
+ { /* CARD_SX   */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SX_E, CARD_P_SX_1, CARD_P_SX_B, CARD_P_SX_F,
+  CARD_P_SX_A, CARD_P_SX_N, CARD_P_SX_5, CARD_P_SX_J,
+  CARD_P_SX_S
+ },
+ { /* CARD_SXN  */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SY_E, CARD_P_SY_1, CARD_P_SY_B, CARD_P_SY_F,
+  CARD_P_SY_A, CARD_P_SY_N, CARD_P_SY_5, CARD_P_SY_J,
+  CARD_P_SY_S
+ },
+ { /* CARD_SCOM */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SY_E, CARD_P_SY_1, CARD_P_SY_B, CARD_P_SY_F,
+  CARD_P_SY_A, CARD_P_SY_N, CARD_P_SY_5, CARD_P_SY_J,
+  CARD_P_SY_S
+ },
+ { /* CARD_QUAD */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SQ_E, CARD_P_SQ_1, CARD_P_SQ_B, CARD_P_SQ_F,
+  CARD_P_SQ_A, CARD_P_SQ_N, CARD_P_SQ_5, CARD_P_SQ_J,
+  CARD_P_SQ_S
+ },
+ { /* CARD_PR   */
+  CARD_B_P,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_P_E, CARD_P_P_1, CARD_P_P_B, CARD_P_P_F,
+  CARD_P_P_A, CARD_P_P_N, CARD_P_P_5, CARD_P_P_J,
+  CARD_P_P_S
+ },
+ { /* CARD_MAE  */
+  CARD_FILE_NONE,
+  CARD_D_K2, CARD_D_H, CARD_D_V, CARD_D_M, CARD_D_F,
+  CARD_D_NEW_DSP_COMBIFILE,
+  CARD_P_M_E, CARD_P_M_1, CARD_P_M_B, CARD_P_M_F,
+  CARD_P_M_A, CARD_P_M_N, CARD_P_M_5, CARD_P_M_J,
+  CARD_P_M_S
+ },
+ { /* CARD_MAEQ */  /* currently not supported */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_MAEP */  /* currently not supported */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ }
+};
+#endif /*CARDTYPE_H_WANT_FILE_DATA*/
+#else /*!CARDTYPE_H_WANT_DATA*/
+extern CARD_FILES_DATA  CardFData [] ;
+extern CARD_FILES   CardFiles [] ;
+#endif /*CARDTYPE_H_WANT_DATA*/
+#endif /* _CARDTYPE_H_ */
diff -Nru a/drivers/isdn/hardware/eicon/cp_vers.h b/drivers/isdn/hardware/eicon/cp_vers.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/cp_vers.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,26 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+static char diva_capi_common_code_build[] = "102-28";  
diff -Nru a/drivers/isdn/hardware/eicon/dadapter.c b/drivers/isdn/hardware/eicon/dadapter.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dadapter.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,355 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "pc.h"
+#include "debuglib.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "dadapter.h"
+/* --------------------------------------------------------------------------
+  Adapter array change notification framework
+   -------------------------------------------------------------------------- */
+typedef struct _didd_adapter_change_notification {
+ didd_adapter_change_callback_t callback;
+ void IDI_CALL_ENTITY_T *    context;
+} didd_adapter_change_notification_t, \
+ * IDI_CALL_ENTITY_T pdidd_adapter_change_notification_t;
+#define DIVA_DIDD_MAX_NOTIFICATIONS 256
+static didd_adapter_change_notification_t\
+              NotificationTable[DIVA_DIDD_MAX_NOTIFICATIONS];
+/* --------------------------------------------------------------------------
+  Array to held adapter information
+   -------------------------------------------------------------------------- */
+static DESCRIPTOR  HandleTable[NEW_MAX_DESCRIPTORS];
+dword Adapters = 0; /* Number of adapters */
+/* --------------------------------------------------------------------------
+  Shadow IDI_DIMAINT
+  and 'shadow' debug stuff
+   -------------------------------------------------------------------------- */
+static void no_printf (unsigned char * format, ...) { }
+DIVA_DI_PRINTF dprintf = no_printf;
+static DESCRIPTOR  MAdapter =  {IDI_DIMAINT, /* Adapter Type */
+                0x00,     /* Channels */
+                0x0000,    /* Features */
+                (IDI_CALL)no_printf};
+/* --------------------------------------------------------------------------
+  DAdapter. Only IDI clients with buffer, that is huge enough to
+  get all descriptors will receive information about DAdapter
+  { byte type, byte channels, word features, IDI_CALL request }
+   -------------------------------------------------------------------------- */
+static void IDI_CALL_LINK_T diva_dadapter_request (ENTITY IDI_CALL_ENTITY_T *);
+static DESCRIPTOR  DAdapter =  {IDI_DADAPTER, /* Adapter Type */
+                0x00,     /* Channels */
+                0x0000,    /* Features */
+                diva_dadapter_request };
+/* --------------------------------------------------------------------------
+  LOCALS
+   -------------------------------------------------------------------------- */
+static dword diva_register_adapter_callback (\
+                   didd_adapter_change_callback_t callback,
+                   void IDI_CALL_ENTITY_T* context);
+static void diva_remove_adapter_callback (dword handle);
+static void diva_notify_adapter_change (DESCRIPTOR* d, int removal);
+static diva_os_spin_lock_t didd_spin;
+/* --------------------------------------------------------------------------
+  Should be called as first step, after driver init
+  -------------------------------------------------------------------------- */
+void diva_didd_load_time_init (void) {
+ memset (&HandleTable[0], 0x00, sizeof(HandleTable));
+ memset (&NotificationTable[0], 0x00, sizeof(NotificationTable));
+ diva_os_initialize_spin_lock (&didd_spin, "didd");
+}
+/* --------------------------------------------------------------------------
+  Should be called as last step, if driver does unload
+  -------------------------------------------------------------------------- */
+void diva_didd_load_time_finit (void) {
+}
+/* --------------------------------------------------------------------------
+  Called in order to register new adapter in adapter array
+  return adapter handle (> 0) on success
+  return -1 adapter array overflow
+  -------------------------------------------------------------------------- */
+int diva_didd_add_descriptor (DESCRIPTOR* d) {
+ diva_os_spin_lock_magic_t      irql;
+ int i;
+ if (d->type == IDI_DIMAINT) {
+  if (d->request) {
+   MAdapter.request = d->request;
+   dprintf = (DIVA_DI_PRINTF)d->request;
+   diva_notify_adapter_change (&MAdapter, 0); /* Inserted */
+   DBG_TRC (("DIMAINT registered, dprintf=%08x", d->request))
+  } else {
+   DBG_TRC (("DIMAINT removed"))
+   diva_notify_adapter_change (&MAdapter, 1); /* About to remove */
+   MAdapter.request = (IDI_CALL)no_printf;
+   dprintf = no_printf;
+  }
+  return (NEW_MAX_DESCRIPTORS);
+ }
+ for (i = 0; i < NEW_MAX_DESCRIPTORS; i++) {
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_add");
+  if (HandleTable[i].type == 0) {
+   memcpy (&HandleTable[i], d, sizeof(*d));
+   Adapters++;
+   diva_os_leave_spin_lock (&didd_spin, &irql, "didd_add");
+   diva_notify_adapter_change (d, 0); /* we have new adapter */
+   DBG_TRC (("Add adapter[%d], request=%08x", (i+1), d->request))
+   return (i+1);
+  }
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_add");
+ }
+ DBG_ERR (("Can't add adapter, out of resources"))
+ return (-1);
+}
+/* --------------------------------------------------------------------------
+  Called in order to remove one registered adapter from array
+  return adapter handle (> 0) on success
+  return 0 on success
+  -------------------------------------------------------------------------- */
+int diva_didd_remove_descriptor (IDI_CALL request) {
+ diva_os_spin_lock_magic_t      irql;
+ int i;
+ if (request == MAdapter.request) {
+  DBG_TRC(("DIMAINT removed"))
+  dprintf = no_printf;
+  diva_notify_adapter_change (&MAdapter, 1); /* About to remove */
+  MAdapter.request = (IDI_CALL)no_printf;
+  return (0);
+ }
+ for (i = 0; (Adapters && (i < NEW_MAX_DESCRIPTORS)); i++) {
+  if (HandleTable[i].request == request) {
+   diva_notify_adapter_change (&HandleTable[i], 1); /* About to remove */
+   diva_os_enter_spin_lock (&didd_spin, &irql, "didd_rm");
+   memset (&HandleTable[i], 0x00, sizeof(HandleTable[0]));
+   Adapters--;
+   diva_os_leave_spin_lock (&didd_spin, &irql, "didd_rm");
+   DBG_TRC (("Remove adapter[%d], request=%08x", (i+1), request))
+   return (0);
+  }
+ }
+ DBG_ERR (("Invalid request=%08x, can't remove adapter", request))
+ return (-1);
+}
+/* --------------------------------------------------------------------------
+  Read adapter array
+  return 1 if not enough space to save all available adapters
+   -------------------------------------------------------------------------- */
+int diva_didd_read_adapter_array (DESCRIPTOR* buffer, int length) {
+ diva_os_spin_lock_magic_t      irql;
+ int src, dst;
+ memset (buffer, 0x00, length);
+ length /= sizeof(DESCRIPTOR);
+ DBG_TRC (("DIDD_Read, space = %d, Adapters = %d", length, Adapters+2))
+ 
+ diva_os_enter_spin_lock (&didd_spin, &irql, "didd_read");
+ for (src = 0, dst = 0;
+    (Adapters && (src < NEW_MAX_DESCRIPTORS) && (dst < length));
+    src++) {
+  if (HandleTable[src].type) {
+   memcpy (&buffer[dst], &HandleTable[src], sizeof(DESCRIPTOR));
+   dst++;
+  }
+ }
+ diva_os_leave_spin_lock (&didd_spin, &irql, "didd_read");
+ if (dst < length) {
+  memcpy (&buffer[dst], &MAdapter, sizeof(DESCRIPTOR));
+  dst++;
+ } else {
+  DBG_ERR (("Can't write DIMAINT. Array too small"))
+ }
+ if (dst < length) {
+  memcpy (&buffer[dst], &DAdapter, sizeof(DESCRIPTOR));
+  dst++;
+ } else {
+  DBG_ERR (("Can't write DADAPTER. Array too small"))
+ }
+ DBG_TRC (("Read %d adapters", dst))
+ return (dst == length);
+}
+/* --------------------------------------------------------------------------
+  DAdapter request function.
+  This function does process only synchronous requests, and is used
+  for reception/registration of new interfaces
+   -------------------------------------------------------------------------- */
+static void IDI_CALL_LINK_T diva_dadapter_request (\
+                      ENTITY IDI_CALL_ENTITY_T *e) {
+ IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e ;
+ if (e->Req) { /* We do not process it, also return error */
+  e->Rc = OUT_OF_RESOURCES;
+  DBG_ERR (("Can't process async request, Req=%02x", e->Req))
+  return;
+ }
+ /*
+  So, we process sync request
+  */
+ switch (e->Rc) {
+  case IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY: {
+   diva_didd_adapter_notify_t* pinfo = &syncReq->didd_notify.info;
+   pinfo->handle = diva_register_adapter_callback (\
+             (didd_adapter_change_callback_t)pinfo->callback,
+             (void IDI_CALL_ENTITY_T *)pinfo->context);
+   e->Rc = 0xff;
+  } break;
+  case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY: {
+   diva_didd_adapter_notify_t* pinfo = &syncReq->didd_notify.info;
+   diva_remove_adapter_callback (pinfo->handle);
+   e->Rc = 0xff;
+  } break;
+  case IDI_SYNC_REQ_DIDD_ADD_ADAPTER: {
+   diva_didd_add_adapter_t* pinfo = &syncReq->didd_add_adapter.info;
+   if (diva_didd_add_descriptor ((DESCRIPTOR*)pinfo->descriptor) < 0) {
+    e->Rc = OUT_OF_RESOURCES;
+   } else {
+    e->Rc = 0xff;
+   }
+  } break;
+  case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER: {
+   diva_didd_remove_adapter_t* pinfo = &syncReq->didd_remove_adapter.info;
+   if (diva_didd_remove_descriptor ((IDI_CALL)pinfo->p_request) < 0) {
+    e->Rc = OUT_OF_RESOURCES;
+   } else {
+    e->Rc = 0xff;
+   }
+  } break;
+  case IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY: {
+   diva_didd_read_adapter_array_t* pinfo =\
+                &syncReq->didd_read_adapter_array.info;
+   if (diva_didd_read_adapter_array ((DESCRIPTOR*)pinfo->buffer,
+                  (int)pinfo->length)) {
+    e->Rc = OUT_OF_RESOURCES;
+   } else {
+    e->Rc = 0xff;
+   }
+  } break;
+  default:
+   DBG_ERR (("Can't process sync request, Req=%02x", e->Rc))
+   e->Rc = OUT_OF_RESOURCES;
+ }
+}
+/* --------------------------------------------------------------------------
+  IDI client does register his notification function
+  -------------------------------------------------------------------------- */
+static dword diva_register_adapter_callback (\
+                   didd_adapter_change_callback_t callback,
+                   void IDI_CALL_ENTITY_T* context) {
+ diva_os_spin_lock_magic_t irql;
+ dword i;
+ 
+ for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) {
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy_add");
+  if (!NotificationTable[i].callback) {
+   NotificationTable[i].callback = callback;
+   NotificationTable[i].context = context;
+   diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_add");
+   DBG_TRC(("Register adapter notification[%d]=%08x", i+1, callback))
+   return (i+1);
+  }
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_add");
+ }
+ DBG_ERR (("Can't register adapter notification, overflow"))
+ return (0);
+}
+/* --------------------------------------------------------------------------
+  IDI client does register his notification function
+  -------------------------------------------------------------------------- */
+static void diva_remove_adapter_callback (dword handle) {
+ diva_os_spin_lock_magic_t irql;
+ if (handle && ((--handle) < DIVA_DIDD_MAX_NOTIFICATIONS)) {
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy_rm");
+  NotificationTable[handle].callback = 0;
+  NotificationTable[handle].context  = 0;
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_rm");
+  DBG_TRC(("Remove adapter notification[%d]", (int)(handle+1)))
+  return;
+ }
+ DBG_ERR(("Can't remove adapter notification, handle=%d", handle))
+}
+/* --------------------------------------------------------------------------
+  Notify all client about adapter array change
+  Does suppose following behavior in the client side:
+  Step 1: Redister Notification
+  Step 2: Read Adapter Array
+  -------------------------------------------------------------------------- */
+static void diva_notify_adapter_change (DESCRIPTOR* d, int removal) {
+ int i, do_notify;
+ didd_adapter_change_notification_t nfy;
+ diva_os_spin_lock_magic_t irql;
+ for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) {
+  do_notify = 0;
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy");
+  if (NotificationTable[i].callback) {
+   memcpy (&nfy, &NotificationTable[i], sizeof(nfy));
+   do_notify = 1;
+  }
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy");
+  if (do_notify) {
+   (*(nfy.callback))(nfy.context, d, removal);
+  }
+ }
+}
+/* --------------------------------------------------------------------------
+  For all systems, that are linked by Kernel Mode Linker this is ONLY one
+  function thet should be exported by this device driver
+  IDI clients should look for IDI_DADAPTER, and use request function
+  of this adapter (sync request) in order to receive appropriate services:
+  - add new adapter
+  - remove existing adapter
+  - add adapter array notification
+  - remove adapter array notification
+  (read adapter is redundant in this case)
+  INPUT:
+   buffer - pointer to buffer that will receive adapter array
+   length  - length (in bytes) of space in buffer
+  OUTPUT:
+   Adapter array will be written to memory described by 'buffer'
+   If the last adapter seen in the returned adapter array is
+   IDI_DADAPTER or if last adapter in array does have type '0', then
+   it was enougth space in buffer to accomodate all available
+   adapter descriptors
+  *NOTE 1 (debug interface):
+   The IDI adapter of type 'IDI_DIMAINT' does register as 'request'
+   famous 'dprintf' function (of type DI_PRINTF, please look
+   include/debuglib.c and include/debuglib.h) for details.
+   So dprintf is not exported from module debug module directly,
+   instead of this IDI_DIMAINT is registered.
+   Module load order will receive in this case:
+    1. DIDD (this file)
+    2. DIMAINT does load and register 'IDI_DIMAINT', at this step
+      DIDD should be able to get 'dprintf', save it, and
+      register with DIDD by means of 'dprintf' function.
+    3. any other driver is loaded and is able to access adapter array
+      and debug interface
+   This approach does allow to load/unload debug interface on demand,
+   and save memory, it it is necessary.
+  -------------------------------------------------------------------------- */
+void IDI_CALL_LINK_T DIVA_DIDD_Read (void IDI_CALL_ENTITY_T * buffer,
+                   int length) {
+ diva_didd_read_adapter_array (buffer, length);
+}
+/* -------------------------------------------------------------------------
+  Portable debug Library
+  ------------------------------------------------------------------------- */
+#include "debuglib.c"
diff -Nru a/drivers/isdn/hardware/eicon/dadapter.h b/drivers/isdn/hardware/eicon/dadapter.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dadapter.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,35 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_DIDD_DADAPTER_INC__
+#define __DIVA_DIDD_DADAPTER_INC__
+void diva_didd_load_time_init (void);
+void diva_didd_load_time_finit (void);
+int diva_didd_add_descriptor (DESCRIPTOR* d);
+int diva_didd_remove_descriptor (IDI_CALL request);
+int diva_didd_read_adapter_array (DESCRIPTOR* buffer, int length);
+#define OLD_MAX_DESCRIPTORS     16
+#define NEW_MAX_DESCRIPTORS     64
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/dbgioctl.h b/drivers/isdn/hardware/eicon/dbgioctl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dbgioctl.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,198 @@
+
+/*
+ *
+  Copyright (c) Eicon Technology Corporation, 2000.
+ *
+  This source file is supplied for the use with Eicon
+  Technology Corporation's range of DIVA Server Adapters.
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+/*------------------------------------------------------------------*/
+/* file: dbgioctl.h                                                 */
+/*------------------------------------------------------------------*/
+
+#if !defined(__DBGIOCTL_H__)
+
+#define __DBGIOCTL_H__
+
+#ifdef NOT_YET_NEEDED
+/*
+ * The requested operation is passed in arg0 of DbgIoctlArgs,
+ * additional arguments (if any) in arg1, arg2 and arg3.
+ */
+
+typedef struct
+{	ULONG	arg0 ;
+	ULONG	arg1 ;
+	ULONG	arg2 ;
+	ULONG	arg3 ;
+} DbgIoctlArgs ;
+
+#define	DBG_COPY_LOGS	0	/* copy debugs to user until buffer full	*/
+							/* arg1: size threshold						*/
+							/* arg2: timeout in milliseconds			*/
+
+#define DBG_FLUSH_LOGS	1	/* flush pending debugs to user buffer		*/
+							/* arg1: internal driver id					*/
+
+#define DBG_LIST_DRVS	2	/* return the list of registered drivers	*/
+
+#define	DBG_GET_MASK	3	/* get current debug mask of driver			*/
+							/* arg1: internal driver id					*/
+
+#define	DBG_SET_MASK	4	/* set/change debug mask of driver			*/
+							/* arg1: internal driver id					*/
+							/* arg2: new debug mask						*/
+
+#define	DBG_GET_BUFSIZE	5	/* get current buffer size of driver		*/
+							/* arg1: internal driver id					*/
+							/* arg2: new debug mask						*/
+
+#define	DBG_SET_BUFSIZE	6	/* set new buffer size of driver			*/
+							/* arg1: new buffer size					*/
+
+/*
+ *	common internal debug message structure
+ */
+
+typedef struct
+{	unsigned short id ;		/* virtual driver id                  */
+	unsigned short type ;	/* special message type               */
+	unsigned long  seq ;	/* sequence number of message         */
+	unsigned long  size ;	/* size of message in bytes           */
+	unsigned long  next ;	/* offset to next buffered message    */
+	LARGE_INTEGER  NTtime ;	/* 100 ns  since 1.1.1601             */
+	unsigned char  data[4] ;/* message data                       */
+} OldDbgMessage ;
+
+typedef struct
+{	LARGE_INTEGER  NTtime ;	/* 100 ns  since 1.1.1601             */
+	unsigned short size ;	/* size of message in bytes           */
+	unsigned short ffff ;	/* always 0xffff to indicate new msg  */
+	unsigned short id ;		/* virtual driver id                  */
+	unsigned short type ;	/* special message type               */
+	unsigned long  seq ;	/* sequence number of message         */
+	unsigned char  data[4] ;/* message data                       */
+} DbgMessage ;
+
+#endif
+
+#define DRV_ID_UNKNOWN		0x0C	/* for messages via prtComp() */
+
+#define	MSG_PROC_FLAG		0x80
+#define	MSG_PROC_NO_GET(x)	(((x) & MSG_PROC_FLAG) ? (((x) >> 4) & 7) : -1)
+#define	MSG_PROC_NO_SET(x)	(MSG_PROC_FLAG | (((x) & 7) << 4))
+
+#define MSG_TYPE_DRV_ID		0x0001
+#define MSG_TYPE_FLAGS		0x0002
+#define MSG_TYPE_STRING		0x0003
+#define MSG_TYPE_BINARY		0x0004
+
+#define MSG_HEAD_SIZE	((unsigned long)&(((DbgMessage *)0)->data[0]))
+#define MSG_ALIGN(len)	(((unsigned long)(len) + MSG_HEAD_SIZE + 3) & ~3)
+#define MSG_SIZE(pMsg)	MSG_ALIGN((pMsg)->size)
+#define MSG_NEXT(pMsg)	((DbgMessage *)( ((char *)(pMsg)) + MSG_SIZE(pMsg) ))
+
+#define OLD_MSG_HEAD_SIZE	((unsigned long)&(((OldDbgMessage *)0)->data[0]))
+#define OLD_MSG_ALIGN(len)	(((unsigned long)(len)+OLD_MSG_HEAD_SIZE+3) & ~3)
+
+/*
+ * manifest constants
+ */
+
+#define MSG_FRAME_MAX_SIZE	2150		/* maximum size of B1 frame	 */
+#define MSG_TEXT_MAX_SIZE	1024		/* maximum size of msg text	 */
+#define MSG_MAX_SIZE		MSG_ALIGN(MSG_FRAME_MAX_SIZE)
+#define DBG_MIN_BUFFER_SIZE	0x00008000	/* minimal total buffer size  32 KB */
+#define DBG_DEF_BUFFER_SIZE	0x00020000	/* default total buffer size 128 KB */
+#define DBG_MAX_BUFFER_SIZE	0x00400000	/* maximal total buffer size   4 MB */
+
+#define DBGDRV_NAME		"Diehl_DIMAINT"
+#define UNIDBG_DRIVER	L"\\Device\\Diehl_DIMAINT" /* UNICODE name for kernel */
+#define DEBUG_DRIVER	"\\\\.\\" DBGDRV_NAME  /* traditional string for apps */
+#define DBGVXD_NAME		"DIMAINT"
+#define DEBUG_VXD		"\\\\.\\" DBGVXD_NAME  /* traditional string for apps */
+
+/*
+ *	Special IDI interface debug construction
+ */
+
+#define	DBG_IDI_SIG_REQ		(unsigned long)0xF479C402
+#define	DBG_IDI_SIG_IND		(unsigned long)0xF479C403
+#define	DBG_IDI_NL_REQ		(unsigned long)0xF479C404
+#define	DBG_IDI_NL_IND		(unsigned long)0xF479C405
+
+typedef struct
+{	unsigned long  magic_type ;
+	unsigned short data_len ;
+	unsigned char  layer_ID ;
+	unsigned char  entity_ID ;
+	unsigned char  request ;
+	unsigned char  ret_code ;
+	unsigned char  indication ;
+	unsigned char  complete ;
+	unsigned char  data[4] ;
+} DbgIdiAct, *DbgIdiAction ;
+
+/*
+ * We want to use the same IOCTL codes in Win95 and WinNT.
+ * The official constructor for IOCTL codes is the CTL_CODE macro
+ * from <winoctl.h> (<devioctl.h> in WinNT DDK environment).
+ * The problem here is that we don't know how to get <winioctl.h>
+ * working in a Win95 DDK environment!
+ */
+
+# ifdef CTL_CODE	/*{*/
+
+/* Assert that we have the same idea of the CTL_CODE macro.	*/
+
+#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
+    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+# else	/* !CTL_CODE */ /*}{*/
+
+/* Use the definitions stolen from <winioctl.h>.  */
+
+#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
+    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+#define METHOD_BUFFERED                 0
+#define METHOD_IN_DIRECT                1
+#define METHOD_OUT_DIRECT               2
+#define METHOD_NEITHER                  3
+
+#define FILE_ANY_ACCESS                 0
+#define FILE_READ_ACCESS          ( 0x0001 )    // file & pipe
+#define FILE_WRITE_ACCESS         ( 0x0002 )    // file & pipe
+
+# endif	/* CTL_CODE */ /*}*/
+
+/*
+ * Now we can define WinNT/Win95 DeviceIoControl codes.
+ *
+ * These codes are defined in di_defs.h too, a possible mismatch will be
+ * detected when the dbgtool is compiled.
+ */
+
+#define IOCTL_DRIVER_LNK \
+	CTL_CODE(0x8001U,0x701,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_DRIVER_DBG \
+	CTL_CODE(0x8001U,0x702,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#endif /* __DBGIOCTL_H__ */
diff -Nru a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/debug.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1784 @@
+#include "platform.h"
+#include "pc.h"
+#include "di_defs.h"
+#include "debug_if.h"
+#include "linux/kernel.h"
+#include "divasync.h"
+#include "kst_ifc.h"
+#include "maintidi.h"
+
+/*
+  LOCALS
+  */
+#define DBG_MAGIC (0x47114711L)
+
+static void DI_register (void *arg);
+static void DI_deregister (pDbgHandle hDbg);
+static void DI_format (int do_lock, word id, int type, char *format, va_list ap);
+static void DI_format_locked   (word id, int type, char *format, va_list argument_list);
+static void DI_format_old (word id, char *format, va_list ap) { }
+static void DiProcessEventLog (word id, dword msgID, va_list ap) { }
+static void single_p (byte * P, word * PLength, byte Id);
+static void diva_maint_xdi_cb (ENTITY* e);
+static word SuperTraceCreateReadReq (byte* P, const char* path);
+void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...);
+
+static dword MaxDumpSize = 256 ;
+static dword MaxXlogSize = 2 + 128 ;
+
+typedef struct _diva_maint_client {
+  dword       sec;
+  dword       usec;
+  pDbgHandle  hDbg;
+  char        drvName[128];
+  dword       dbgMask;
+  dword       last_dbgMask;
+  IDI_CALL    request;
+  _DbgHandle_ Dbg;
+  int         logical;
+  int         channels;
+  diva_strace_library_interface_t* pIdiLib;
+  BUFFERS     XData;
+  char        xbuffer[2048+512];
+  byte*       pmem;
+	int         request_pending;
+} diva_maint_client_t;
+static diva_maint_client_t clients[64];
+
+static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask);
+
+static void diva_maint_error (void* user_context,
+                              diva_strace_library_interface_t* hLib,
+                              int Adapter,
+                              int error,
+                              const char* file,
+                              int line);
+static void diva_maint_state_change_notify (void* user_context,
+                                            diva_strace_library_interface_t* hLib,
+                                            int Adapter,
+                                            diva_trace_line_state_t* channel,
+                                            int notify_subject);
+static void diva_maint_trace_notify (void* user_context,
+                                     diva_strace_library_interface_t* hLib,
+                                     int Adapter,
+                                     void* xlog_buffer,
+                                     int length);
+
+
+
+typedef struct MSG_QUEUE {
+	dword	Size;		/* total size of queue (constant)	*/
+	byte	*Base;		/* lowest address (constant)		*/
+	byte	*High;		/* Base + Size (constant)		*/
+	byte	*Head;		/* first message in queue (if any)	*/
+	byte	*Tail;		/* first free position			*/
+	byte	*Wrap;		/* current wraparound position 		*/
+	dword	Count;		/* current no of bytes in queue		*/
+} MSG_QUEUE;
+
+typedef struct MSG_HEAD {
+	volatile dword	Size;		/* size of data following MSG_HEAD	*/
+#define	MSG_INCOMPLETE	0x8000	/* ored to Size until queueCompleteMsg 	*/
+} MSG_HEAD;
+
+#define queueCompleteMsg(p) do{ ((MSG_HEAD *)p - 1)->Size &= ~MSG_INCOMPLETE; }while(0)
+#define queueCount(q)	((q)->Count)
+#define MSG_NEED(size) \
+	( (sizeof(MSG_HEAD) + size + sizeof(dword) - 1) & ~(sizeof(dword) - 1) )
+
+static void queueInit (MSG_QUEUE *Q, byte *Buffer, dword sizeBuffer) {
+	Q->Size = sizeBuffer;
+	Q->Base = Q->Head = Q->Tail = Buffer;
+	Q->High = Buffer + sizeBuffer;
+	Q->Wrap = 0;
+	Q->Count= 0;
+}
+
+static byte *queueAllocMsg (MSG_QUEUE *Q, word size) {
+	/* Allocate 'size' bytes at tail of queue which will be filled later
+   * directly whith callers own message header info and/or message.
+   * An 'alloced' message is marked incomplete by oring the 'Size' field
+   * whith MSG_INCOMPLETE.
+   * This must be reset via queueCompleteMsg() after the message is filled.
+   * As long as a message is marked incomplete queuePeekMsg() will return
+   * a 'queue empty' condition when it reaches such a message.  */
+
+	MSG_HEAD *Msg;
+	word need = MSG_NEED(size);
+
+	if (Q->Tail == Q->Head) {
+		if (Q->Wrap || need > Q->Size) {
+			return(0); /* full */
+		}
+		goto alloc; /* empty */
+	}
+	
+	if (Q->Tail > Q->Head) {
+		if (Q->Tail + need <= Q->High) goto alloc; /* append */
+		if (Q->Base + need > Q->Head) {
+			return (0); /* too much */
+		}
+		/* wraparound the queue (but not the message) */
+		Q->Wrap = Q->Tail;
+		Q->Tail = Q->Base;
+		goto alloc;
+	}
+
+	if (Q->Tail + need > Q->Head) {
+		return (0); /* too much */
+	}
+
+alloc:
+	Msg = (MSG_HEAD *)Q->Tail;
+
+	Msg->Size = size | MSG_INCOMPLETE;
+
+	Q->Tail	 += need;
+	Q->Count += size;
+
+
+
+	return ((byte*)(Msg + 1));
+}
+
+static void queueFreeMsg (MSG_QUEUE *Q) {
+/* Free the message at head of queue */
+
+	word size = ((MSG_HEAD *)Q->Head)->Size & ~MSG_INCOMPLETE;
+
+	Q->Head  += MSG_NEED(size);
+	Q->Count -= size;
+
+	if (Q->Wrap) {
+		if (Q->Head >= Q->Wrap) {
+			Q->Head = Q->Base;
+			Q->Wrap = 0;
+		}
+	} else if (Q->Head >= Q->Tail) {
+		Q->Head = Q->Tail = Q->Base;
+	}
+}
+
+static byte *queuePeekMsg (MSG_QUEUE *Q, word *size) {
+	/* Show the first valid message in queue BUT DONT free the message.
+   * After looking on the message contents it can be freed queueFreeMsg()
+   * or simply remain in message queue.  */
+
+	MSG_HEAD *Msg = (MSG_HEAD *)Q->Head;
+
+	if (((byte *)Msg == Q->Tail && !Q->Wrap) ||
+	    (Msg->Size & MSG_INCOMPLETE)) {
+		return (0);
+	} else {
+		*size = Msg->Size;
+		return ((byte *)(Msg + 1));
+	}
+}
+
+/*
+  Message queue header
+  */
+static MSG_QUEUE*          dbg_queue = 0;
+static byte*               dbg_base  = 0;
+static int                 external_dbg_queue = 0;
+static diva_os_spin_lock_t dbg_q_lock;
+static diva_os_spin_lock_t dbg_adapter_lock;
+static int                 dbg_q_busy = 0;
+static volatile dword      dbg_sequence = 0;
+static dword               start_sec;
+static dword               start_usec;
+
+/*
+	INTERFACE:
+    Initialize run time queue structures.
+    base:    base of the message queue
+    length:  length of the message queue
+    do_init: perfor queue reset
+
+    return:  zero on sucess, -1 on error
+  */
+int diva_maint_init (byte* base, unsigned long length, int do_init) {
+  if (dbg_queue || (!base) || (length < (4096*4))) {
+    return (-1);
+  }
+
+  dbg_base = base;
+
+  diva_os_get_time (&start_sec, &start_usec);
+
+  *(dword*)base  = (dword)DBG_MAGIC; /* Store Magic */
+  base   += sizeof(dword);
+  length -= sizeof(dword);
+
+  *(dword*)base = 2048; /* Extension Field Length */
+  base   += sizeof(dword);
+  length -= sizeof(dword);
+
+  strcpy (base, "KERNEL MODE BUFFER\n");
+  base   += 2048;
+  length -= 2048;
+
+  *(dword*)base = 0; /* Terminate extension */
+  base   += sizeof(dword);
+  length -= sizeof(dword);
+
+  *(void**)base  =  (void*)(base+sizeof(void*)); /* Store Base  */
+  base   += sizeof(void*);
+  length -= sizeof(void*);
+
+  dbg_queue = (MSG_QUEUE*)base;
+  queueInit (dbg_queue, base + sizeof(MSG_QUEUE), length - sizeof(MSG_QUEUE) - 512);
+  external_dbg_queue = 0;
+
+  if (!do_init) {
+    external_dbg_queue = 1; /* memory was located on the external device */
+  }
+
+
+	if (diva_os_initialize_spin_lock (&dbg_q_lock, "dbg_init")) {
+    dbg_queue = 0;
+    dbg_base = 0;
+    external_dbg_queue = 0;
+		return (-1);
+  }
+
+	if (diva_os_initialize_spin_lock (&dbg_adapter_lock, "dbg_init")) {
+    diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_init");
+    dbg_queue = 0;
+    dbg_base = 0;
+    external_dbg_queue = 0;
+		return (-1);
+  }
+
+
+  return (0);
+}
+
+/*
+  INTERFACE:
+    Finit at unload time
+    return address of internal queue or zero if queue
+    was external
+  */
+void* diva_maint_finit (void) {
+  void* ret = (void*)dbg_base;
+  int i;
+
+  dbg_queue = 0;
+  dbg_base  = 0;
+
+  if (ret) {
+    diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_finit");
+    diva_os_destroy_spin_lock(&dbg_adapter_lock, "dbg_finit");
+  }
+
+  if (external_dbg_queue) {
+    ret = 0;
+  }
+  external_dbg_queue = 0;
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].pmem) {
+      diva_os_free (0, clients[i].pmem);
+    }
+  }
+
+  return (ret);
+}
+
+/*
+  INTERFACE:
+    Return amount of messages in debug queue
+  */
+dword diva_dbg_q_length (void) {
+	return (dbg_queue ? queueCount(dbg_queue)	: 0);
+}
+
+/*
+  INTERFACE:
+    Lock messafe queue and return the pointer to the first
+    entry.
+  */
+diva_dbg_entry_head_t* diva_maint_get_message (word* size,
+                                               diva_os_spin_lock_magic_t* old_irql) {
+  diva_dbg_entry_head_t*     pmsg = 0;
+
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, old_irql, "read");
+  if (dbg_q_busy) {
+    diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_busy");
+    return (0);
+  }
+  dbg_q_busy = 1;
+
+  if (!(pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, size))) {
+    dbg_q_busy = 0;
+    diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_empty");
+  }
+
+  return (pmsg);
+}
+
+/*
+  INTERFACE:
+    acknowledge last message and unlock queue
+  */
+void diva_maint_ack_message (int do_release,
+                             diva_os_spin_lock_magic_t* old_irql) {
+	if (!dbg_q_busy) {
+		return;
+	}
+	if (do_release) {
+		queueFreeMsg (dbg_queue);
+	}
+	dbg_q_busy = 0;
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, old_irql, "read_ack");
+}
+
+
+/*
+  INTERFACE:
+    PRT COMP function used to register
+    with MAINT adapter or log in compatibility
+    mode in case older driver version is connected too
+  */
+void diva_maint_prtComp (char *format, ...) {
+  void    *hDbg;
+  va_list ap;
+
+  if (!format)
+    return;
+
+  va_start(ap, format);
+
+  /*
+    register to new log driver functions
+   */
+  if ((format[0] == 0) && ((unsigned char)format[1] == 255)) {
+    hDbg = va_arg(ap, void *); /* ptr to DbgHandle */
+    DI_register (hDbg);
+  }
+
+  va_end (ap);
+}
+
+static void DI_register (void *arg) {
+  diva_os_spin_lock_magic_t old_irql;
+  dword sec, usec;
+  pDbgHandle  	hDbg ;
+  int id, free_id = -1, best_id = 0;
+  
+  diva_os_get_time (&sec, &usec);
+
+	hDbg = (pDbgHandle)arg ;
+  /*
+    Check for bad args, specially for the old obsolete debug handle
+    */
+  if ((hDbg == NULL) ||
+      ((hDbg->id == 0) && (((_OldDbgHandle_ *)hDbg)->id == -1)) ||
+      (hDbg->Registered != 0)) {
+		return ;
+  }
+
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+
+  for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
+    if (clients[id].hDbg == hDbg) {
+      /*
+        driver already registered
+        */
+      diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+      return;
+    }
+    if (clients[id].hDbg) { /* slot is busy */
+      continue;
+    }
+    free_id = id;
+    if (!strcmp (clients[id].drvName, hDbg->drvName)) {
+      /*
+        This driver was already registered with this name
+        and slot is still free - reuse it
+        */
+      best_id = 1;
+      break;
+    }
+    if (!clients[id].hDbg) { /* slot is busy */
+      break;
+    }
+  }
+
+  if (free_id != -1) {
+    diva_dbg_entry_head_t* pmsg = 0;
+    int len;
+    char tmp[256];
+    word size;
+
+    /*
+      Register new driver with id == free_id
+      */
+    clients[free_id].hDbg = hDbg;
+    clients[free_id].sec  = sec;
+    clients[free_id].usec = usec;
+    strcpy (clients[free_id].drvName, hDbg->drvName);
+
+    clients[free_id].dbgMask = hDbg->dbgMask;
+    if (best_id) {
+      hDbg->dbgMask |= clients[free_id].last_dbgMask;
+    } else {
+      clients[free_id].last_dbgMask = 0;
+    }
+
+    hDbg->Registered = DBG_HANDLE_REG_NEW ;
+    hDbg->id         = (byte)free_id;
+    hDbg->dbg_end    = DI_deregister;
+    hDbg->dbg_prt    = DI_format_locked;
+    hDbg->dbg_ev     = DiProcessEventLog;
+    hDbg->dbg_irq    = DI_format_locked;
+    if (hDbg->Version > 0) {
+      hDbg->dbg_old  = DI_format_old;
+    }
+    hDbg->next       = (pDbgHandle)DBG_MAGIC;
+
+    /*
+      Log driver register, MAINT driver ID is '0'
+      */
+    len = sprintf (tmp, "DIMAINT - drv # %d = '%s' registered",
+                   free_id, hDbg->drvName);
+
+    while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                        (word)(len+1+sizeof(*pmsg))))) {
+      if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+        queueFreeMsg (dbg_queue);
+      } else {
+        break;
+      }
+    }
+
+    if (pmsg) {
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_STRING;
+      pmsg->dli         = DLI_REG;
+      pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = len+1;
+
+      memcpy (&pmsg[1], tmp, len+1);
+		  queueCompleteMsg (pmsg);
+      diva_maint_wakeup_read();
+    }
+  }
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+}
+
+static void DI_deregister (pDbgHandle hDbg) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  dword sec, usec;
+  int i;
+  word size;
+  byte* pmem = 0;
+
+  diva_os_get_time (&sec, &usec);
+
+  diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read");
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "read");
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg == hDbg) {
+      diva_dbg_entry_head_t* pmsg;
+      char tmp[256];
+      int len;
+
+      clients[i].hDbg = 0;
+
+      hDbg->id       = -1;
+      hDbg->dbgMask  = 0;
+      hDbg->dbg_end  = 0;
+      hDbg->dbg_prt  = 0;
+      hDbg->dbg_irq  = 0;
+      if (hDbg->Version > 0)
+        hDbg->dbg_old = 0;
+      hDbg->Registered = 0;
+      hDbg->next     = 0;
+
+      if (clients[i].pIdiLib) {
+        (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
+        clients[i].pIdiLib = 0;
+
+        pmem = clients[i].pmem;
+        clients[i].pmem = 0;
+      }
+
+      /*
+        Log driver register, MAINT driver ID is '0'
+        */
+      len = sprintf (tmp, "DIMAINT - drv # %d = '%s' de-registered",
+                     i, hDbg->drvName);
+
+      while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                        (word)(len+1+sizeof(*pmsg))))) {
+        if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+          queueFreeMsg (dbg_queue);
+        } else {
+          break;
+        }
+      }
+
+      if (pmsg) {
+        pmsg->sequence    = dbg_sequence++;
+        pmsg->time_sec    = sec;
+        pmsg->time_usec   = usec;
+        pmsg->facility    = MSG_TYPE_STRING;
+        pmsg->dli         = DLI_REG;
+        pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+        pmsg->di_cpu      = 0;
+        pmsg->data_length = len+1;
+
+        memcpy (&pmsg[1], tmp, len+1);
+  		  queueCompleteMsg (pmsg);
+        diva_maint_wakeup_read();
+      }
+
+      break;
+    }
+  }
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "read_ack");
+  diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read_ack");
+
+  if (pmem) {
+    diva_os_free (0, pmem);
+  }
+}
+
+static void DI_format_locked (unsigned short id,
+                       int type,
+                       char *format,
+                       va_list argument_list) {
+  DI_format (1, id, type, format, argument_list);
+}
+
+static void DI_format (int do_lock,
+                       unsigned short id,
+                       int type,
+                       char *format,
+                       va_list ap) {
+  diva_os_spin_lock_magic_t old_irql;
+  dword sec, usec;
+  diva_dbg_entry_head_t* pmsg = 0;
+  dword length;
+  word size;
+  static char fmtBuf[MSG_FRAME_MAX_SIZE+sizeof(*pmsg)+1];
+  char          *data;
+  unsigned short code;
+
+  if (!format)
+    return;
+  
+  diva_os_get_time (&sec, &usec);
+
+  if (do_lock) {
+    diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "format");
+  }
+
+  switch (type) {
+  case DLI_MXLOG :
+  case DLI_BLK :
+  case DLI_SEND:
+  case DLI_RECV:
+    if (!(length = va_arg(ap, unsigned long))) {
+      break;
+    }
+    if (length > MaxDumpSize) {
+      length = MaxDumpSize;
+    }
+    while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                (word)length+sizeof(*pmsg)))) {
+      if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+        queueFreeMsg (dbg_queue);
+      } else {
+        break;
+      }
+    }
+    if (pmsg) {
+      memcpy (&pmsg[1], format, length);
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_BINARY ;
+      pmsg->dli         = type; /* DLI_XXX */
+      pmsg->drv_id      = id;   /* driver MAINT id */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = length;
+      queueCompleteMsg (pmsg);
+    }
+		break;
+
+  case DLI_XLOG: {
+    byte* p;
+    data    = va_arg(ap, char*);
+    code    = (unsigned short)va_arg(ap, unsigned int);
+    length	= (unsigned long) va_arg(ap, unsigned int);
+
+    if (length > MaxXlogSize)
+      length = MaxXlogSize;
+
+    while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                  (word)length+sizeof(*pmsg)+2))) {
+      if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+        queueFreeMsg (dbg_queue);
+      } else {
+        break;
+      }
+    }
+    if (pmsg) {
+      p = (byte*)&pmsg[1];
+      p[0] = (char)(code) ;
+      p[1] = (char)(code >> 8) ;
+      if (data && length) {
+        memcpy (&p[2], &data[0], length) ;
+      }
+      length += 2 ;
+
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_BINARY ;
+      pmsg->dli         = type; /* DLI_XXX */
+      pmsg->drv_id      = id;   /* driver MAINT id */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = length;
+      queueCompleteMsg (pmsg);
+    }
+  } break;
+
+  case DLI_LOG :
+  case DLI_FTL :
+  case DLI_ERR :
+  case DLI_TRC :
+  case DLI_REG :
+  case DLI_MEM :
+  case DLI_SPL :
+  case DLI_IRP :
+  case DLI_TIM :
+  case DLI_TAPI:
+  case DLI_NDIS:
+  case DLI_CONN:
+  case DLI_STAT:
+  case DLI_PRV0:
+  case DLI_PRV1:
+  case DLI_PRV2:
+  case DLI_PRV3:
+    if ((length = (unsigned long)vsprintf (&fmtBuf[0], format, ap)) > 0) {
+      length += (sizeof(*pmsg)+1);
+
+      while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                                          (word)length))) {
+        if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+          queueFreeMsg (dbg_queue);
+        } else {
+          break;
+        }
+      }
+
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_STRING;
+      pmsg->dli         = type; /* DLI_XXX */
+      pmsg->drv_id      = id;   /* driver MAINT id */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = length - sizeof(*pmsg);
+
+      memcpy (&pmsg[1], fmtBuf, pmsg->data_length);
+		  queueCompleteMsg (pmsg);
+    }
+    break;
+
+  } /* switch type */
+
+
+  if (queueCount(dbg_queue)) {
+    diva_maint_wakeup_read();
+  }
+
+  if (do_lock) {
+    diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "format");
+  }
+}
+
+/*
+  Write driver ID and driver revision to callers buffer
+  */
+int diva_get_driver_info (dword id, byte* data, int data_length) {
+  diva_os_spin_lock_magic_t old_irql;
+  byte* p = data;
+  int to_copy;
+
+  if (!data || !id || (data_length < 17) ||
+      (id >= (sizeof(clients)/sizeof(clients[0])))) {
+    return (-1);
+  }
+
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info");
+
+  if (clients[id].hDbg) {
+    *p++ = 1;
+    *p++ = (byte)clients[id].sec; /* save secounds */
+    *p++ = (byte)(clients[id].sec >>  8);
+    *p++ = (byte)(clients[id].sec >> 16);
+    *p++ = (byte)(clients[id].sec >> 24);
+
+    *p++ = (byte)(clients[id].usec/1000); /* save msecounds */
+    *p++ = (byte)((clients[id].usec/1000) >>  8);
+    *p++ = (byte)((clients[id].usec/1000) >> 16);
+    *p++ = (byte)((clients[id].usec/1000) >> 24);
+
+    data_length -= 9;
+
+    if ((to_copy = MIN(strlen(clients[id].drvName), data_length-1))) {
+      memcpy (p, clients[id].drvName, to_copy);
+      p += to_copy;
+      data_length -= to_copy;
+      if ((data_length >= 4) && clients[id].hDbg->drvTag[0]) {
+        *p++ = '(';
+        data_length -= 1;
+        if ((to_copy = MIN(strlen(clients[id].hDbg->drvTag), data_length-2))) {
+          memcpy (p, clients[id].hDbg->drvTag, to_copy);
+          p += to_copy;
+          data_length -= to_copy;
+          if (data_length >= 2) {
+            *p++ = ')';
+            data_length--;
+          }
+        }
+      }
+    }
+  }
+  *p++ = 0;
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info");
+
+  return (p - data);
+}
+
+int diva_get_driver_dbg_mask (dword id, byte* data) {
+  diva_os_spin_lock_magic_t old_irql;
+  int ret = -1;
+
+  if (!data || !id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
+    return (-1);
+  }
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info");
+
+  if (clients[id].hDbg) {
+    ret = 4;
+    *data++= (byte)(clients[id].hDbg->dbgMask);
+    *data++= (byte)(clients[id].hDbg->dbgMask >>  8);
+    *data++= (byte)(clients[id].hDbg->dbgMask >> 16);
+    *data++= (byte)(clients[id].hDbg->dbgMask >> 24);
+  }
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "driver info");
+
+  return (ret);
+}
+
+int diva_set_driver_dbg_mask (dword id, dword mask) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  int ret = -1;
+  
+
+  if (!id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
+    return (-1);
+  }
+
+  diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "dbg mask");
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "dbg mask");
+
+  if (clients[id].hDbg) {
+    dword old_mask = clients[id].hDbg->dbgMask;
+    mask &= 0x7fffffff;
+    clients[id].hDbg->dbgMask = mask;
+    clients[id].last_dbgMask = (clients[id].hDbg->dbgMask | clients[id].dbgMask);
+    ret = 4;
+    diva_change_management_debug_mask (&clients[id], old_mask);
+  }
+
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "dbg mask");
+
+  if (clients[id].request_pending) {
+    clients[id].request_pending = 0;
+    (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
+  }
+
+  diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "dbg mask");
+
+  return (ret);
+}
+
+static int diva_get_idi_adapter_info (IDI_CALL request, dword* serial, dword* logical) {
+  IDI_SYNC_REQ sync_req;
+
+  sync_req.xdi_logical_adapter_number.Req = 0;
+  sync_req.xdi_logical_adapter_number.Rc = IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
+  (*request)((ENTITY *)&sync_req);
+  *logical = sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
+
+  sync_req.GetSerial.Req = 0;
+  sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
+  sync_req.GetSerial.serial = 0;
+  (*request)((ENTITY *)&sync_req);
+	*serial = sync_req.GetSerial.serial;
+
+  return (0);
+}
+
+/*
+  Register XDI adapter as MAINT compatible driver
+  */
+void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  dword sec, usec, logical, serial, org_mask;
+  int id, best_id = 0, free_id = -1;
+  char tmp[256];
+  diva_dbg_entry_head_t* pmsg = 0;
+  int len;
+  word size;
+  byte* pmem;
+
+  diva_os_get_time (&sec, &usec);
+  diva_get_idi_adapter_info (d->request, &serial, &logical);
+  if (serial & 0xff000000) {
+    sprintf (tmp, "ADAPTER:%d SN:%d-%d",
+             (int)logical,
+             serial & 0x00ffffff,
+             (byte)(((serial & 0xff000000) >> 24) + 1));
+  } else {
+    sprintf (tmp, "ADAPTER:%d SN:%d", (int)logical, serial);
+  }
+
+  if (!(pmem = diva_os_malloc (0, DivaSTraceGetMemotyRequirement (d->channels)))) {
+    return;
+  }
+  memset (pmem, 0x00, DivaSTraceGetMemotyRequirement (d->channels));
+
+  diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register");
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+
+  for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
+    if (clients[id].hDbg && (clients[id].request == d->request)) {
+      diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+      diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register");
+      return;
+    }
+    if (clients[id].hDbg) { /* slot is busy */
+      continue;
+    }
+    if (free_id < 0) {
+      free_id = id;
+    }
+    if (!strcmp (clients[id].drvName, tmp)) {
+      /*
+        This driver was already registered with this name
+        and slot is still free - reuse it
+        */
+      free_id = id;
+      best_id = 1;
+      break;
+    }
+  }
+
+  if (free_id < 0) {
+    diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+    diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register");
+    diva_os_free (0, pmem);
+    return;
+  }
+
+  id = free_id;
+  clients[id].request  = d->request;
+  clients[id].request_pending = 0;
+  clients[id].hDbg     = &clients[id].Dbg;
+  clients[id].sec      = sec;
+  clients[id].usec     = usec;
+  strcpy (clients[id].drvName,     tmp);
+  strcpy (clients[id].Dbg.drvName, tmp);
+  clients[id].Dbg.drvTag[0] = 0;
+  clients[id].logical  = (int)logical;
+  clients[id].channels = (int)d->channels;
+
+  clients[id].Dbg.dbgMask    = 0;
+  clients[id].dbgMask        = clients[id].Dbg.dbgMask;
+  if (id) {
+    clients[id].Dbg.dbgMask |= clients[free_id].last_dbgMask;
+  } else {
+    clients[id].last_dbgMask = 0;
+  }
+  clients[id].Dbg.Registered = DBG_HANDLE_REG_NEW;
+  clients[id].Dbg.id         = (byte)id;
+  clients[id].Dbg.dbg_end    = DI_deregister;
+  clients[id].Dbg.dbg_prt    = DI_format_locked;
+  clients[id].Dbg.dbg_ev     = DiProcessEventLog;
+  clients[id].Dbg.dbg_irq    = DI_format_locked;
+  clients[id].Dbg.next       = (pDbgHandle)DBG_MAGIC;
+
+  {
+    diva_trace_library_user_interface_t diva_maint_user_ifc = { &clients[id],
+																							 diva_maint_state_change_notify,
+																							 diva_maint_trace_notify,
+																							 diva_maint_error };
+
+    /*
+      Attach to adapter management interface
+      */
+    if ((clients[id].pIdiLib =
+               DivaSTraceLibraryCreateInstance ((int)logical, &diva_maint_user_ifc, pmem))) {
+      if (((*(clients[id].pIdiLib->DivaSTraceLibraryStart))(clients[id].pIdiLib->hLib))) {
+        diva_mnt_internal_dprintf (0, DLI_ERR, "Adapter(%d) Start failed", (int)logical);
+        (*(clients[id].pIdiLib->DivaSTraceLibraryFinit))(clients[id].pIdiLib->hLib);
+        clients[id].pIdiLib = 0;
+      }
+    } else {
+      diva_mnt_internal_dprintf (0, DLI_ERR, "A(%d) management init failed", (int)logical);
+    }
+  }
+
+  if (!clients[id].pIdiLib) {
+    clients[id].request = 0;
+    clients[id].request_pending = 0;
+    clients[id].hDbg    = 0;
+    diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+    diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register");
+    diva_os_free (0, pmem);
+    return;
+  }
+
+  /*
+    Log driver register, MAINT driver ID is '0'
+    */
+  len = sprintf (tmp, "DIMAINT - drv # %d = '%s' registered",
+                 id, clients[id].Dbg.drvName);
+
+  while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                      (word)(len+1+sizeof(*pmsg))))) {
+    if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+      queueFreeMsg (dbg_queue);
+    } else {
+      break;
+    }
+  }
+
+  if (pmsg) {
+    pmsg->sequence    = dbg_sequence++;
+    pmsg->time_sec    = sec;
+    pmsg->time_usec   = usec;
+    pmsg->facility    = MSG_TYPE_STRING;
+    pmsg->dli         = DLI_REG;
+    pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+    pmsg->di_cpu      = 0;
+    pmsg->data_length = len+1;
+
+    memcpy (&pmsg[1], tmp, len+1);
+    queueCompleteMsg (pmsg);
+    diva_maint_wakeup_read();
+  }
+
+  org_mask = clients[id].Dbg.dbgMask;
+  clients[id].Dbg.dbgMask = 0;
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "register");
+
+  if (clients[id].request_pending) {
+    clients[id].request_pending = 0;
+    (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
+  }
+
+  diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "register");
+
+	diva_set_driver_dbg_mask (id, org_mask);
+}
+
+/*
+  De-Register XDI adapter
+  */
+void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  dword sec, usec;
+  int i;
+  word size;
+  byte* pmem = 0;
+
+  diva_os_get_time (&sec, &usec);
+
+  diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read");
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "read");
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg && (clients[i].request == d->request)) {
+      diva_dbg_entry_head_t* pmsg;
+      char tmp[256];
+      int len;
+
+      if (clients[i].pIdiLib) {
+        (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
+        clients[i].pIdiLib = 0;
+
+        pmem = clients[i].pmem;
+        clients[i].pmem = 0;
+      }
+
+      clients[i].hDbg    = 0;
+      clients[i].request = 0;
+      clients[i].request_pending = 0;
+
+      /*
+        Log driver register, MAINT driver ID is '0'
+        */
+      len = sprintf (tmp, "DIMAINT - drv # %d = '%s' de-registered",
+                     i, clients[i].Dbg.drvName);
+
+      memset (&clients[i].Dbg, 0x00, sizeof(clients[i].Dbg));
+
+      while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                        (word)(len+1+sizeof(*pmsg))))) {
+        if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+          queueFreeMsg (dbg_queue);
+        } else {
+          break;
+        }
+      }
+
+      if (pmsg) {
+        pmsg->sequence    = dbg_sequence++;
+        pmsg->time_sec    = sec;
+        pmsg->time_usec   = usec;
+        pmsg->facility    = MSG_TYPE_STRING;
+        pmsg->dli         = DLI_REG;
+        pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+        pmsg->di_cpu      = 0;
+        pmsg->data_length = len+1;
+
+        memcpy (&pmsg[1], tmp, len+1);
+  		  queueCompleteMsg (pmsg);
+        diva_maint_wakeup_read();
+      }
+
+      break;
+    }
+  }
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "read_ack");
+  diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "read_ack");
+
+  if (pmem) {
+    diva_os_free (0, pmem);
+  }
+}
+
+/* ----------------------------------------------------------------
+     Low level interface for management interace client
+   ---------------------------------------------------------------- */
+/*
+  Return handle to client structure
+  */
+void* SuperTraceOpenAdapter   (int AdapterNumber) {
+  int i;
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg && clients[i].request && (clients[i].logical == AdapterNumber)) {
+      return (&clients[i]);
+    }
+  }
+
+  return (0);
+}
+
+int SuperTraceCloseAdapter  (void* AdapterHandle) {
+  return (0);
+}
+
+int SuperTraceReadRequest (void* AdapterHandle, const char* name, byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    byte* xdata = (byte*)&pC->xbuffer[0];
+    char tmp = 0;
+    word length;
+
+    if (!strcmp(name, "\\")) { /* Read ROOT */
+      name = &tmp;
+    }
+    length = SuperTraceCreateReadReq (xdata, name);
+    single_p (xdata, &length, 0); /* End Of Message */
+
+    e->Req        = MAN_READ;
+    e->ReqCh      = 0;
+    e->X->PLength = length;
+    e->X->P			  = (byte*)xdata;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceGetNumberOfChannels (void* AdapterHandle) {
+  if (AdapterHandle) {
+    diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+    return (pC->channels);
+  }
+
+  return (0);
+}
+
+int SuperTraceASSIGN (void* AdapterHandle, byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+
+    e->Id          = MAN_ID;
+    e->callback    = diva_maint_xdi_cb;
+    e->XNum        = 1;
+    e->X           = &pC->XData;
+    e->Req         = ASSIGN;
+    e->ReqCh       = 0;
+    e->X->PLength  = 1;
+    e->X->P        = (byte*)&pC->xbuffer[0];
+    pC->xbuffer[0] = 0;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceREMOVE (void* AdapterHandle) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+
+    e->XNum        = 1;
+    e->X           = &pC->XData;
+    e->Req         = REMOVE;
+    e->ReqCh       = 0;
+    e->X->PLength  = 1;
+    e->X->P        = (byte*)&pC->xbuffer[0];
+    pC->xbuffer[0] = 0;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceTraceOnRequest(void* hAdapter, const char* name, byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)hAdapter;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    byte* xdata = (byte*)&pC->xbuffer[0];
+    char tmp = 0;
+    word length;
+
+    if (!strcmp(name, "\\")) { /* Read ROOT */
+      name = &tmp;
+    }
+    length = SuperTraceCreateReadReq (xdata, name);
+    single_p (xdata, &length, 0); /* End Of Message */
+    e->Req          = MAN_EVENT_ON;
+    e->ReqCh        = 0;
+    e->X->PLength   = length;
+    e->X->P			    = (byte*)xdata;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceWriteVar (void* AdapterHandle,
+                        byte* data,
+                        const char* name,
+                        void* var,
+                        byte type,
+                        byte var_length) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    diva_man_var_header_t* pVar = (diva_man_var_header_t*)&pC->xbuffer[0];
+    word length = SuperTraceCreateReadReq ((byte*)pVar, name);
+
+    memcpy (&pC->xbuffer[length], var, var_length);
+    length += var_length;
+    pVar->length += var_length;
+    pVar->value_length = var_length;
+    pVar->type = type;
+    single_p ((byte*)pVar, &length, 0); /* End Of Message */
+
+    e->Req          = MAN_WRITE;
+    e->ReqCh			  = 0;
+    e->X->PLength   = length;
+    e->X->P			    = (byte*)pVar;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceExecuteRequest (void* AdapterHandle,
+                              const char* name,
+                              byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    byte* xdata = (byte*)&pC->xbuffer[0];
+    word length;
+
+    length = SuperTraceCreateReadReq (xdata, name);
+    single_p (xdata, &length, 0); /* End Of Message */
+
+    e->Req          = MAN_EXECUTE;
+    e->ReqCh			  = 0;
+    e->X->PLength   = length;
+    e->X->P			    = (byte*)xdata;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+static word SuperTraceCreateReadReq (byte* P, const char* path) {
+	byte var_length;
+	byte* plen;
+
+	var_length = (byte)strlen (path);
+
+	*P++ = ESC;
+	plen = P++;
+	*P++ = 0x80; /* MAN_IE */
+	*P++ = 0x00; /* Type */
+	*P++ = 0x00; /* Attribute */
+	*P++ = 0x00; /* Status */
+	*P++ = 0x00; /* Variable Length */
+	*P++ = var_length;
+	memcpy (P, path, var_length);
+	P += var_length;
+	*plen = var_length + 0x06;
+
+	return ((word)(var_length + 0x08));
+}
+
+static void single_p (byte * P, word * PLength, byte Id) {
+  P[(*PLength)++] = Id;
+}
+
+static void diva_maint_xdi_cb (ENTITY* e) {
+  diva_strace_context_t* pLib = DIVAS_CONTAINING_RECORD(e,diva_strace_context_t,e);
+  diva_maint_client_t* pC;
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+
+
+  diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "xdi_cb");
+  diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "xdi_cb");
+
+  pC = (diva_maint_client_t*)pLib->hAdapter;
+
+	if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
+    diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error");
+  }
+
+  diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "xdi_cb");
+
+
+	if (pC->request_pending) {
+    pC->request_pending = 0;
+    (*(pC->request))(e);
+	}
+
+  diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "xdi_cb");
+}
+
+
+static void diva_maint_error (void* user_context,
+                              diva_strace_library_interface_t* hLib,
+                              int Adapter,
+                              int error,
+                              const char* file,
+                              int line) {
+	diva_mnt_internal_dprintf (0, DLI_ERR,
+                             "Trace library error(%d) A(%d) %s %d", error, Adapter, file, line);
+}
+
+static void print_ie (diva_trace_ie_t* ie, char* buffer, int length) {
+	int i;
+
+  buffer[0] = 0;
+
+  if (length > 32) {
+    for (i = 0; ((i < ie->length) && (length > 3)); i++) {
+      sprintf (buffer, "%02x", ie->data[i]);
+      buffer += 2;
+      length -= 2;
+      if (i < (ie->length-1)) {
+        strcpy (buffer, " ");
+        buffer++;
+        length--;
+      }
+    }
+  }
+}
+
+static void diva_maint_state_change_notify (void* user_context,
+                                            diva_strace_library_interface_t* hLib,
+                                            int Adapter,
+                                            diva_trace_line_state_t* channel,
+                                            int notify_subject) {
+  diva_maint_client_t*      pC    = (diva_maint_client_t*)user_context;
+  diva_trace_fax_state_t*   fax   = &channel->fax;
+  diva_trace_modem_state_t* modem = &channel->modem;
+  char tmp[256];
+
+  if (!pC->hDbg) {
+    return;
+  }
+
+  switch (notify_subject) {
+    case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Ch     = %d",
+                                                                     (int)channel->ChannelNumber);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Status = <%s>", &channel->Line[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer1 = <%s>", &channel->Framing[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer2 = <%s>", &channel->Layer2[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer3 = <%s>", &channel->Layer3[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L RAddr  = <%s>",
+                                                                     &channel->RemoteAddress[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L RSAddr = <%s>",
+                                                                     &channel->RemoteSubAddress[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LAddr  = <%s>",
+                                                                     &channel->LocalAddress[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LSAddr = <%s>",
+                                                                     &channel->LocalSubAddress[0]);
+        print_ie(&channel->call_BC, tmp, sizeof(tmp));
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L BC     = <%s>", tmp);
+        print_ie(&channel->call_HLC, tmp, sizeof(tmp));
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L HLC    = <%s>", tmp);
+        print_ie(&channel->call_LLC, tmp, sizeof(tmp));
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LLC    = <%s>", tmp);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L CR     = 0x%x", channel->CallReference);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Disc   = 0x%x",
+                                                                    channel->LastDisconnecCause);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Owner  = <%s>", &channel->UserID[0]);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_PROGRESS) {
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Ch    = %lu",
+                                                                     (int)modem->ChannelNumber);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Event = %lu",     modem->Event);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Norm  = %lu",     modem->Norm);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Opts. = 0x%08x",  modem->Options);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Tx    = %lu Bps", modem->TxSpeed);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rx    = %lu Bps", modem->RxSpeed);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RT    = %lu mSec",
+                                                                     modem->RoundtripMsec);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Sr    = %lu",     modem->SymbolRate);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rxl   = %d dBm",  modem->RxLeveldBm);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM El    = %d dBm",  modem->EchoLeveldBm);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM SNR   = %lu dB",  modem->SNRdb);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM MAE   = %lu",     modem->MAE);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRet  = %lu",
+                                                                     modem->LocalRetrains);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRet  = %lu",
+                                                                     modem->RemoteRetrains);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRes  = %lu",     modem->LocalResyncs);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRes  = %lu",
+                                                                     modem->RemoteResyncs);
+        if (modem->Event == 3) {
+          diva_mnt_internal_dprintf(pC->hDbg->id,DLI_STAT,"MDM Disc  =  %lu",    modem->DiscReason);
+        }
+      }
+      if ((modem->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_STATISTICS)) {
+        (*(pC->pIdiLib->DivaSTraceGetModemStatistics))(pC->pIdiLib);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_PROGRESS) {
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Ch    = %lu",(int)fax->ChannelNumber);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Event = %lu",     fax->Event);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pages = %lu",     fax->Page_Counter);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Feat. = 0x%08x",  fax->Features);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX ID    = <%s>",    &fax->Station_ID[0]);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Saddr = <%s>",    &fax->Subaddress[0]);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pwd   = <%s>",    &fax->Password[0]);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Speed = %lu",     fax->Speed);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Res.  = 0x%08x",  fax->Resolution);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Width = %lu",     fax->Paper_Width);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Length= %lu",     fax->Paper_Length);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX SLT   = %lu",     fax->Scanline_Time);
+        if (fax->Event == 3) {
+          diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Disc  = %lu",     fax->Disc_Reason);
+        }
+      }
+      if ((fax->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_STATISTICS)) {
+        (*(pC->pIdiLib->DivaSTraceGetFaxStatistics))(pC->pIdiLib);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_INTERFACE_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_EVENTS) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT,
+                                 "Layer 1 -> [%s]", channel->pInterface->Layer1);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT,
+                                 "Layer 2 -> [%s]", channel->pInterface->Layer2);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_STATISTICS) {
+        /*
+          Incoming Statistices
+          */
+        if (channel->pInterfaceStat->inc.Calls) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Calls                     =%lu", channel->pInterfaceStat->inc.Calls);
+        }
+        if (channel->pInterfaceStat->inc.Connected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Connected                 =%lu", channel->pInterfaceStat->inc.Connected);
+        }
+        if (channel->pInterfaceStat->inc.User_Busy) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Busy                      =%lu", channel->pInterfaceStat->inc.User_Busy);
+        }
+        if (channel->pInterfaceStat->inc.Call_Rejected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Rejected                  =%lu", channel->pInterfaceStat->inc.Call_Rejected);
+        }
+        if (channel->pInterfaceStat->inc.Wrong_Number) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Wrong Nr                  =%lu", channel->pInterfaceStat->inc.Wrong_Number);
+        }
+        if (channel->pInterfaceStat->inc.Incompatible_Dst) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Incomp. Dest              =%lu", channel->pInterfaceStat->inc.Incompatible_Dst);
+        }
+        if (channel->pInterfaceStat->inc.Out_of_Order) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Out of Order              =%lu", channel->pInterfaceStat->inc.Out_of_Order);
+        }
+        if (channel->pInterfaceStat->inc.Ignored) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Ignored                   =%lu", channel->pInterfaceStat->inc.Ignored);
+        }
+        
+        /*
+          Outgoing Statistices
+          */
+        if (channel->pInterfaceStat->outg.Calls) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Calls                    =%lu", channel->pInterfaceStat->outg.Calls);
+        }
+        if (channel->pInterfaceStat->outg.Connected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Connected                =%lu", channel->pInterfaceStat->outg.Connected);
+        }
+        if (channel->pInterfaceStat->outg.User_Busy) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Busy                     =%lu", channel->pInterfaceStat->outg.User_Busy);
+        }
+        if (channel->pInterfaceStat->outg.No_Answer) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg No Answer                =%lu", channel->pInterfaceStat->outg.No_Answer);
+        }
+        if (channel->pInterfaceStat->outg.Wrong_Number) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Wrong Nr                 =%lu", channel->pInterfaceStat->outg.Wrong_Number);
+        }
+        if (channel->pInterfaceStat->outg.Call_Rejected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Rejected                 =%lu", channel->pInterfaceStat->outg.Call_Rejected);
+        }
+        if (channel->pInterfaceStat->outg.Other_Failures) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Other Failures           =%lu", channel->pInterfaceStat->outg.Other_Failures);
+        }
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE:
+      if (channel->pInterfaceStat->mdm.Disc_Normal) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Normal        = %lu", channel->pInterfaceStat->mdm.Disc_Normal);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Unspecified) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Unsp.         = %lu", channel->pInterfaceStat->mdm.Disc_Unspecified);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Busy_Tone) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Busy Tone     = %lu", channel->pInterfaceStat->mdm.Disc_Busy_Tone);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Congestion) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Congestion    = %lu", channel->pInterfaceStat->mdm.Disc_Congestion);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Carr_Wait) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Carrier Wait  = %lu", channel->pInterfaceStat->mdm.Disc_Carr_Wait);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Trn_Timeout) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Trn. T.o.     = %lu", channel->pInterfaceStat->mdm.Disc_Trn_Timeout);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Incompat) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Incompatible  = %lu", channel->pInterfaceStat->mdm.Disc_Incompat);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Frame_Rej) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Frame Reject  = %lu", channel->pInterfaceStat->mdm.Disc_Frame_Rej);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_V42bis) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc V.42bis       = %lu", channel->pInterfaceStat->mdm.Disc_V42bis);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE:
+      if (channel->pInterfaceStat->fax.Disc_Normal) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Normal        = %lu", channel->pInterfaceStat->fax.Disc_Normal);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Not_Ident) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Not Ident.    = %lu", channel->pInterfaceStat->fax.Disc_Not_Ident);
+      }
+      if (channel->pInterfaceStat->fax.Disc_No_Response) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc No Response   = %lu", channel->pInterfaceStat->fax.Disc_No_Response);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Retries) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Max Retries   = %lu", channel->pInterfaceStat->fax.Disc_Retries);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Unexp_Msg) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Unexp. Msg.        = %lu", channel->pInterfaceStat->fax.Disc_Unexp_Msg);
+      }
+      if (channel->pInterfaceStat->fax.Disc_No_Polling) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc No Polling    = %lu", channel->pInterfaceStat->fax.Disc_No_Polling);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Training) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Training      = %lu", channel->pInterfaceStat->fax.Disc_Training);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Unexpected) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Unexpected    = %lu", channel->pInterfaceStat->fax.Disc_Unexpected);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Application) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Application   = %lu", channel->pInterfaceStat->fax.Disc_Application);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Incompat) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Incompatible  = %lu", channel->pInterfaceStat->fax.Disc_Incompat);
+      }
+      if (channel->pInterfaceStat->fax.Disc_No_Command) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc No Command    = %lu", channel->pInterfaceStat->fax.Disc_No_Command);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Long_Msg) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Long Msg.     = %lu", channel->pInterfaceStat->fax.Disc_Long_Msg);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Supervisor) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Supervisor    = %lu", channel->pInterfaceStat->fax.Disc_Supervisor);
+      }
+      if (channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc SUP SEP PWD   = %lu", channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Invalid_Msg) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Invalid Msg.  = %lu", channel->pInterfaceStat->fax.Disc_Invalid_Msg);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Page_Coding) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Page Coding   = %lu", channel->pInterfaceStat->fax.Disc_Page_Coding);
+      }
+      if (channel->pInterfaceStat->fax.Disc_App_Timeout) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Appl. T.o.    = %lu", channel->pInterfaceStat->fax.Disc_App_Timeout);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Unspecified) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Unspec.       = %lu", channel->pInterfaceStat->fax.Disc_Unspecified);
+      }
+      break;
+  }
+}
+
+/*
+  Receive trace information from the Management Interface and store it in the
+  internal trace buffer with MSG_TYPE_MLOG as is, without any filtering.
+  Event Filtering and formatting is done in  Management Interface self.
+  */
+static void diva_maint_trace_notify (void* user_context,
+                                     diva_strace_library_interface_t* hLib,
+                                     int Adapter,
+                                     void* xlog_buffer,
+                                     int length) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)user_context;
+  diva_dbg_entry_head_t* pmsg;
+  word size;
+  dword sec, usec;
+
+  diva_os_get_time (&sec, &usec);
+
+  while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                              (word)length+sizeof(*pmsg)))) {
+    if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+      queueFreeMsg (dbg_queue);
+    } else {
+      break;
+    }
+  }
+  if (pmsg) {
+    memcpy (&pmsg[1], xlog_buffer, length);
+    pmsg->sequence    = dbg_sequence++;
+    pmsg->time_sec    = sec;
+    pmsg->time_usec   = usec;
+    pmsg->facility    = MSG_TYPE_MLOG;
+    pmsg->dli         = pC->logical;
+    pmsg->drv_id      = pC->hDbg->id;
+    pmsg->di_cpu      = 0;
+    pmsg->data_length = length;
+    queueCompleteMsg (pmsg);
+    if (queueCount(dbg_queue)) {
+      diva_maint_wakeup_read();
+    }
+  }
+}
+
+
+/*
+  Convert MAINT trace mask to management interface trace mask/work/facility and
+  issue command to management interface
+  */
+static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask) {
+  if (pC->request && pC->hDbg && pC->pIdiLib) {
+    dword changed = pC->hDbg->dbgMask ^ old_mask;
+
+    if (changed & DIVA_MGT_DBG_TRACE) {
+      (*(pC->pIdiLib->DivaSTraceSetInfo))(pC->pIdiLib,
+                                          (pC->hDbg->dbgMask & DIVA_MGT_DBG_TRACE) != 0);
+    }
+    if (changed & DIVA_MGT_DBG_DCHAN) {
+      (*(pC->pIdiLib->DivaSTraceSetDChannel))(pC->pIdiLib,
+                                              (pC->hDbg->dbgMask & DIVA_MGT_DBG_DCHAN) != 0);
+    }
+    if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) {
+      int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
+
+      for (i = 0; i < pC->channels; i++) {
+        (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i+1, state);
+      }
+    }
+    if (changed & DIVA_MGT_DBG_IFC_AUDIO) {
+      int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0);
+
+      for (i = 0; i < pC->channels; i++) {
+        (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i+1, state);
+      }
+    }
+  }
+}
+
+
+void diva_mnt_internal_dprintf (dword drv_id, dword type, char* fmt, ...) {
+  va_list ap;
+
+	va_start(ap, fmt);
+  DI_format (0, (word)drv_id, (int)type, fmt, ap);
+	va_end(ap);
+}
+
+/*
+  Shutdown all adapters before driver removal
+  */
+int diva_mnt_shutdown_xdi_adapters (void) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  int i, fret = 0;
+  byte * pmem;
+
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    pmem = 0;
+
+    diva_os_enter_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "unload");
+    diva_os_enter_spin_lock_hard (&dbg_q_lock, &old_irql, "unload");
+
+    if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
+      if ((*(clients[i].pIdiLib->DivaSTraceLibraryStop))(clients[i].pIdiLib) == 1) {
+        /*
+          Adapter removal complete
+          */
+        if (clients[i].pIdiLib) {
+          (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
+          clients[i].pIdiLib = 0;
+
+          pmem = clients[i].pmem;
+          clients[i].pmem = 0;
+        }
+        clients[i].hDbg    = 0;
+        clients[i].request = 0;
+        clients[i].request_pending = 0;
+      } else {
+        fret = -1;
+      }
+    }
+
+    diva_os_leave_spin_lock_hard (&dbg_q_lock, &old_irql, "unload");
+    if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
+      clients[i].request_pending = 0;
+      (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
+    }
+    diva_os_leave_spin_lock_hard (&dbg_adapter_lock, &old_irql1, "unload");
+
+    if (pmem) {
+      diva_os_free (0, pmem);
+    }
+  }
+
+  return (fret);
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/debug_if.h b/drivers/isdn/hardware/eicon/debug_if.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/debug_if.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,84 @@
+/*
+ *
+  Copyright (c) Eicon Technology Corporation, 2000.
+ *
+  This source file is supplied for the use with Eicon
+  Technology Corporation's range of DIVA Server Adapters.
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_DEBUG_IF_H__
+#define __DIVA_DEBUG_IF_H__
+#define MSG_TYPE_DRV_ID		0x0001
+#define MSG_TYPE_FLAGS		0x0002
+#define MSG_TYPE_STRING		0x0003
+#define MSG_TYPE_BINARY		0x0004
+#define MSG_TYPE_MLOG     0x0005
+
+#define MSG_FRAME_MAX_SIZE 2150
+
+typedef struct _diva_dbg_entry_head {
+  dword sequence;
+  dword time_sec;
+  dword time_usec;
+  dword facility;
+  dword dli;
+  dword drv_id;
+  dword di_cpu;
+  dword data_length;
+} diva_dbg_entry_head_t;
+
+int diva_maint_init (byte* base, unsigned long length, int do_init);
+void* diva_maint_finit (void);
+dword diva_dbg_q_length (void);
+diva_dbg_entry_head_t* diva_maint_get_message (word* size,
+                                               diva_os_spin_lock_magic_t* old_irql);
+void diva_maint_ack_message (int do_release,
+                             diva_os_spin_lock_magic_t* old_irql);
+void diva_maint_prtComp (char *format, ...);
+void diva_maint_wakeup_read (void);
+int diva_get_driver_info (dword id, byte* data, int data_length);
+int diva_get_driver_dbg_mask (dword id, byte* data);
+int diva_set_driver_dbg_mask (dword id, dword mask);
+void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d);
+void diva_mnt_add_xdi_adapter    (const DESCRIPTOR* d);
+int diva_mnt_shutdown_xdi_adapters (void);
+
+
+#define DITRACE_CMD_GET_DRIVER_INFO   1
+#define DITRACE_READ_DRIVER_DBG_MASK  2
+#define DITRACE_WRITE_DRIVER_DBG_MASK 3
+#define DITRACE_READ_TRACE_ENTRY      4
+#define DITRACE_READ_TRACE_ENTRYS     5
+
+/*
+  Trace lavels for debug via management interface
+  */
+#define DIVA_MGT_DBG_TRACE          0x00000001 /* All trace messages from the card */
+#define DIVA_MGT_DBG_DCHAN          0x00000002 /* All D-channel relater trace messages */
+#define DIVA_MGT_DBG_MDM_PROGRESS   0x00000004 /* Modem progress events */
+#define DIVA_MGT_DBG_FAX_PROGRESS   0x00000008 /* Fax progress events */
+#define DIVA_MGT_DBG_IFC_STATISTICS 0x00000010 /* Interface call statistics */
+#define DIVA_MGT_DBG_MDM_STATISTICS 0x00000020 /* Global modem statistics   */
+#define DIVA_MGT_DBG_FAX_STATISTICS 0x00000040 /* Global call statistics    */
+#define DIVA_MGT_DBG_LINE_EVENTS    0x00000080 /* Line state events */
+#define DIVA_MGT_DBG_IFC_EVENTS     0x00000100 /* Interface/L1/L2 state events */
+#define DIVA_MGT_DBG_IFC_BCHANNEL   0x00000200 /* B-Channel trace for all channels */
+#define DIVA_MGT_DBG_IFC_AUDIO      0x00000400 /* Audio Tap trace for all channels */
+
+# endif /* DEBUG_IF___H */
+
+
diff -Nru a/drivers/isdn/hardware/eicon/debuglib.c b/drivers/isdn/hardware/eicon/debuglib.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/debuglib.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,148 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "debuglib.h"
+_DbgHandle_ myDriverDebugHandle = { 0 /*!Registered*/, DBG_HANDLE_VERSION };
+/*****************************************************************************/
+#define DBG_FUNC(name) \
+void  \
+myDbgPrint_##name (char *format, ...) \
+{ va_list ap ; \
+ if ( myDriverDebugHandle.dbg_prt ) \
+ { va_start (ap, format) ; \
+  (myDriverDebugHandle.dbg_prt) \
+   (myDriverDebugHandle.id, DLI_##name, format, ap) ; \
+  va_end (ap) ; \
+} }
+DBG_FUNC(LOG)
+DBG_FUNC(FTL)
+DBG_FUNC(ERR)
+DBG_FUNC(TRC)
+DBG_FUNC(MXLOG)
+DBG_FUNC(FTL_MXLOG)
+void 
+myDbgPrint_EVL (long msgID, ...)
+{ va_list ap ;
+ if ( myDriverDebugHandle.dbg_ev )
+ { va_start (ap, msgID) ;
+  (myDriverDebugHandle.dbg_ev)
+   (myDriverDebugHandle.id, (unsigned long)msgID, ap) ;
+  va_end (ap) ;
+} }
+DBG_FUNC(REG)
+DBG_FUNC(MEM)
+DBG_FUNC(SPL)
+DBG_FUNC(IRP)
+DBG_FUNC(TIM)
+DBG_FUNC(BLK)
+DBG_FUNC(TAPI)
+DBG_FUNC(NDIS)
+DBG_FUNC(CONN)
+DBG_FUNC(STAT)
+DBG_FUNC(SEND)
+DBG_FUNC(RECV)
+DBG_FUNC(PRV0)
+DBG_FUNC(PRV1)
+DBG_FUNC(PRV2)
+DBG_FUNC(PRV3)
+/*****************************************************************************/
+int
+DbgRegister (char *drvName, char *drvTag, unsigned long dbgMask)
+{
+ int len;
+/*
+ * deregister (if already registered) and zero out myDriverDebugHandle
+ */
+ DbgDeregister () ;
+/*
+ * initialize the debug handle
+ */
+ myDriverDebugHandle.Version = DBG_HANDLE_VERSION ;
+ myDriverDebugHandle.id  = -1 ;
+ myDriverDebugHandle.dbgMask = dbgMask | (DL_EVL | DL_FTL | DL_LOG) ;
+ len = strlen (drvName) ;
+ memcpy (myDriverDebugHandle.drvName, drvName,
+         (len < sizeof(myDriverDebugHandle.drvName)) ?
+    len : sizeof(myDriverDebugHandle.drvName) - 1) ;
+ len = strlen (drvTag) ;
+ memcpy (myDriverDebugHandle.drvTag, drvTag,
+         (len < sizeof(myDriverDebugHandle.drvTag)) ?
+    len : sizeof(myDriverDebugHandle.drvTag) - 1) ;
+/*
+ * Try to register debugging via old (and only) interface
+ */
+ dprintf("\000\377", &myDriverDebugHandle) ;
+ if ( myDriverDebugHandle.dbg_prt )
+ {
+  return (1) ;
+ }
+/*
+ * Check if we registered whith an old maint driver (see debuglib.h)
+ */
+ if ( myDriverDebugHandle.dbg_end != NULL
+   /* location of 'dbg_prt' in _OldDbgHandle_ struct */
+   && (myDriverDebugHandle.regTime.LowPart ||
+       myDriverDebugHandle.regTime.HighPart  ) )
+   /* same location as in _OldDbgHandle_ struct */
+ {
+  dprintf("%s: Cannot log to old maint driver !", drvName) ;
+  myDriverDebugHandle.dbg_end =
+  ((_OldDbgHandle_ *)&myDriverDebugHandle)->dbg_end ;
+  DbgDeregister () ;
+ }
+ return (0) ;
+}
+/*****************************************************************************/
+void
+DbgSetLevel (unsigned long dbgMask)
+{
+ myDriverDebugHandle.dbgMask = dbgMask | (DL_EVL | DL_FTL | DL_LOG) ;
+}
+/*****************************************************************************/
+void
+DbgDeregister (void)
+{
+ if ( myDriverDebugHandle.dbg_end )
+ {
+  (myDriverDebugHandle.dbg_end)(&myDriverDebugHandle) ;
+ }
+ memset (&myDriverDebugHandle, 0, sizeof(myDriverDebugHandle)) ;
+}
+void  xdi_dbg_xlog (char* x, ...) {
+ va_list ap;
+ va_start (ap, x);
+ if (myDriverDebugHandle.dbg_end &&
+   (myDriverDebugHandle.dbg_irq || myDriverDebugHandle.dbg_old) &&
+   (myDriverDebugHandle.dbgMask & DL_STAT)) {
+  if (myDriverDebugHandle.dbg_irq) {
+   (*(myDriverDebugHandle.dbg_irq))(myDriverDebugHandle.id,
+       (x[0] != 0) ? DLI_TRC : DLI_XLOG, x, ap);
+  } else {
+   (*(myDriverDebugHandle.dbg_old))(myDriverDebugHandle.id, x, ap);
+  }
+ }
+ va_end(ap);
+}
+/*****************************************************************************/
diff -Nru a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/debuglib.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,282 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#if !defined(__DEBUGLIB_H__)
+#define __DEBUGLIB_H__
+#include <stdarg.h>
+/*
+ * define global debug priorities
+ */
+#define DL_LOG  0x00000001 /* always worth mentioning */
+#define DL_FTL  0x00000002 /* always sampled error    */
+#define DL_ERR  0x00000004 /* any kind of error       */
+#define DL_TRC  0x00000008 /* verbose information     */
+#define DL_XLOG  0x00000010 /* old xlog info           */
+#define DL_MXLOG 0x00000020 /* maestra xlog info    */
+#define DL_FTL_MXLOG 0x00000021 /* fatal maestra xlog info */
+#define DL_EVL  0x00000080 /* special NT eventlog msg */
+#define DL_COMPAT (DL_MXLOG | DL_XLOG)
+#define DL_PRIOR_MASK (DL_EVL | DL_COMPAT | DL_TRC | DL_ERR | DL_FTL | DL_LOG)
+#define DLI_LOG  0x0100
+#define DLI_FTL  0x0200
+#define DLI_ERR  0x0300
+#define DLI_TRC  0x0400
+#define DLI_XLOG 0x0500
+#define DLI_MXLOG 0x0600
+#define DLI_FTL_MXLOG 0x0600
+#define DLI_EVL  0x0800
+/*
+ * define OS (operating system interface) debuglevel
+ */
+#define DL_REG  0x00000100 /* init/query registry     */
+#define DL_MEM  0x00000200 /* memory management       */
+#define DL_SPL  0x00000400 /* event/spinlock handling */
+#define DL_IRP  0x00000800 /* I/O request handling    */
+#define DL_TIM  0x00001000 /* timer/watchdog handling */
+#define DL_BLK  0x00002000 /* raw data block contents */
+#define DL_OS_MASK (DL_BLK | DL_TIM | DL_IRP | DL_SPL | DL_MEM | DL_REG)
+#define DLI_REG  0x0900
+#define DLI_MEM  0x0A00
+#define DLI_SPL  0x0B00
+#define DLI_IRP  0x0C00
+#define DLI_TIM  0x0D00
+#define DLI_BLK  0x0E00
+/*
+ * define ISDN (connection interface) debuglevel
+ */
+#define DL_TAPI  0x00010000 /* debug TAPI interface    */
+#define DL_NDIS  0x00020000 /* debug NDIS interface    */
+#define DL_CONN  0x00040000 /* connection handling     */
+#define DL_STAT  0x00080000 /* trace state machines    */
+#define DL_SEND  0x00100000 /* trace raw xmitted data  */
+#define DL_RECV  0x00200000 /* trace raw received data */
+#define DL_DATA  (DL_SEND | DL_RECV)
+#define DL_ISDN_MASK (DL_DATA | DL_STAT | DL_CONN | DL_NDIS | DL_TAPI)
+#define DLI_TAPI 0x1100
+#define DLI_NDIS 0x1200
+#define DLI_CONN 0x1300
+#define DLI_STAT 0x1400
+#define DLI_SEND 0x1500
+#define DLI_RECV 0x1600
+/*
+ * define some private (unspecified) debuglevel
+ */
+#define DL_PRV0  0x01000000
+#define DL_PRV1  0x02000000
+#define DL_PRV2  0x04000000
+#define DL_PRV3  0x08000000
+#define DL_PRIV_MASK (DL_PRV0 | DL_PRV1 | DL_PRV2 | DL_PRV3)
+#define DLI_PRV0 0x1900
+#define DLI_PRV1 0x1A00
+#define DLI_PRV2 0x1B00
+#define DLI_PRV3 0x1C00
+#define DT_INDEX(x)  ((x) & 0x000F)
+#define DL_INDEX(x)  ((((x) >> 8) & 0x00FF) - 1)
+#define DLI_NAME(x)  ((x) & 0xFF00)
+/*
+ * Debug mask for kernel mode tracing, if set the output is also sent to
+ * the system debug function. Requires that the project is compiled
+ * with _KERNEL_DBG_PRINT_
+ */
+#define DL_TO_KERNEL    0x40000000
+/*
+ * define low level macros for formatted & raw debugging
+ */
+#define DBG_DECL(func) extern void  myDbgPrint_##func (char *, ...) ;
+DBG_DECL(LOG)
+DBG_DECL(FTL)
+DBG_DECL(ERR)
+DBG_DECL(TRC)
+DBG_DECL(MXLOG)
+DBG_DECL(FTL_MXLOG)
+extern void  myDbgPrint_EVL (long, ...) ;
+DBG_DECL(REG)
+DBG_DECL(MEM)
+DBG_DECL(SPL)
+DBG_DECL(IRP)
+DBG_DECL(TIM)
+DBG_DECL(BLK)
+DBG_DECL(TAPI)
+DBG_DECL(NDIS)
+DBG_DECL(CONN)
+DBG_DECL(STAT)
+DBG_DECL(SEND)
+DBG_DECL(RECV)
+DBG_DECL(PRV0)
+DBG_DECL(PRV1)
+DBG_DECL(PRV2)
+DBG_DECL(PRV3)
+#ifdef  _KERNEL_DBG_PRINT_
+/*
+ * tracing to maint and kernel if selected in the trace mask.
+ */
+#define DBG_TEST(func,args) \
+{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_##func ) \
+ { \
+        if ( (myDriverDebugHandle.dbgMask) & DL_TO_KERNEL ) \
+            {DbgPrint args; DbgPrint ("\r\n");} \
+        myDbgPrint_##func args ; \
+} }
+#else
+/*
+ * Standard tracing to maint driver.
+ */
+#define DBG_TEST(func,args) \
+{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_##func ) \
+ { myDbgPrint_##func args ; \
+} }
+#endif
+/*
+ * For event level debug use a separate define, the paramete are
+ * different and cause compiler errors on some systems.
+ */
+#define DBG_EVL_ID(args) \
+{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_EVL ) \
+ { myDbgPrint_EVL args ; \
+} }
+#define DBG_LOG(args)  DBG_TEST(LOG, args)
+#define DBG_FTL(args)  DBG_TEST(FTL, args)
+#define DBG_ERR(args)  DBG_TEST(ERR, args)
+#define DBG_TRC(args)  DBG_TEST(TRC, args)
+#define DBG_MXLOG(args)  DBG_TEST(MXLOG, args)
+#define DBG_FTL_MXLOG(args) DBG_TEST(FTL_MXLOG, args)
+#define DBG_EVL(args)  DBG_EVL_ID(args)
+#define DBG_REG(args)  DBG_TEST(REG, args)
+#define DBG_MEM(args)  DBG_TEST(MEM, args)
+#define DBG_SPL(args)  DBG_TEST(SPL, args)
+#define DBG_IRP(args)  DBG_TEST(IRP, args)
+#define DBG_TIM(args)  DBG_TEST(TIM, args)
+#define DBG_BLK(args)  DBG_TEST(BLK, args)
+#define DBG_TAPI(args)  DBG_TEST(TAPI, args)
+#define DBG_NDIS(args)  DBG_TEST(NDIS, args)
+#define DBG_CONN(args)  DBG_TEST(CONN, args)
+#define DBG_STAT(args)  DBG_TEST(STAT, args)
+#define DBG_SEND(args)  DBG_TEST(SEND, args)
+#define DBG_RECV(args)  DBG_TEST(RECV, args)
+#define DBG_PRV0(args)  DBG_TEST(PRV0, args)
+#define DBG_PRV1(args)  DBG_TEST(PRV1, args)
+#define DBG_PRV2(args)  DBG_TEST(PRV2, args)
+#define DBG_PRV3(args)  DBG_TEST(PRV3, args)
+/*
+ * prototypes for debug register/deregister functions in "debuglib.c"
+ */
+extern int  DbgRegister (char *drvName, char *drvTag, unsigned long dbgMask) ;
+extern void DbgDeregister (void) ;
+extern void DbgSetLevel (unsigned long dbgMask) ;
+/*
+ * driver internal structure for debug handling;
+ * in client drivers this structure is maintained in "debuglib.c",
+ * in the debug driver "debug.c" maintains a chain of such structs.
+ */
+typedef struct _DbgHandle_ *pDbgHandle ;
+typedef void ( * DbgEnd) (pDbgHandle) ;
+typedef void ( * DbgLog) (unsigned short, int, char *, va_list) ;
+typedef void ( * DbgOld) (unsigned short, char *, va_list) ;
+typedef void ( * DbgEv)  (unsigned short, unsigned int, va_list) ;
+typedef void ( * DbgIrq) (unsigned short, int, char *, va_list) ;
+typedef struct _DbgHandle_
+{ char    Registered ; /* driver successfull registered */
+#define DBG_HANDLE_REG_NEW 0x01  /* this (new) structure    */
+#define DBG_HANDLE_REG_OLD 0x7f  /* old structure (see below)  */
+ char    Version;  /* version of this structure  */
+#define DBG_HANDLE_VERSION 1   /* contains dbg_old function now */
+#define DBG_HANDLE_VER_EXT  2           /* pReserved points to extended info*/
+ short               id ;   /* internal id of registered driver */
+  struct _DbgHandle_ *next ;   /* ptr to next registered driver    */
+ struct /*LARGE_INTEGER*/ {
+  unsigned long LowPart;
+  long          HighPart;
+ }     regTime ;  /* timestamp for registration       */
+ void               *pIrp ;   /* ptr to pending i/o request       */
+ unsigned long       dbgMask ;  /* current debug mask               */
+ char                drvName[16] ; /* ASCII name of registered driver  */
+ char                drvTag[64] ; /* revision string     */
+ DbgEnd              dbg_end ;  /* function for debug closing       */
+ DbgLog              dbg_prt ;  /* function for debug appending     */
+ DbgOld              dbg_old ;  /* function for old debug appending */
+ DbgEv       dbg_ev ;  /* function for Windows NT Eventlog */
+ DbgIrq    dbg_irq ;  /* function for irql checked debug  */
+ void      *pReserved3 ;
+} _DbgHandle_ ;
+extern _DbgHandle_ myDriverDebugHandle ;
+typedef struct
+{ struct _OldDbgHandle_ *next ;
+ void                *pIrp ;
+ long    regTime[2] ;
+ unsigned long       dbgMask ;
+ short               id ;
+ char                drvName[78] ;
+ DbgEnd              dbg_end ;
+ DbgLog              dbg_prt ;
+} _OldDbgHandle_ ;
+/* the differences in DbgHandles
+   old:    tmp:     new:
+ 0 long next  char Registered  char Registered
+       char filler   char Version
+       short id    short id
+ 4 long pIrp  long    regTime.lo  long next
+ 8 long    regTime.lo long    regTime.hi  long    regTime.lo
+ 12 long    regTime.hi long next   long regTime.hi
+ 16 long dbgMask  long pIrp   long pIrp
+ 20 short id   long dbgMask   long dbgMask
+ 22 char    drvName[78] ..
+ 24 ..     char drvName[16]  char drvName[16]
+ 40 ..     char drvTag[64]  char drvTag[64]
+ 100 void *dbg_end ..      ..
+ 104 void *dbg_prt void *dbg_end  void *dbg_end
+ 108 ..     void *dbg_prt  void *dbg_prt
+ 112 ..     ..      void *dbg_old
+ 116 ..     ..      void *dbg_ev
+ 120 ..     ..      void *dbg_irq
+ 124 ..     ..      void *pReserved3
+ ( new->id == 0 && *((short *)&new->dbgMask) == -1 ) identifies "old",
+ new->Registered and new->Version overlay old->next,
+ new->next overlays old->pIrp, new->regTime matches old->regTime and
+ thus these fields can be maintained in new struct whithout trouble;
+ id, dbgMask, drvName, dbg_end and dbg_prt need special handling !
+*/
+#define DBG_EXT_TYPE_CARD_TRACE     0x00000001
+typedef struct
+{
+    unsigned long       ExtendedType;
+    union
+    {
+        /* DBG_EXT_TYPE_CARD_TRACE */
+        struct
+        {
+            void ( * MaskChangedNotify) (void *pContext);
+            unsigned long   ModuleTxtMask;
+            unsigned long   DebugLevel;
+            unsigned long   B_ChannelMask;
+            unsigned long   LogBufferSize;
+        } CardTrace;
+    } u1;     
+} _DbgExtendedInfo_;
+/* -------------------------------------------------------------
+    Function used for xlog-style debug
+   ------------------------------------------------------------- */
+#define XDI_USE_XLOG 1
+void  xdi_dbg_xlog (char* x, ...);
+#endif /* __DEBUGLIB_H__ */
diff -Nru a/drivers/isdn/hardware/eicon/dfifo.h b/drivers/isdn/hardware/eicon/dfifo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dfifo.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,54 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_IDI_DFIFO_INC__
+#define __DIVA_IDI_DFIFO_INC__
+#define DIVA_DFIFO_CACHE_SZ   64 /* Used to isolate pipe from
+                    rest of the world
+                   should be divisible by 4
+                   */
+#define DIVA_DFIFO_RAW_SZ    (2512*8)
+#define DIVA_DFIFO_DATA_SZ   68
+#define DIVA_DFIFO_HDR_SZ    4
+#define DIVA_DFIFO_SEGMENT_SZ  (DIVA_DFIFO_DATA_SZ+DIVA_DFIFO_HDR_SZ)
+#define DIVA_DFIFO_SEGMENTS   ((DIVA_DFIFO_RAW_SZ)/(DIVA_DFIFO_SEGMENT_SZ)+1)
+#define DIVA_DFIFO_MEM_SZ (\
+        (DIVA_DFIFO_SEGMENT_SZ)*(DIVA_DFIFO_SEGMENTS)+\
+        (DIVA_DFIFO_CACHE_SZ)*2\
+             )
+#define DIVA_DFIFO_STEP DIVA_DFIFO_SEGMENT_SZ
+/* -------------------------------------------------------------------------
+  Block header layout is:
+   byte[0] -> flags
+   byte[1] -> length of data in block
+   byte[2] -> reserved
+   byte[4] -> reserved
+  ------------------------------------------------------------------------- */
+#define DIVA_DFIFO_WRAP   0x80 /* This is the last block in fifo   */
+#define DIVA_DFIFO_READY  0x40 /* This block is ready for processing */
+#define DIVA_DFIFO_LAST   0x20 /* This block is last in message      */
+#define DIVA_DFIFO_AUTO   0x10 /* Don't look for 'ready', don't ack */
+int diva_dfifo_create (void* start, int length);
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/di.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1033 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "di.h"
+#if !defined USE_EXTENDED_DEBUGS
+  #include "dimaint.h"
+#else
+  #define dprintf
+#endif
+#include "io.h"
+#include "dfifo.h"
+#define PR_RAM  ((struct pr_ram *)0)
+#define RAM ((struct dual *)0)
+/*------------------------------------------------------------------*/
+/* local function prototypes                                        */
+/*------------------------------------------------------------------*/
+void pr_out(ADAPTER * a);
+byte pr_dpc(ADAPTER * a);
+void scom_out(ADAPTER * a);
+byte scom_dpc(ADAPTER * a);
+static byte pr_ready(ADAPTER * a);
+static byte scom_ready(ADAPTER * a);
+static byte isdn_rc(ADAPTER *, byte, byte, byte, word, dword, dword);
+static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
+/* -----------------------------------------------------------------
+    Functions used for the extended XDI Debug
+    macros
+    global convergence counter (used by all adapters)
+    Look by the implementation part of the functions
+    about the parameters.
+    If you change the dubugging parameters, then you should update
+    the aididbg.doc in the IDI doc's.
+   ----------------------------------------------------------------- */
+#if defined(XDI_USE_XLOG)
+#define XDI_A_NR(_x_) ((byte)(((ISDN_ADAPTER *)(_x_->io))->ANum))
+#else
+#define XDI_A_NR(_x_) ((byte)0)
+#endif
+byte xdi_xlog_sec = 0;
+void xdi_xlog (byte *msg, word code, int length);
+static void xdi_xlog_rc_event (byte Adapter,
+                               byte Id, byte Ch, byte Rc, byte cb, byte type);
+static void xdi_xlog_request (byte Adapter, byte Id,
+                              byte Ch, byte Req, byte type);
+static void xdi_xlog_ind (byte Adapter,
+                          byte Id,
+                          byte Ch,
+                          byte Ind,
+                          byte rnr_valid,
+                          byte rnr,
+                          byte type);
+/*------------------------------------------------------------------*/
+/* output function                                                  */
+/*------------------------------------------------------------------*/
+void pr_out(ADAPTER * a)
+{
+  byte e_no;
+  ENTITY  * this = 0;
+  BUFFERS  *X;
+  word length;
+  word i;
+  word clength;
+  REQ * ReqOut;
+  byte more;
+  byte ReadyCount;
+  byte ReqCount;
+  byte Id;
+  dtrc(dprintf("pr_out"));
+        /* while a request is pending ...                           */
+  e_no = look_req(a);
+  if(!e_no)
+  {
+    dtrc(dprintf("no_req"));
+    return;
+  }
+  ReadyCount = pr_ready(a);
+  if(!ReadyCount)
+  {
+    dtrc(dprintf("not_ready"));
+    return;
+  }
+  ReqCount = 0;
+  while(e_no && ReadyCount) {
+    next_req(a);
+    this = entity_ptr(a, e_no);
+#ifdef USE_EXTENDED_DEBUGS
+    if ( !this )
+    {
+      ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+      DBG_FTL(("XDI: [%02x] !A%d ==> NULL entity ptr - try to ignore",
+               xdi_xlog_sec++, (int)io->ANum))
+      e_no = look_req(a) ;
+      ReadyCount-- ;
+      continue ;
+    }
+    {
+      ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+      DBG_TRC((">A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req))
+    }
+#else
+    dbug(dprintf("out:Req=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
+#endif
+        /* get address of next available request buffer             */
+    ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
+#if defined(DIVA_ISTREAM)
+    if (!(a->tx_stream[this->Id]   &&
+        this->Req == N_DATA)) {
+#endif
+        /* now copy the data from the current data buffer into the  */
+        /* adapters request buffer                                  */
+    length = 0;
+    i = this->XCurrent;
+    X = PTR_X(a,this);
+    while(i<this->XNum && length<270) {
+      clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+      a->ram_out_buffer(a,
+                        &ReqOut->XBuffer.P[length],
+                        PTR_P(a,this,&X[i].P[this->XOffset]),
+                        clength);
+      length +=clength;
+      this->XOffset +=clength;
+      if(this->XOffset==X[i].PLength) {
+        this->XCurrent = (byte)++i;
+        this->XOffset = 0;
+      }
+    }
+#if defined(DIVA_ISTREAM)
+   } else { /* Use CMA extension in order to transfer data to the card */
+      i = this->XCurrent;
+      X = PTR_X(a,this);
+      while (i < this->XNum) {
+        diva_istream_write (a,
+                            this->Id,
+                            PTR_P(a,this,&X[i].P[0]),
+                            X[i].PLength,
+                            ((i+1) == this->XNum),
+                            0, 0);
+        this->XCurrent = (byte)++i;
+      }
+      length = 0;
+   }
+#endif
+    a->ram_outw(a, &ReqOut->XBuffer.length, length);
+    a->ram_out(a, &ReqOut->ReqId, this->Id);
+    a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
+        /* if its a specific request (no ASSIGN) ...                */
+    if(this->Id &0x1f) {
+        /* if buffers are left in the list of data buffers do       */
+        /* do chaining (LL_MDATA, N_MDATA)                          */
+      this->More++;
+      if(i<this->XNum && this->MInd) {
+        xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->MInd,
+                          a->IdTypeTable[this->No]);
+        a->ram_out(a, &ReqOut->Req, this->MInd);
+        more = TRUE;
+      }
+      else {
+        xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->Req,
+                          a->IdTypeTable[this->No]);
+        this->More |=XMOREF;
+        a->ram_out(a, &ReqOut->Req, this->Req);
+        more = FALSE;
+        if (a->FlowControlIdTable[this->ReqCh] == this->Id)
+          a->FlowControlSkipTable[this->ReqCh] = TRUE;
+        /*
+           Note that remove request was sent to the card
+           */
+        if (this->Req == REMOVE) {
+          a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING;
+        }
+      }
+        /* if we did chaining, this entity is put back into the     */
+        /* request queue                                            */
+      if(more) {
+        req_queue(a,this->No);
+      }
+    }
+        /* else it's a ASSIGN                                       */
+    else {
+        /* save the request code used for buffer chaining           */
+      this->MInd = 0;
+      if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
+      if (this->Id==NL_ID   ||
+          this->Id==TASK_ID ||
+          this->Id==MAN_ID
+        ) this->MInd = N_MDATA;
+        /* send the ASSIGN                                          */
+      a->IdTypeTable[this->No] = this->Id;
+      xdi_xlog_request (XDI_A_NR(a),this->Id,this->ReqCh,this->Req, this->Id);
+      this->More |=XMOREF;
+      a->ram_out(a, &ReqOut->Req, this->Req);
+        /* save the reference of the ASSIGN                         */
+      assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
+    }
+    a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
+    ReadyCount--;
+    ReqCount++;
+    e_no = look_req(a);
+  }
+        /* send the filled request buffers to the ISDN adapter      */
+  a->ram_out(a, &PR_RAM->ReqInput,
+             (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
+        /* if it is a 'unreturncoded' UREMOVE request, remove the  */
+        /* Id from our table after sending the request             */
+  if(this && (this->Req==UREMOVE) && this->Id) {
+    Id = this->Id;
+    e_no = a->IdTable[Id];
+    free_entity(a, e_no);
+    for (i = 0; i < 256; i++)
+    {
+      if (a->FlowControlIdTable[i] == Id)
+        a->FlowControlIdTable[i] = 0;
+    }
+    a->IdTable[Id] = 0;
+    this->Id = 0;
+  }
+}
+static byte pr_ready(ADAPTER * a)
+{
+  byte ReadyCount;
+  ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
+                      a->ram_in(a, &PR_RAM->ReqInput));
+  if(!ReadyCount) {
+    if(!a->ReadyInt) {
+      a->ram_inc(a, &PR_RAM->ReadyInt);
+      a->ReadyInt++;
+    }
+  }
+  return ReadyCount;
+}
+/*------------------------------------------------------------------*/
+/* isdn interrupt handler                                           */
+/*------------------------------------------------------------------*/
+byte pr_dpc(ADAPTER * a)
+{
+  byte Count;
+  RC * RcIn;
+  IND * IndIn;
+  byte c;
+  byte RNRId;
+  byte Rc;
+  byte Ind;
+        /* if return codes are available ...                        */
+  if((Count = a->ram_in(a, &PR_RAM->RcOutput)) != 0) {
+    dtrc(dprintf("#Rc=%x",Count));
+        /* get the buffer address of the first return code          */
+    RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
+        /* for all return codes do ...                              */
+    while(Count--) {
+      if((Rc=a->ram_in(a, &RcIn->Rc)) != 0) {
+        dword tmp[2];
+        /*
+          Get extended information, associated with return code
+          */
+        a->ram_in_buffer(a,
+                         &RcIn->Reserved2[0],
+                         (byte*)&tmp[0],
+                         8);
+        /* call return code handler, if it is not our return code   */
+        /* the handler returns 2                                    */
+        /* for all return codes we process, we clear the Rc field   */
+        isdn_rc(a,
+                Rc,
+                a->ram_in(a, &RcIn->RcId),
+                a->ram_in(a, &RcIn->RcCh),
+                a->ram_inw(a, &RcIn->Reference),
+                tmp[0],  /* type of extended informtion */
+                tmp[1]); /* extended information        */
+        a->ram_out(a, &RcIn->Rc, 0);
+      }
+        /* get buffer address of next return code                   */
+      RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
+    }
+        /* clear all return codes (no chaining!)                    */
+    a->ram_out(a, &PR_RAM->RcOutput ,0);
+        /* call output function                                     */
+    pr_out(a);
+  }
+        /* clear RNR flag                                           */
+  RNRId = 0;
+        /* if indications are available ...                         */
+  if((Count = a->ram_in(a, &PR_RAM->IndOutput)) != 0) {
+    dtrc(dprintf("#Ind=%x",Count));
+        /* get the buffer address of the first indication           */
+    IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
+        /* for all indications do ...                               */
+    while(Count--) {
+        /* if the application marks an indication as RNR, all       */
+        /* indications from the same Id delivered in this interrupt */
+        /* are marked RNR                                           */
+      if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
+        a->ram_out(a, &IndIn->Ind, 0);
+        a->ram_out(a, &IndIn->RNR, TRUE);
+      }
+      else {
+        Ind = a->ram_in(a, &IndIn->Ind);
+        if(Ind) {
+          RNRId = 0;
+        /* call indication handler, a return value of 2 means chain */
+        /* a return value of 1 means RNR                            */
+        /* for all indications we process, we clear the Ind field   */
+          c = isdn_ind(a,
+                       Ind,
+                       a->ram_in(a, &IndIn->IndId),
+                       a->ram_in(a, &IndIn->IndCh),
+                       &IndIn->RBuffer,
+                       a->ram_in(a, &IndIn->MInd),
+                       a->ram_inw(a, &IndIn->MLength));
+          if(c==1) {
+            dtrc(dprintf("RNR"));
+            a->ram_out(a, &IndIn->Ind, 0);
+            RNRId = a->ram_in(a, &IndIn->IndId);
+            a->ram_out(a, &IndIn->RNR, TRUE);
+          }
+        }
+      }
+        /* get buffer address of next indication                    */
+      IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
+    }
+    a->ram_out(a, &PR_RAM->IndOutput, 0);
+  }
+  return FALSE;
+}
+byte pr_test_int(ADAPTER * a)
+{
+  return a->ram_in(a,(void *)0x3ffc);
+}
+void pr_clear_int(ADAPTER * a)
+{
+  a->ram_out(a,(void *)0x3ffc,0);
+}
+/*------------------------------------------------------------------*/
+/* output function                                                  */
+/*------------------------------------------------------------------*/
+void scom_out(ADAPTER * a)
+{
+  byte e_no;
+  ENTITY  * this;
+  BUFFERS  * X;
+  word length;
+  word i;
+  word clength;
+  byte more;
+  byte Id;
+  dtrc(dprintf("scom_out"));
+        /* check if the adapter is ready to accept an request:      */
+  e_no = look_req(a);
+  if(!e_no)
+  {
+    dtrc(dprintf("no_req"));
+    return;
+  }
+  if(!scom_ready(a))
+  {
+    dtrc(dprintf("not_ready"));
+    return;
+  }
+  this = entity_ptr(a,e_no);
+  dtrc(dprintf("out:Req=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
+  next_req(a);
+        /* now copy the data from the current data buffer into the  */
+        /* adapters request buffer                                  */
+  length = 0;
+  i = this->XCurrent;
+  X = PTR_X(a, this);
+  while(i<this->XNum && length<270) {
+    clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+    a->ram_out_buffer(a,
+                      &RAM->XBuffer.P[length],
+                      PTR_P(a,this,&X[i].P[this->XOffset]),
+                      clength);
+    length +=clength;
+    this->XOffset +=clength;
+    if(this->XOffset==X[i].PLength) {
+      this->XCurrent = (byte)++i;
+      this->XOffset = 0;
+    }
+  }
+  a->ram_outw(a, &RAM->XBuffer.length, length);
+  a->ram_out(a, &RAM->ReqId, this->Id);
+  a->ram_out(a, &RAM->ReqCh, this->ReqCh);
+        /* if its a specific request (no ASSIGN) ...                */
+  if(this->Id &0x1f) {
+        /* if buffers are left in the list of data buffers do       */
+        /* chaining (LL_MDATA, N_MDATA)                             */
+    this->More++;
+    if(i<this->XNum && this->MInd) {
+      a->ram_out(a, &RAM->Req, this->MInd);
+      more = TRUE;
+    }
+    else {
+      this->More |=XMOREF;
+      a->ram_out(a, &RAM->Req, this->Req);
+      more = FALSE;
+      if (a->FlowControlIdTable[this->ReqCh] == this->Id)
+        a->FlowControlSkipTable[this->ReqCh] = TRUE;
+      /*
+         Note that remove request was sent to the card
+         */
+      if (this->Req == REMOVE) {
+        a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING;
+      }
+    }
+    if(more) {
+      req_queue(a,this->No);
+    }
+  }
+        /* else it's a ASSIGN                                       */
+  else {
+        /* save the request code used for buffer chaining           */
+    this->MInd = 0;
+    if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
+    if (this->Id==NL_ID   ||
+        this->Id==TASK_ID ||
+        this->Id==MAN_ID
+      ) this->MInd = N_MDATA;
+        /* send the ASSIGN                                          */
+    this->More |=XMOREF;
+    a->ram_out(a, &RAM->Req, this->Req);
+        /* save the reference of the ASSIGN                         */
+    assign_queue(a, this->No, 0);
+  }
+        /* if it is a 'unreturncoded' UREMOVE request, remove the  */
+        /* Id from our table after sending the request             */
+  if(this->Req==UREMOVE && this->Id) {
+    Id = this->Id;
+    e_no = a->IdTable[Id];
+    free_entity(a, e_no);
+    for (i = 0; i < 256; i++)
+    {
+      if (a->FlowControlIdTable[i] == Id)
+        a->FlowControlIdTable[i] = 0;
+    }
+    a->IdTable[Id] = 0;
+    this->Id = 0;
+  }
+}
+static byte scom_ready(ADAPTER * a)
+{
+  if(a->ram_in(a, &RAM->Req)) {
+    if(!a->ReadyInt) {
+      a->ram_inc(a, &RAM->ReadyInt);
+      a->ReadyInt++;
+    }
+    return 0;
+  }
+  return 1;
+}
+/*------------------------------------------------------------------*/
+/* isdn interrupt handler                                           */
+/*------------------------------------------------------------------*/
+byte scom_dpc(ADAPTER * a)
+{
+  byte c;
+        /* if a return code is available ...                        */
+  if(a->ram_in(a, &RAM->Rc)) {
+        /* call return code handler, if it is not our return code   */
+        /* the handler returns 2, if it's the return code to an     */
+        /* ASSIGN the handler returns 1                             */
+    c = isdn_rc(a,
+                a->ram_in(a, &RAM->Rc),
+                a->ram_in(a, &RAM->RcId),
+                a->ram_in(a, &RAM->RcCh),
+                0,
+                /*
+                  Scom Card does not provide extended information
+                  */
+                0, 0);
+    switch(c) {
+    case 0:
+      a->ram_out(a, &RAM->Rc, 0);
+      break;
+    case 1:
+      a->ram_out(a, &RAM->Req, 0);
+      a->ram_out(a, &RAM->Rc, 0);
+      break;
+    case 2:
+      return TRUE;
+    }
+        /* call output function                                     */
+    scom_out(a);
+  }
+  else {
+        /* if an indications is available ...                       */
+    if(a->ram_in(a, &RAM->Ind)) {
+        /* call indication handler, a return value of 2 means chain */
+        /* a return value of 1 means RNR                            */
+      c = isdn_ind(a,
+                   a->ram_in(a, &RAM->Ind),
+                   a->ram_in(a, &RAM->IndId),
+                   a->ram_in(a, &RAM->IndCh),
+                   &RAM->RBuffer,
+                   a->ram_in(a, &RAM->MInd),
+                   a->ram_inw(a, &RAM->MLength));
+      switch(c) {
+      case 0:
+        a->ram_out(a, &RAM->Ind, 0);
+        break;
+      case 1:
+        dtrc(dprintf("RNR"));
+        a->ram_out(a, &RAM->RNR, TRUE);
+        break;
+      case 2:
+        return TRUE;
+      }
+    }
+  }
+  return FALSE;
+}
+byte scom_test_int(ADAPTER * a)
+{
+  return a->ram_in(a,(void *)0x3fe);
+}
+void scom_clear_int(ADAPTER * a)
+{
+  a->ram_out(a,(void *)0x3fe,0);
+}
+void quadro_clear_int(ADAPTER * a)
+{
+  a->ram_out(a,(void *)0x3fe,0);
+  a->ram_out(a,(void *)0x401,0);
+}
+/*------------------------------------------------------------------*/
+/* return code handler                                              */
+/*------------------------------------------------------------------*/
+byte isdn_rc(ADAPTER * a,
+             byte Rc,
+             byte Id,
+             byte Ch,
+             word Ref,
+             dword extended_info_type,
+             dword extended_info)
+{
+  ENTITY  * this;
+  byte e_no;
+  word i;
+  int cancel_rc;
+#ifdef USE_EXTENDED_DEBUGS
+  {
+    ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+    DBG_TRC(("<A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
+  }
+#else
+  dbug(dprintf("isdn_rc(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
+#endif
+        /* check for ready interrupt                                */
+  if(Rc==READY_INT) {
+    xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, 0);
+    if(a->ReadyInt) {
+      a->ReadyInt--;
+      return 0;
+    }
+    return 2;
+  }
+        /* if we know this Id ...                                   */
+  e_no = a->IdTable[Id];
+  if(e_no) {
+    this = entity_ptr(a,e_no);
+    xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, a->IdTypeTable[this->No]);
+    this->RcCh = Ch;
+        /* if it is a return code to a REMOVE request, remove the   */
+        /* Id from our table                                        */
+    if ((a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_REMOVE_PENDING) &&
+        (Rc==OK)) {
+      if (a->IdTypeTable[e_no] == NL_ID) {
+        if (a->RcExtensionSupported &&
+            (extended_info_type != DIVA_RC_TYPE_REMOVE_COMPLETE)) {
+        dtrc(dprintf("XDI: N-REMOVE, A(%02x) Id:%02x, ignore RC=OK",
+                        XDI_A_NR(a),Id));
+          return (0);
+        }
+        if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE)
+          a->RcExtensionSupported = TRUE;
+      }
+      a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING;
+      a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING;
+      free_entity(a, e_no);
+      for (i = 0; i < 256; i++)
+      {
+        if (a->FlowControlIdTable[i] == Id)
+          a->FlowControlIdTable[i] = 0;
+      }
+      a->IdTable[Id] = 0;
+      this->Id = 0;
+      /* ---------------------------------------------------------------
+        If we send N_DISC or N_DISK_ACK after we have received OK_FC
+        then the card will respond with OK_FC and later with RC==OK.
+        If we send N_REMOVE in this state we will receive only RC==OK
+        This will create the state in that the XDI is waiting for the
+        additional RC and does not delivery the RC to the client. This
+        code corrects the counter of outstanding RC's in this case.
+      --------------------------------------------------------------- */
+      if ((this->More & XMOREC) > 1) {
+        this->More &= ~XMOREC;
+        this->More |= 1;
+        dtrc(dprintf("XDI: correct MORE on REMOVE A(%02x) Id:%02x",
+                     XDI_A_NR(a),Id));
+      }
+    }
+    if (Rc==OK_FC) {
+      a->FlowControlIdTable[Ch] = Id;
+      a->FlowControlSkipTable[Ch] = FALSE;
+      this->Rc = Rc;
+      this->More &= ~(XBUSY | XMOREC);
+      this->complete=0xff;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+      CALLBACK(a, this);
+      return 0;
+    }
+    /*
+      New protocol code sends return codes that comes from release
+      of flow control condition marked with DIVA_RC_TYPE_OK_FC extended
+      information element type.
+      If like return code arrives then application is able to process
+      all return codes self and XDI should not cances return codes.
+      This return code does not decrement XMOREC partial return code
+      counter due to fact that it was no request for this return code,
+      also XMOREC was not incremented.
+      */
+    if (extended_info_type == DIVA_RC_TYPE_OK_FC) {
+      a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_NO_RC_CANCELLING;
+      this->Rc = Rc;
+      this->complete=0xff;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+      DBG_TRC(("XDI OK_FC A(%02x) Id:%02x Ch:%02x Rc:%02x",
+      XDI_A_NR(a), Id, Ch, Rc))
+      CALLBACK(a, this);
+      return 0;
+    }
+    cancel_rc = !(a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_NO_RC_CANCELLING);
+    if (cancel_rc && (a->FlowControlIdTable[Ch] == Id))
+    {
+      a->FlowControlIdTable[Ch] = 0;
+      if ((Rc != OK) || !a->FlowControlSkipTable[Ch])
+      {
+        this->Rc = Rc;
+        if (Ch == this->ReqCh)
+        {
+          this->More &=~(XBUSY | XMOREC);
+          this->complete=0xff;
+        }
+        xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+        CALLBACK(a, this);
+      }
+      return 0;
+    }
+    if (this->More &XMOREC)
+      this->More--;
+        /* call the application callback function                   */
+    if (((!cancel_rc) || (this->More & XMOREF)) && !(this->More & XMOREC)) {
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+        /* if it's an ASSIGN return code check if it's a return     */
+        /* code to an ASSIGN request from us                        */
+  if((Rc &0xf0)==ASSIGN_RC) {
+    e_no = get_assign(a, Ref);
+    if(e_no) {
+      this = entity_ptr(a,e_no);
+      this->Id = Id;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 2, a->IdTypeTable[this->No]);
+        /* call the application callback function                   */
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+#if defined(DIVA_ISTREAM) /* { */
+      if ((Rc == ASSIGN_OK) && a->ram_offset &&
+          (a->IdTypeTable[this->No] == NL_ID) &&
+          ((extended_info_type == DIVA_RC_TYPE_RX_DMA) ||
+          (extended_info_type == DIVA_RC_TYPE_CMA_PTR)) &&
+          extended_info) {
+        dword offset = (*(a->ram_offset)) (a);
+        dword tmp[2];
+        extended_info -= offset;
+#ifdef PLATFORM_GT_32BIT
+        a->ram_in_dw(a, (void*)ULongToPtr(extended_info), (dword*)&tmp[0], 2);
+#else
+        a->ram_in_dw(a, (void*)extended_info, (dword*)&tmp[0], 2);
+#endif
+        a->tx_stream[Id]  = tmp[0];
+        a->rx_stream[Id]  = tmp[1];
+        if (extended_info_type == DIVA_RC_TYPE_RX_DMA) {
+          DBG_TRC(("Id=0x%x RxDMA=%08x:%08x",
+                    Id, a->tx_stream[Id], a->rx_stream[Id]))
+          a->misc_flags_table[this->No] |= DIVA_MISC_FLAGS_RX_DMA;
+        } else {
+          DBG_TRC(("Id=0x%x CMA=%08x:%08x",
+                    Id, a->tx_stream[Id], a->rx_stream[Id]))
+          a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
+          a->rx_pos[Id]     = 0;
+          a->rx_stream[Id] -= offset;
+        }
+        a->tx_pos[Id]     = 0;
+        a->tx_stream[Id] -= offset;
+      } else {
+        a->tx_stream[Id] = 0;
+        a->rx_stream[Id] = 0;
+        a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
+      }
+#endif /* } */
+      CALLBACK(a, this);
+      if(Rc==ASSIGN_OK) {
+        a->IdTable[Id] = e_no;
+      }
+      else
+      {
+        free_entity(a, e_no);
+        for (i = 0; i < 256; i++)
+        {
+          if (a->FlowControlIdTable[i] == Id)
+            a->FlowControlIdTable[i] = 0;
+        }
+        a->IdTable[Id] = 0;
+        this->Id = 0;
+      }
+      return 1;
+    }
+  }
+  return 2;
+}
+/*------------------------------------------------------------------*/
+/* indication handler                                               */
+/*------------------------------------------------------------------*/
+byte isdn_ind(ADAPTER * a,
+              byte Ind,
+              byte Id,
+              byte Ch,
+              PBUFFER * RBuffer,
+              byte MInd,
+              word MLength)
+{
+  ENTITY  * this;
+  word clength;
+  word offset;
+  BUFFERS  *R;
+  byte* cma = 0;
+#ifdef USE_EXTENDED_DEBUGS
+  {
+    ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+    DBG_TRC(("<A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
+  }
+#else
+  dbug(dprintf("isdn_ind(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
+#endif
+  if(a->IdTable[Id]) {
+    this = entity_ptr(a,a->IdTable[Id]);
+    this->IndCh = Ch;
+    xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+                  0/* rnr_valid */, 0 /* rnr */, a->IdTypeTable[this->No]);
+        /* if the Receive More flag is not yet set, this is the     */
+        /* first buffer of the packet                               */
+    if(this->RCurrent==0xff) {
+        /* check for receive buffer chaining                        */
+      if(Ind==this->MInd) {
+        this->complete = 0;
+        this->Ind = MInd;
+      }
+      else {
+        this->complete = 1;
+        this->Ind = Ind;
+      }
+        /* call the application callback function for the receive   */
+        /* look ahead                                               */
+      this->RLength = MLength;
+#if defined(DIVA_ISTREAM)
+      if ((a->rx_stream[this->Id] ||
+           (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA)) &&
+          ((Ind == N_DATA) ||
+           (a->protocol_capabilities & PROTCAP_CMA_ALLPR))) {
+        PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
+        if (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA) {
+#if defined(DIVA_IDI_RX_DMA)
+          dword d;
+          diva_get_dma_map_entry (\
+                   (struct _diva_dma_map_entry*)IoAdapter->dma_map,
+                   (int)a->rx_stream[this->Id], (void**)&cma, &d);
+#else
+          cma = &a->stream_buffer[0];
+          cma[0] = cma[1] = cma[2] = cma[3] = 0;
+#endif
+          this->RLength = MLength = (word)*(dword*)cma;
+          cma += 4;
+        } else {
+        int final = 0;
+        cma = &a->stream_buffer[0];
+        this->RLength = MLength = (word)diva_istream_read (a,
+                                                     Id,
+                                                     cma,
+                                                     sizeof(a->stream_buffer),
+                                                     &final, 0, 0);
+        }
+        IoAdapter->RBuffer.length = MIN(MLength, 270);
+        if (IoAdapter->RBuffer.length != MLength) {
+          this->complete = 0;
+        } else {
+          this->complete = 1;
+        }
+        memcpy (IoAdapter->RBuffer.P, cma, IoAdapter->RBuffer.length) ;
+        this->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
+      }
+#endif
+      if (!cma) {
+        a->ram_look_ahead(a, RBuffer, this);
+      }
+      this->RNum = 0;
+      CALLBACK(a, this);
+        /* map entity ptr, selector could be re-mapped by call to   */
+        /* IDI from within callback                                 */
+      this = entity_ptr(a,a->IdTable[Id]);
+      xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+          1/* rnr_valid */, this->RNR/* rnr */, a->IdTypeTable[this->No]);
+        /* check for RNR                                            */
+      if(this->RNR==1) {
+        this->RNR = 0;
+        return 1;
+      }
+        /* if no buffers are provided by the application, the       */
+        /* application want to copy the data itself including       */
+        /* N_MDATA/LL_MDATA chaining                                */
+      if(!this->RNR && !this->RNum) {
+        xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+            2/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
+        return 0;
+      }
+        /* if there is no RNR, set the More flag                    */
+      this->RCurrent = 0;
+      this->ROffset = 0;
+    }
+    if(this->RNR==2) {
+      if(Ind!=this->MInd) {
+        this->RCurrent = 0xff;
+        this->RNR = 0;
+      }
+      return 0;
+    }
+        /* if we have received buffers from the application, copy   */
+        /* the data into these buffers                              */
+    offset = 0;
+    R = PTR_R(a,this);
+    do {
+      if(this->ROffset==R[this->RCurrent].PLength) {
+        this->ROffset = 0;
+        this->RCurrent++;
+      }
+      if (cma) {
+        clength = MIN(MLength, R[this->RCurrent].PLength-this->ROffset);
+      } else {
+        clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
+                      R[this->RCurrent].PLength-this->ROffset);
+      }
+      if(R[this->RCurrent].P) {
+        if (cma) {
+          memcpy (PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
+                  &cma[offset],
+                  clength);
+        } else {
+          a->ram_in_buffer(a,
+                           &RBuffer->P[offset],
+                           PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
+                           clength);
+        }
+      }
+      offset +=clength;
+      this->ROffset +=clength;
+      if (cma) {
+        if (offset >= MLength) {
+          break;
+        }
+        continue;
+      }
+    } while(offset<(a->ram_inw(a, &RBuffer->length)));
+        /* if it's the last buffer of the packet, call the          */
+        /* application callback function for the receive complete   */
+        /* call                                                     */
+    if(Ind!=this->MInd) {
+      R[this->RCurrent].PLength = this->ROffset;
+      if(this->ROffset) this->RCurrent++;
+      this->RNum = this->RCurrent;
+      this->RCurrent = 0xff;
+      this->Ind = Ind;
+      this->complete = 2;
+      xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+          3/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+  return 2;
+}
+/* -----------------------------------------------------------
+   This function works in the same way as xlog on the
+   active board
+   ----------------------------------------------------------- */
+void xdi_xlog (byte *msg, word code, int length) {
+#if defined(XDI_USE_XLOG)
+  xdi_dbg_xlog ("\x00\x02", msg, code, length);
+#endif
+}
+/* -----------------------------------------------------------
+    This function writes the information about the Return Code
+    processing in the trace buffer. Trace ID is 221.
+    INPUT:
+        Adapter - system unicue adapter number (0 ... 255)
+        Id      - Id of the entity that had sent this return code
+        Ch      - Channel of the entity that had sent this return code
+        Rc      - return code value
+        cb:       (0...2)
+                  switch (cb) {
+                   case 0: printf ("DELIVERY"); break;
+                   case 1: printf ("CALLBACK"); break;
+                   case 2: printf ("ASSIGN"); break;
+                  }
+                  DELIVERY - have entered isdn_rc with this RC
+                  CALLBACK - about to make callback to the application
+                             for this RC
+                  ASSIGN   - about to make callback for RC that is result
+                             of ASSIGN request. It is no DELIVERY message
+                             before of this message
+        type   - the Id that was sent by the ASSIGN of this entity.
+                 This should be global Id like NL_ID, DSIG_ID, MAN_ID.
+                 An unknown Id will cause "?-" in the front of the request.
+                 In this case the log.c is to be extended.
+   ----------------------------------------------------------- */
+static void xdi_xlog_rc_event (byte Adapter,
+                               byte Id, byte Ch, byte Rc, byte cb, byte type) {
+#if defined(XDI_USE_XLOG)
+  word LogInfo[4];
+  LogInfo[0] = (word)Adapter | (word)(xdi_xlog_sec++ << 8);
+  LogInfo[1] = (word)Id | (word)(Ch << 8);
+  LogInfo[2] = (word)Rc | (word)(type << 8);
+  LogInfo[3] = cb;
+  xdi_xlog ((byte*)&LogInfo[0], 221, sizeof(LogInfo));
+#endif
+}
+/* ------------------------------------------------------------------------
+    This function writes the information about the request processing
+    in the trace buffer. Trace ID is 220.
+    INPUT:
+        Adapter - system unicue adapter number (0 ... 255)
+        Id      - Id of the entity that had sent this request
+        Ch      - Channel of the entity that had sent this request
+        Req     - Code of the request
+        type    - the Id that was sent by the ASSIGN of this entity.
+                  This should be global Id like NL_ID, DSIG_ID, MAN_ID.
+                  An unknown Id will cause "?-" in the front of the request.
+                  In this case the log.c is to be extended.
+   ------------------------------------------------------------------------ */
+static void xdi_xlog_request (byte Adapter, byte Id,
+                              byte Ch, byte Req, byte type) {
+#if defined(XDI_USE_XLOG)
+  word LogInfo[3];
+  LogInfo[0] = (word)Adapter | (word)(xdi_xlog_sec++ << 8);
+  LogInfo[1] = (word)Id | (word)(Ch << 8);
+  LogInfo[2] = (word)Req | (word)(type << 8);
+  xdi_xlog ((byte*)&LogInfo[0], 220, sizeof(LogInfo));
+#endif
+}
+/* ------------------------------------------------------------------------
+    This function writes the information about the indication processing
+    in the trace buffer. Trace ID is 222.
+    INPUT:
+        Adapter - system unicue adapter number (0 ... 255)
+        Id      - Id of the entity that had sent this indication
+        Ch      - Channel of the entity that had sent this indication
+        Ind     - Code of the indication
+        rnr_valid: (0 .. 3) supported
+          switch (rnr_valid) {
+            case 0: printf ("DELIVERY"); break;
+            case 1: printf ("RNR=%d", rnr);
+            case 2: printf ("RNum=0");
+            case 3: printf ("COMPLETE");
+          }
+          DELIVERY - indication entered isdn_rc function
+          RNR=...  - application had returned RNR=... after the
+                     look ahead callback
+          RNum=0   - aplication had not returned any buffer to copy
+                     this indication and will copy it self
+          COMPLETE - XDI had copied the data to the buffers provided
+                     bu the application and is about to issue the
+                     final callback
+        rnr:  Look case 1 of the rnr_valid
+        type: the Id that was sent by the ASSIGN of this entity. This should
+              be global Id like NL_ID, DSIG_ID, MAN_ID. An unknown Id will
+              cause "?-" in the front of the request. In this case the
+              log.c is to be extended.
+   ------------------------------------------------------------------------ */
+static void xdi_xlog_ind (byte Adapter,
+                          byte Id,
+                          byte Ch,
+                          byte Ind,
+                          byte rnr_valid,
+                          byte rnr,
+                          byte type) {
+#if defined(XDI_USE_XLOG)
+  word LogInfo[4];
+  LogInfo[0] = (word)Adapter | (word)(xdi_xlog_sec++ << 8);
+  LogInfo[1] = (word)Id | (word)(Ch << 8);
+  LogInfo[2] = (word)Ind | (word)(type << 8);
+  LogInfo[3] = (word)rnr | (word)(rnr_valid << 8);
+  xdi_xlog ((byte*)&LogInfo[0], 222, sizeof(LogInfo));
+#endif
+}
diff -Nru a/drivers/isdn/hardware/eicon/di.h b/drivers/isdn/hardware/eicon/di.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/di.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,123 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+/*
+ *  some macros for detailed trace management
+ */
+#include "di_dbg.h"
+/*****************************************************************************/
+#define XMOREC 0x1f
+#define XMOREF 0x20
+#define XBUSY  0x40
+#define RMORE  0x80
+#define DIVA_MISC_FLAGS_REMOVE_PENDING    0x01
+#define DIVA_MISC_FLAGS_NO_RC_CANCELLING  0x02
+#define DIVA_MISC_FLAGS_RX_DMA            0x04
+        /* structure for all information we have to keep on a per   */
+        /* adapater basis                                           */
+typedef struct adapter_s ADAPTER;
+struct adapter_s {
+  void * io;
+  byte IdTable[256];
+  byte IdTypeTable[256];
+  byte FlowControlIdTable[256];
+  byte FlowControlSkipTable[256];
+  byte ReadyInt;
+  byte RcExtensionSupported;
+  byte misc_flags_table[256];
+  dword protocol_capabilities;
+  byte ( * ram_in)(ADAPTER * a, void * adr);
+  word ( * ram_inw)(ADAPTER * a, void * adr);
+  void (* ram_in_buffer)(ADAPTER * a, void * adr, void  * P, word length);
+  void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY  * e);
+  void ( * ram_out)(ADAPTER * a, void * adr, byte data);
+  void ( * ram_outw)(ADAPTER * a, void * adr, word data);
+  void (* ram_out_buffer)(ADAPTER * a, void * adr, void  * P, word length);
+  void ( * ram_inc)(ADAPTER * a, void * adr);
+#if defined(DIVA_ISTREAM)
+  dword rx_stream[256];
+  dword tx_stream[256];
+  word tx_pos[256];
+  word rx_pos[256];
+  byte stream_buffer[2512];
+  dword ( * ram_offset)(ADAPTER * a);
+  void ( * ram_out_dw) (ADAPTER *a,
+                                    void *addr,
+                                    const dword* data,
+                                    int dwords);
+  void ( * ram_in_dw) (ADAPTER *a,
+                                   void *addr,
+                                   dword* data,
+                                   int dwords);
+  void ( * istream_wakeup)(ADAPTER* a);
+#else
+  byte stream_buffer[4];
+#endif
+};
+/*------------------------------------------------------------------*/
+/* public functions of IDI common code                              */
+/*------------------------------------------------------------------*/
+void pr_out(ADAPTER * a);
+byte pr_dpc(ADAPTER * a);
+byte pr_test_int(ADAPTER * a);
+void pr_clear_int(ADAPTER * a);
+void scom_out(ADAPTER * a);
+byte scom_dpc(ADAPTER * a);
+byte scom_test_int(ADAPTER * a);
+void scom_clear_int(ADAPTER * a);
+void quadro_clear_int(ADAPTER * a);
+/*------------------------------------------------------------------*/
+/* OS specific functions used by IDI common code                    */
+/*------------------------------------------------------------------*/
+void free_entity(ADAPTER * a, byte e_no);
+void assign_queue(ADAPTER * a, byte e_no, word ref);
+byte get_assign(ADAPTER * a, word ref);
+void req_queue(ADAPTER * a, byte e_no);
+byte look_req(ADAPTER * a);
+void next_req(ADAPTER * a);
+ENTITY  * entity_ptr(ADAPTER * a, byte e_no);
+#if defined(DIVA_ISTREAM)
+struct _diva_xdi_stream_interface;
+void diva_xdi_provide_istream_info (ADAPTER* a,
+                                    struct _diva_xdi_stream_interface* pI);
+void pr_stream (ADAPTER * a);
+int diva_istream_write (void* context,
+                        int Id,
+                        void* data,
+                        int length,
+                        int final,
+                        byte usr1,
+                        byte usr2);
+int diva_istream_read (void* context,
+                        int Id,
+                        void* data,
+                        int max_length,
+                        int* final,
+                        byte* usr1,
+                        byte* usr2);
+#if defined(DIVA_IDI_RX_DMA)
+#include "diva_dma.h"
+#endif
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/di_dbg.h b/drivers/isdn/hardware/eicon/di_dbg.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/di_dbg.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,37 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_DI_DBG_INC__
+#define __DIVA_DI_DBG_INC__
+#if !defined (dtrc)
+#define dtrc(a)
+#endif
+#if !defined (dbug)
+#define dbug(a)
+#endif
+#if !defined USE_EXTENDED_DEBUGS
+extern void (*dprintf)(char*, ...);
+#endif
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/di_defs.h b/drivers/isdn/hardware/eicon/di_defs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/di_defs.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,181 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef _DI_DEFS_  
+#define _DI_DEFS_
+        /* typedefs for our data structures                         */
+typedef struct get_name_s GET_NAME;
+/*  The entity_s structure is used to pass all
+    parameters between application and IDI   */
+typedef struct entity_s ENTITY;
+typedef struct buffers_s BUFFERS;
+typedef struct postcall_s POSTCALL;
+typedef struct get_para_s GET_PARA;
+#define BOARD_NAME_LENGTH 9
+#define IDI_CALL_LINK_T
+#define IDI_CALL_ENTITY_T
+/* typedef void ( * IDI_CALL)(ENTITY *); */
+/* --------------------------------------------------------
+    IDI_CALL
+   -------------------------------------------------------- */
+typedef void (IDI_CALL_LINK_T * IDI_CALL)(ENTITY IDI_CALL_ENTITY_T *);
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} DBUFFER;
+struct get_name_s {
+  word command;         /* command = 0x0100 */
+  byte name[BOARD_NAME_LENGTH];
+};
+struct postcall_s {
+  word      command;                           /* command = 0x0300 */
+  word      dummy;                             /* not used */
+  void      (  * callback)(void   *);      /* call back */
+  void    *context;                          /* context pointer */
+};
+#define REQ_PARA            0x0600   /* request command line parameters */
+#define REQ_PARA_LEN             1   /* number of data bytes */
+#define L1_STARTUP_DOWN_POS      0   /* '-y' command line parameter in......*/
+#define L1_STARTUP_DOWN_MSK   0x01   /* first byte position (index 0) with value 0x01 */
+struct get_para_s {
+  word  command;            /* command = 0x0600 */
+  byte  len;                /* max length of para field in bytes */
+  byte  para[REQ_PARA_LEN]; /* parameter field */
+};
+struct buffers_s {
+  word PLength;
+  byte   * P;
+};
+struct entity_s {
+  byte                  Req;            /* pending request          */
+  byte                  Rc;             /* return code received     */
+  byte                  Ind;            /* indication received      */
+  byte                  ReqCh;          /* channel of current Req   */
+  byte                  RcCh;           /* channel of current Rc    */
+  byte                  IndCh;          /* channel of current Ind   */
+  byte                  Id;             /* ID used by this entity   */
+  byte                  GlobalId;       /* reserved field           */
+  byte                  XNum;           /* number of X-buffers      */
+  byte                  RNum;           /* number of R-buffers      */
+  BUFFERS                 * X;        /* pointer to X-buffer list */
+  BUFFERS                 * R;        /* pointer to R-buffer list */
+  word                  RLength;        /* length of current R-data */
+  DBUFFER   *         RBuffer;        /* buffer of current R-data */
+  byte                  RNR;            /* receive not ready flag   */
+  byte                  complete;       /* receive complete status  */
+  IDI_CALL              callback;
+  word                  user[2];
+        /* fields used by the driver internally                     */
+  byte                  No;             /* entity number            */
+  byte                  reserved2;      /* reserved field           */
+  byte                  More;           /* R/X More flags           */
+  byte                  MInd;           /* MDATA coding for this ID */
+  byte                  XCurrent;       /* current transmit buffer  */
+  byte                  RCurrent;       /* current receive buffer   */
+  word                  XOffset;        /* offset in x-buffer       */
+  word                  ROffset;        /* offset in r-buffer       */
+};
+typedef struct {
+  byte                  type;
+  byte                  channels;
+  word                  features;
+  IDI_CALL              request;
+} DESCRIPTOR;
+        /* descriptor type field coding */
+#define IDI_ADAPTER_S           1
+#define IDI_ADAPTER_PR          2
+#define IDI_ADAPTER_DIVA        3
+#define IDI_ADAPTER_MAESTRA     4
+#define IDI_VADAPTER            0x40
+#define IDI_DRIVER              0x80
+#define IDI_DADAPTER            0xfd
+#define IDI_DIDDPNP             0xfe
+#define IDI_DIMAINT             0xff
+        /* Hardware IDs ISA PNP */
+#define HW_ID_DIVA_PRO     3    /* same as IDI_ADAPTER_DIVA    */
+#define HW_ID_MAESTRA      4    /* same as IDI_ADAPTER_MAESTRA */
+#define HW_ID_PICCOLA      5
+#define HW_ID_DIVA_PRO20   6
+#define HW_ID_DIVA20       7
+#define HW_ID_DIVA_PRO20_U 8
+#define HW_ID_DIVA20_U     9
+#define HW_ID_DIVA30       10
+#define HW_ID_DIVA30_U     11
+        /* Hardware IDs PCI */
+#define HW_ID_EICON_PCI              0x1133
+#define HW_ID_SIEMENS_PCI            0x8001 /* unused SubVendor ID for Siemens Cornet-N cards */
+#define HW_ID_PROTTYPE_CORNETN       0x0014 /* SubDevice ID for Siemens Cornet-N cards */
+#define HW_ID_FUJITSU_SIEMENS_PCI    0x110A /* SubVendor ID for Fujitsu Siemens */
+#define HW_ID_GS03_PCI               0x0021 /* SubDevice ID for Fujitsu Siemens ISDN S0 card */
+#define HW_ID_DIVA_PRO20_PCI         0xe001
+#define HW_ID_DIVA20_PCI             0xe002
+#define HW_ID_DIVA_PRO20_PCI_U       0xe003
+#define HW_ID_DIVA20_PCI_U           0xe004
+#define HW_ID_DIVA201_PCI            0xe005
+#define HW_ID_DIVA_CT_ST             0xe006
+#define HW_ID_DIVA_CT_U              0xe007
+#define HW_ID_DIVA_CTL_ST            0xe008
+#define HW_ID_DIVA_CTL_U             0xe009
+#define HW_ID_DIVA_ISDN_V90_PCI      0xe00a
+#define HW_ID_DIVA202_PCI_ST         0xe00b
+#define HW_ID_DIVA202_PCI_U          0xe00c
+#define HW_ID_DIVA_PRO30_PCI         0xe00d
+#define HW_ID_MAESTRA_PCI            0xe010
+#define HW_ID_MAESTRAQ_PCI           0xe012
+#define HW_ID_DSRV_Q8M_V2_PCI        0xe013
+#define HW_ID_MAESTRAP_PCI           0xe014
+#define HW_ID_DSRV_P30M_V2_PCI       0xe015
+#define HW_ID_DSRV_VOICE_Q8M_PCI     0xe016
+#define HW_ID_DSRV_VOICE_Q8M_V2_PCI  0xe017
+#define HW_ID_DSRV_B2M_V2_PCI        0xe018
+#define HW_ID_DSRV_VOICE_P30M_V2_PCI 0xe019
+#define HW_ID_DSRV_B2F_PCI           0xe01a
+#define HW_ID_DSRV_VOICE_B2M_V2_PCI  0xe01b
+        /* Hardware IDs USB */
+#define EICON_USB_VENDOR_ID          0x071D
+#define HW_ID_DIVA_USB_REV1          0x1000
+#define HW_ID_DIVA_USB_REV2          0x1003
+#define HW_ID_TELEDAT_SURF_USB_REV2  0x1004
+#define HW_ID_TELEDAT_SURF_USB_REV1  0x2000
+/* --------------------------------------------------------------------------
+  Adapter array change notification framework
+  -------------------------------------------------------------------------- */
+typedef void (IDI_CALL_LINK_T* didd_adapter_change_callback_t)(     void IDI_CALL_ENTITY_T * context, DESCRIPTOR* adapter, int removal);
+/* -------------------------------------------------------------------------- */
+#define DI_VOICE          0x0 /* obsolete define */
+#define DI_FAX3           0x1
+#define DI_MODEM          0x2
+#define DI_POST           0x4
+#define DI_V110           0x8
+#define DI_V120           0x10
+#define DI_POTS           0x20
+#define DI_CODEC          0x40
+#define DI_MANAGE         0x80
+#define DI_V_42           0x0100
+#define DI_EXTD_FAX       0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
+#define DI_AT_PARSER      0x0400 /* Build-in AT Parser in the L2 */
+#define DI_VOICE_OVER_IP  0x0800 /* Voice over IP support */
+typedef void (IDI_CALL_LINK_T* _IDI_CALL)(void*, ENTITY*);  
+#endif  
diff -Nru a/drivers/isdn/hardware/eicon/did_vers.h b/drivers/isdn/hardware/eicon/did_vers.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/did_vers.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,26 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+static char diva_didd_common_code_build[] = "102-51";  
diff -Nru a/drivers/isdn/hardware/eicon/diddfunc.c b/drivers/isdn/hardware/eicon/diddfunc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/diddfunc.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,126 @@
+/* $Id: diddfunc.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * DIDD Interface module for Eicon active cards.
+ * 
+ * Functions are in dadapter.c 
+ * 
+ * Copyright 2002 by Armin Schindler (mac@melware.de) 
+ * Copyright 2002 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "dadapter.h"
+#include "divasync.h"
+
+#define MAX_DESCRIPTORS  32
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+
+extern void DIVA_DIDD_Read (void *, int);
+extern char *DRIVERRELEASE;
+static dword notify_handle;
+static DESCRIPTOR _DAdapter;
+
+/*
+ * didd callback function
+ */
+static void *
+didd_callback(void *context, DESCRIPTOR* adapter, int removal)
+{
+  if (adapter->type == IDI_DADAPTER)
+  {
+    DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."))
+    return(NULL);
+  }
+  else if (adapter->type == IDI_DIMAINT)
+  {
+    if (removal) {
+				DbgDeregister();
+		} else {
+				DbgRegister("DIDD", DRIVERRELEASE, DBG_DEFAULT);
+		}
+  }
+  return(NULL);
+}
+
+/*
+ * connect to didd
+ */
+static int DIVA_INIT_FUNCTION
+connect_didd(void)
+{
+  int x = 0;
+  int dadapter = 0;
+  IDI_SYNC_REQ req;
+  DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+  DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+  for (x = 0; x < MAX_DESCRIPTORS; x++)
+  {
+    if (DIDD_Table[x].type == IDI_DADAPTER)
+    {  /* DADAPTER found */
+      dadapter = 1;
+      memcpy(&_DAdapter, &DIDD_Table[x], sizeof(_DAdapter));
+      req.didd_notify.e.Req = 0;
+      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+      req.didd_notify.info.callback = didd_callback;
+      req.didd_notify.info.context = 0;
+      _DAdapter.request((ENTITY *)&req);
+      if (req.didd_notify.e.Rc != 0xff)
+        return(0);
+      notify_handle = req.didd_notify.info.handle;
+    }
+    else if (DIDD_Table[x].type == IDI_DIMAINT)
+    {  /* MAINT found */
+      DbgRegister("DIDD", DRIVERRELEASE, DBG_DEFAULT);
+    }
+  }
+  return(dadapter);
+}
+
+/*
+ * disconnect from didd
+ */
+static void DIVA_EXIT_FUNCTION
+disconnect_didd(void)
+{
+  IDI_SYNC_REQ req;
+
+  req.didd_notify.e.Req = 0;
+  req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+  req.didd_notify.info.handle = notify_handle;
+  _DAdapter.request((ENTITY *)&req);
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION diddfunc_init(void)
+{
+  diva_didd_load_time_init();
+
+  if(!connect_didd()) {
+    DBG_ERR(("init: failed to connect to DIDD."))
+    diva_didd_load_time_finit();
+    return(0);
+  }
+  return(1);
+}
+
+/*
+ * finit
+ */
+void DIVA_EXIT_FUNCTION diddfunc_finit(void)
+{
+  DbgDeregister();
+  disconnect_didd();
+  diva_didd_load_time_finit();
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/diva.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,633 @@
+/* $Id: diva.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#define CARDTYPE_H_WANT_DATA            1
+#define CARDTYPE_H_WANT_IDI_DATA        0
+#define CARDTYPE_H_WANT_RESOURCE_DATA   0
+#define CARDTYPE_H_WANT_FILE_DATA       0
+
+#include "platform.h"
+#include "debuglib.h"
+#include "diva_pci.h"
+#include "cardtype.h"
+#include "dlist.h"
+#include "pc.h"
+#include "di_defs.h"
+#include "di.h"
+#include "io.h"
+#include "pc_maint.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "diva.h"
+
+#ifdef CONFIG_ISDN_DIVAS_PRIPCI
+  #include "os_pri.h"
+#endif
+#ifdef CONFIG_ISDN_DIVAS_4BRIPCI
+  #include "os_4bri.h"
+#endif
+#ifdef CONFIG_ISDN_DIVAS_BRIPCI
+  #include "os_bri.h"
+#endif
+
+PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+extern IDI_CALL Requests[MAX_ADAPTER];
+extern int create_adapter_proc (diva_os_xdi_adapter_t* a);
+extern void remove_adapter_proc (diva_os_xdi_adapter_t* a);
+
+#define DivaIdiReqFunc(N) \
+static void DivaIdiRequest##N(ENTITY *e) \
+{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }
+
+/*
+**  Create own 32 Adapters
+*/
+DivaIdiReqFunc(0)
+DivaIdiReqFunc(1)
+DivaIdiReqFunc(2)
+DivaIdiReqFunc(3)
+DivaIdiReqFunc(4)
+DivaIdiReqFunc(5)
+DivaIdiReqFunc(6)
+DivaIdiReqFunc(7)
+DivaIdiReqFunc(8)
+DivaIdiReqFunc(9)
+DivaIdiReqFunc(10)
+DivaIdiReqFunc(11)
+DivaIdiReqFunc(12)
+DivaIdiReqFunc(13)
+DivaIdiReqFunc(14)
+DivaIdiReqFunc(15)
+DivaIdiReqFunc(16)
+DivaIdiReqFunc(17)
+DivaIdiReqFunc(18)
+DivaIdiReqFunc(19)
+DivaIdiReqFunc(20)
+DivaIdiReqFunc(21)
+DivaIdiReqFunc(22)
+DivaIdiReqFunc(23)
+DivaIdiReqFunc(24)
+DivaIdiReqFunc(25)
+DivaIdiReqFunc(26)
+DivaIdiReqFunc(27)
+DivaIdiReqFunc(28)
+DivaIdiReqFunc(29)
+DivaIdiReqFunc(30)
+DivaIdiReqFunc(31)
+
+struct pt_regs;
+
+/*
+**  LOCALS
+*/
+diva_entity_queue_t adapter_queue;
+
+typedef struct _diva_get_xlog {
+  word command;
+  byte req;
+  byte rc;
+  byte data [sizeof(struct mi_pc_maint)];
+} diva_get_xlog_t;
+
+typedef struct _diva_supported_cards_info {
+  int CardOrdinal;
+  diva_init_card_proc_t init_card;
+} diva_supported_cards_info_t;
+
+static diva_supported_cards_info_t divas_supported_cards [] = {
+#ifdef CONFIG_ISDN_DIVAS_PRIPCI
+  /*
+    PRI Cards
+  */
+  { CARDTYPE_DIVASRV_P_30M_PCI,	 diva_pri_init_card },
+  /*
+    PRI Rev.2 Cards
+  */
+  { CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card },
+  /*
+    PRI Rev.2 VoIP Cards
+  */
+  { CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card },
+#endif
+#ifdef CONFIG_ISDN_DIVAS_4BRIPCI
+  /*
+    4BRI Rev 1 Cards
+  */
+  { CARDTYPE_DIVASRV_Q_8M_PCI,	 diva_4bri_init_card },
+  { CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card },
+  /*
+    4BRI Rev 2 Cards
+  */
+  { CARDTYPE_DIVASRV_Q_8M_V2_PCI,    diva_4bri_init_card },
+  { CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card },
+  /*
+    4BRI Based BRI Rev 2 Cards
+  */
+  { CARDTYPE_DIVASRV_B_2M_V2_PCI,    diva_4bri_init_card },
+  { CARDTYPE_DIVASRV_B_2F_PCI,       diva_4bri_init_card },
+  { CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card },
+#endif
+#ifdef CONFIG_ISDN_DIVAS_BRIPCI
+  /*
+    BRI
+  */
+  { CARDTYPE_MAESTRA_PCI,		diva_bri_init_card },
+#endif
+
+  /*
+    EOL
+  */
+  { -1, 0 }
+};
+
+static void diva_init_request_array (void);
+static void* divas_create_pci_card (int handle, void* pci_dev_handle);
+
+static diva_os_spin_lock_t adapter_lock;
+
+static int diva_find_free_adapters (int base, int nr) {
+  int i;
+
+  for (i = 0; i < nr; i++) {
+    if (IoAdapters[base+i]) {
+      return (-1);
+    }
+  }
+
+  return (0);
+}
+
+/* --------------------------------------------------------------------------
+    Add card to the card list
+   -------------------------------------------------------------------------- */
+void* diva_driver_add_card (void* pdev, unsigned long CardOrdinal) {
+  diva_os_spin_lock_magic_t old_irql;
+  diva_os_xdi_adapter_t* pdiva, *pa;
+  int i, j, max, nr;
+
+  for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
+    if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
+      if (!(pdiva = divas_create_pci_card (i, pdev))) {
+        return (0);
+      }
+      switch (CardOrdinal) {
+        case CARDTYPE_DIVASRV_Q_8M_PCI:
+        case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:
+        case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
+        case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
+          max = MAX_ADAPTER - 4;
+          nr = 4;
+          break;
+
+        default:
+          max = MAX_ADAPTER;
+          nr  = 1;
+      }
+
+      diva_os_enter_spin_lock (&adapter_lock, &old_irql, "add card");
+
+      for (i = 0; i < max; i++) {
+        if (!diva_find_free_adapters (i, nr)) {
+          pdiva->controller        = i+1;
+          pdiva->xdi_adapter.ANum  = pdiva->controller;
+          IoAdapters[i]            = &pdiva->xdi_adapter;
+          create_adapter_proc (pdiva); /* add adapter to proc file system */
+
+          DBG_LOG(("add %s:%d",
+                  CardProperties[CardOrdinal].Name,
+                  pdiva->controller))
+
+          pa = pdiva;
+          for (j = 1; j < nr; j++) { /* slave adapters, if any */
+            pa = (diva_os_xdi_adapter_t*)diva_q_get_next (&pa->link);
+            if (pa && !pa->interface.cleanup_adapter_proc) {
+              pa->controller       = i+1+j;
+              pa->xdi_adapter.ANum = pa->controller;
+              IoAdapters[i+j]      = &pa->xdi_adapter;
+              DBG_LOG(("add slave adapter (%d)", pa->controller))
+              create_adapter_proc (pa); /* add adapter to proc file system */
+            } else {
+              DBG_ERR(("slave adapter problem"))
+              break;
+            }
+          }
+          
+          diva_os_leave_spin_lock (&adapter_lock, &old_irql, "add card");
+
+          return (pdiva);
+        }
+      }
+
+      diva_os_leave_spin_lock (&adapter_lock, &old_irql, "add card");
+
+      /*
+         Not able to add adapter - remove it and return error
+         */
+      DBG_ERR(("can not alloc request array"))
+      diva_driver_remove_card (pdiva);
+
+      return (0);
+    }
+  }
+
+  return (0);
+}
+
+/* --------------------------------------------------------------------------
+    Called on driver load, MAIN, main, DriverEntry
+   -------------------------------------------------------------------------- */
+int divasa_xdi_driver_entry (void) {
+  diva_os_initialize_spin_lock (&adapter_lock, "adapter");
+  diva_q_init(&adapter_queue);
+  memset (&IoAdapters[0], 0x00, sizeof(IoAdapters));
+  diva_init_request_array ();
+
+  return  (0);
+}
+
+/* --------------------------------------------------------------------------
+    Remove adapter from list
+   -------------------------------------------------------------------------- */
+static diva_os_xdi_adapter_t* get_and_remove_from_queue(void) {
+  diva_os_spin_lock_magic_t old_irql;
+  diva_os_xdi_adapter_t* a;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "driver_unload");
+
+  if((a = (diva_os_xdi_adapter_t*)diva_q_get_head(&adapter_queue)))
+    diva_q_remove (&adapter_queue, &a->link);
+
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "driver_unload");
+  return(a);
+}
+
+/* --------------------------------------------------------------------------
+    Remove card from the card list
+   -------------------------------------------------------------------------- */
+void diva_driver_remove_card (void* pdiva) {
+  diva_os_spin_lock_magic_t old_irql;
+  diva_os_xdi_adapter_t* a[4];
+  diva_os_xdi_adapter_t* pa;
+  int i;
+
+  pa = a[0] = (diva_os_xdi_adapter_t*)pdiva;
+  a[1] = a[2] = a[3] = 0;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "remode adapter");
+
+  for (i = 1; i < 4; i++) {
+    if ((pa = (diva_os_xdi_adapter_t*)diva_q_get_next	(&pa->link)) &&
+        !pa->interface.cleanup_adapter_proc) {
+      a[i] = pa;
+    } else {
+      break;
+    }
+  }
+
+  for (i = 0; ((i < 4) && a[i]); i++) {
+    diva_q_remove (&adapter_queue, &a[i]->link);
+  }
+
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "driver_unload");
+
+  (*(a[0]->interface.cleanup_adapter_proc))(a[0]);
+
+  for (i = 0; i < 4; i++) {
+    if (a[i]) {
+      if (a[i]->controller) {
+        DBG_LOG(("remove adapter (%d)", a[i]->controller))
+        IoAdapters[a[i]->controller - 1] = 0;
+        remove_adapter_proc (a[i]);
+      }
+      diva_os_free (0, a[i]);
+    }
+  }
+}
+
+/* --------------------------------------------------------------------------
+    Create diva PCI adapter and init internal adapter structures
+   -------------------------------------------------------------------------- */
+static void* divas_create_pci_card (int handle, void* pci_dev_handle) {
+  diva_supported_cards_info_t* pI = &divas_supported_cards[handle];
+  diva_os_spin_lock_magic_t old_irql;
+  diva_os_xdi_adapter_t* a;
+
+  DBG_LOG(("found %d-%s",
+          pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))
+
+  if (!(a = (diva_os_xdi_adapter_t*)diva_os_malloc (0, sizeof(*a)))) {
+    DBG_ERR(("A: can't alloc adapter"));
+    return (0);
+  }
+
+  memset (a, 0x00, sizeof(*a));
+
+  a->CardIndex = handle;
+  a->CardOrdinal = pI->CardOrdinal;
+  a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
+  a->xdi_adapter.cardType = a->CardOrdinal;
+  a->resources.pci.bus	= diva_os_get_pci_bus(pci_dev_handle);
+  a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
+  a->resources.pci.hdev = pci_dev_handle;
+
+  /*
+    Add master adapter first, so slave adapters will receive higher
+    numbers as master adapter
+  */
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "found_pci_card");
+  diva_q_add_tail (&adapter_queue, &a->link);
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "found_pci_card");
+
+  if ((*(pI->init_card))(a)) {
+    diva_os_enter_spin_lock (&adapter_lock, &old_irql, "found_pci_card");
+    diva_q_remove (&adapter_queue, &a->link);
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "found_pci_card");
+    diva_os_free (0, a);
+    DBG_ERR(("A: can't get adapter resources"));
+    return (0);
+  }
+
+  return (a);
+}
+
+/* --------------------------------------------------------------------------
+    Called on driver unload FINIT, finit, Unload
+   -------------------------------------------------------------------------- */
+void divasa_xdi_driver_unload (void) {
+  diva_os_xdi_adapter_t* a;
+
+  while ((a = get_and_remove_from_queue())) {
+    if (a->interface.cleanup_adapter_proc) {
+      (*(a->interface.cleanup_adapter_proc))(a);
+    }
+    if (a->controller) {
+      IoAdapters[a->controller - 1] = 0;
+      remove_adapter_proc (a);
+    }
+    diva_os_free (0, a);
+  }
+  diva_os_destroy_spin_lock (&adapter_lock, "adapter");
+}
+
+/*
+**  Receive and process command from user mode utility
+*/
+static int
+cmp_adapter_nr (const void* what, const diva_entity_link_t* p)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t*)p;
+  dword nr = (dword)(unsigned long)what;
+
+  return (nr != a->controller);
+}
+
+void*
+diva_xdi_open_adapter (void* os_handle, const void* src,
+                       int length, divas_xdi_copy_from_user_fn_t cp_fn)
+{
+  diva_xdi_um_cfg_cmd_t	msg;
+  diva_os_xdi_adapter_t* a;
+  diva_os_spin_lock_magic_t old_irql;
+
+  if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
+    DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
+            length, sizeof(diva_xdi_um_cfg_cmd_t)))
+    return (0);
+  }
+  if ((*cp_fn)(os_handle, &msg, src, sizeof(msg)) <= 0) {
+    DBG_ERR(("A: A(?) open, write error"))
+    return (0);
+  }
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "open_adapter");
+  a = (diva_os_xdi_adapter_t*)diva_q_find (&adapter_queue,
+                                           (void*)(unsigned long)msg.adapter, cmp_adapter_nr);
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "open_adapter");
+
+  if (!a) {
+    DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
+  }
+	
+  return (a);
+}
+
+/*
+**  Easy cleanup mailbox status
+*/
+void
+diva_xdi_close_adapter (void* adapter, void* os_handle)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t*)adapter;
+
+  a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
+  if (a->xdi_mbox.data) {
+    diva_os_free (0, a->xdi_mbox.data);
+    a->xdi_mbox.data = 0;
+  }
+}
+
+int
+diva_xdi_write (void* adapter, void* os_handle, const void* src,
+                int length,divas_xdi_copy_from_user_fn_t cp_fn)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t*)adapter;
+  void* data;
+
+  if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
+    DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
+    return (-1);
+  }
+
+  if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
+    DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
+          a->controller, length, sizeof(diva_xdi_um_cfg_cmd_t)))
+    return (-3);
+  }
+
+  if (!(data = diva_os_malloc (0, length))) {
+    DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
+    return (-2);
+  }
+
+  length = (*cp_fn)(os_handle, data, src, length);
+  if (length > 0) {
+    if ((*(a->interface.cmd_proc))(a, (diva_xdi_um_cfg_cmd_t*)data, length)) {
+      length = -3;
+    }
+  } else {
+    DBG_ERR(("A: A(%d) write error (%d)", a->controller, length))
+  }
+
+  diva_os_free (0, data);
+
+  return (length);
+}
+
+/*
+**  Write answers to user mode utility, if any
+*/
+int
+diva_xdi_read (void* adapter, void* os_handle, void* dst,
+               int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t*)adapter;
+  int ret;
+
+  if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
+    DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
+    return (-1);
+  }
+  if (!a->xdi_mbox.data) {
+    a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
+    DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
+    return (-2);
+  }
+
+  if (max_length < a->xdi_mbox.data_length) {
+    DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)", 
+            a->controller, max_length, a->xdi_mbox.data_length))
+    return (-3);
+  }
+
+  ret = (*cp_fn)(os_handle, dst, a->xdi_mbox.data, a->xdi_mbox.data_length);
+  if (ret > 0) {
+    diva_os_free (0, a->xdi_mbox.data);
+    a->xdi_mbox.data = 0;
+    a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
+  }
+
+  return (ret);
+}
+
+
+void
+diva_os_irq_wrapper (int irq, void* context, struct pt_regs* regs)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t*)context;
+  diva_xdi_clear_interrupts_proc_t clear_int_proc;
+
+  if (!a || !a->xdi_adapter.diva_isr_handler) {
+    return;
+  }
+
+  if ((clear_int_proc = a->clear_interrupts_proc)) {
+    (*clear_int_proc)(a);
+    a->clear_interrupts_proc = 0;
+    return;
+  }
+
+  (*(a->xdi_adapter.diva_isr_handler))(&a->xdi_adapter);
+}
+
+static void
+diva_init_request_array (void)
+{
+  Requests[0 ] = DivaIdiRequest0;
+  Requests[1 ] = DivaIdiRequest1;
+  Requests[2 ] = DivaIdiRequest2;
+  Requests[3 ] = DivaIdiRequest3;
+  Requests[4 ] = DivaIdiRequest4;
+  Requests[5 ] = DivaIdiRequest5;
+  Requests[6 ] = DivaIdiRequest6;
+  Requests[7 ] = DivaIdiRequest7;
+  Requests[8 ] = DivaIdiRequest8;
+  Requests[9 ] = DivaIdiRequest9;
+  Requests[10] = DivaIdiRequest10;
+  Requests[11] = DivaIdiRequest11;
+  Requests[12] = DivaIdiRequest12;
+  Requests[13] = DivaIdiRequest13;
+  Requests[14] = DivaIdiRequest14;
+  Requests[15] = DivaIdiRequest15;
+  Requests[16] = DivaIdiRequest16;
+  Requests[17] = DivaIdiRequest17;
+  Requests[18] = DivaIdiRequest18;
+  Requests[19] = DivaIdiRequest19;
+  Requests[20] = DivaIdiRequest20;
+  Requests[21] = DivaIdiRequest21;
+  Requests[22] = DivaIdiRequest22;
+  Requests[23] = DivaIdiRequest23;
+  Requests[24] = DivaIdiRequest24;
+  Requests[25] = DivaIdiRequest25;
+  Requests[26] = DivaIdiRequest26;
+  Requests[27] = DivaIdiRequest27;
+  Requests[28] = DivaIdiRequest28;
+  Requests[29] = DivaIdiRequest29;
+  Requests[30] = DivaIdiRequest30;
+  Requests[31] = DivaIdiRequest31;
+}
+
+void
+diva_xdi_display_adapter_features (int card)
+{
+  dword features;
+  if (!card || ((card-1) > MAX_ADAPTER) || !IoAdapters[card-1]) {
+    return;
+  }
+  card--;
+  features = IoAdapters[card]->Properties.Features;
+
+  DBG_LOG(("FEATURES FOR ADAPTER: %d", card+1))
+  DBG_LOG((" DI_FAX3          :  %s", (features & DI_FAX3)   ? "Y" : "N"))
+  DBG_LOG((" DI_MODEM         :  %s", (features & DI_MODEM)  ? "Y" : "N"))
+  DBG_LOG((" DI_POST          :  %s", (features & DI_POST)   ? "Y" : "N"))
+  DBG_LOG((" DI_V110          :  %s", (features & DI_V110)   ? "Y" : "N"))
+  DBG_LOG((" DI_V120          :  %s", (features & DI_V120)   ? "Y" : "N"))
+  DBG_LOG((" DI_POTS          :  %s", (features & DI_POTS)   ? "Y" : "N"))
+  DBG_LOG((" DI_CODEC         :  %s", (features & DI_CODEC)  ? "Y" : "N"))
+  DBG_LOG((" DI_MANAGE        :  %s", (features & DI_MANAGE) ? "Y" : "N"))
+  DBG_LOG((" DI_V_42          :  %s", (features & DI_V_42)   ? "Y" : "N"))
+  DBG_LOG((" DI_EXTD_FAX      :  %s", (features & DI_EXTD_FAX) ? "Y" : "N"))
+  DBG_LOG((" DI_AT_PARSER     :  %s", (features & DI_AT_PARSER) ? "Y" : "N"))
+  DBG_LOG((" DI_VOICE_OVER_IP :  %s", (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
+}
+
+void diva_add_slave_adapter (diva_os_xdi_adapter_t* a) {
+  diva_os_spin_lock_magic_t old_irql;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "add_slave");
+  diva_q_add_tail (&adapter_queue, &a->link);
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "add_slave");
+}
+
+int diva_card_read_xlog (diva_os_xdi_adapter_t* a) {
+  diva_get_xlog_t *req;
+  byte* data;
+
+  if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
+    return (-1);                                                                                         }
+  if (!(data = diva_os_malloc (0, sizeof(struct mi_pc_maint)))) {
+    return (-1);
+  }
+  memset (data, 0x00, sizeof(struct mi_pc_maint));
+
+  if (!(req = diva_os_malloc (0, sizeof(*req)))) {
+    diva_os_free (0, data);
+    return (-1);
+  }
+  req->command = 0x0400;
+  req->req = LOG;
+  req->rc = 0x00;
+
+  (*(a->xdi_adapter.DIRequest))(&a->xdi_adapter, (ENTITY*)req);
+
+  if (!req->rc || req->req) {
+    diva_os_free (0, data);
+    diva_os_free (0, req);
+    return (-1);
+  }
+
+  memcpy (data, &req->req, sizeof(struct mi_pc_maint));
+
+  diva_os_free (0, req);
+
+  a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
+  a->xdi_mbox.data = data;
+  a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+
+  return (0);
+}
+
+void
+xdiFreeFile (void* handle)
+{
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/diva.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,31 @@
+/* $Id: diva.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#ifndef __DIVA_XDI_OS_PART_H__
+#define __DIVA_XDI_OS_PART_H__
+
+
+int  divasa_xdi_driver_entry  (void);
+void divasa_xdi_driver_unload (void);
+void* diva_driver_add_card (void* pdev, unsigned long CardOrdinal);
+void diva_driver_remove_card (void* pdiva);
+
+typedef int (*divas_xdi_copy_to_user_fn_t)(void* os_handle, void* dst,
+                                           const void* src, int length);
+
+typedef int (*divas_xdi_copy_from_user_fn_t)(void* os_handle, void* dst,
+                                             const void* src, int length);
+
+int diva_xdi_read (void* adapter, void* os_handle, void* dst,
+                   int max_length, divas_xdi_copy_to_user_fn_t cp_fn);
+
+int diva_xdi_write (void* adapter, void* os_handle, const void* src,
+                    int length, divas_xdi_copy_from_user_fn_t cp_fn);
+
+void*	diva_xdi_open_adapter (void* os_handle, const void* src,
+                               int length, divas_xdi_copy_from_user_fn_t cp_fn);
+
+void	diva_xdi_close_adapter (void* adapter, void* os_handle);
+
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/diva_didd.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,168 @@
+/* $Id: diva_didd.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * DIDD Interface module for Eicon active cards.
+ * 
+ * Functions are in dadapter.c 
+ * 
+ * Copyright 2002 by Armin Schindler (mac@melware.de) 
+ * Copyright 2002 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+
+#include "platform.h"
+#include "di_defs.h"
+#include "dadapter.h"
+#include "divasync.h"
+#include "did_vers.h"
+
+static char *main_revision = "$Revision: 1.1.2.2 $";
+
+static char *DRIVERNAME = "Eicon DIVA - DIDD table (http://www.melware.net)";
+static char *DRIVERLNAME = "divadidd";
+char *DRIVERRELEASE = "2.0";
+
+static char *dir_in_proc_net = "isdn";
+static char *main_proc_dir = "eicon";
+
+MODULE_DESCRIPTION(             "DIDD table driver for diva drivers");
+MODULE_AUTHOR(                  "Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE(        "Eicon diva drivers");
+MODULE_LICENSE("GPL");
+
+#define MAX_DESCRIPTORS  32
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+extern int diddfunc_init(void);
+extern void diddfunc_finit(void);
+
+extern void DIVA_DIDD_Read (void *, int);
+
+static struct proc_dir_entry *proc_net_isdn;
+static struct proc_dir_entry *proc_didd;
+struct proc_dir_entry *proc_net_isdn_eicon = NULL;
+
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(proc_net_isdn_eicon);
+
+static char *
+getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else rev = "1.0";
+	return rev;
+}
+
+static int
+proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+  int len = 0;
+  char tmprev[32];
+
+  strcpy(tmprev, main_revision);
+  len += sprintf(page+len, "%s\n", DRIVERNAME);
+  len += sprintf(page+len, "name     : %s\n", DRIVERLNAME);
+  len += sprintf(page+len, "release  : %s\n", DRIVERRELEASE);
+  len += sprintf(page+len, "build    : %s(%s)\n",
+            diva_didd_common_code_build, DIVA_BUILD);
+  len += sprintf(page+len, "revision : %s\n", getrev(tmprev));
+
+  if (off + count >= len)
+    *eof = 1;
+  if (len < off)
+    return 0;
+  *start = page + off;
+  return((count < len-off) ? count : len-off);
+}
+
+static int DIVA_INIT_FUNCTION create_proc(void)
+{
+  struct proc_dir_entry *pe;
+
+  for (pe = proc_net->subdir; pe; pe = pe->next) {
+    if (!memcmp(dir_in_proc_net, pe->name, pe->namelen)) {
+        proc_net_isdn = pe;
+        break;
+    }
+  }
+  if (!proc_net_isdn) {
+    proc_net_isdn = create_proc_entry(dir_in_proc_net, S_IFDIR, proc_net);
+  }
+  proc_net_isdn_eicon = create_proc_entry(main_proc_dir, S_IFDIR, proc_net_isdn);
+
+  if(proc_net_isdn_eicon) {
+    if((proc_didd = create_proc_entry(DRIVERLNAME, S_IFREG | S_IRUGO, proc_net_isdn_eicon))) {
+      proc_didd->read_proc = proc_read;
+    }
+    return(1);
+  }
+  return(0);
+}
+
+static void DIVA_EXIT_FUNCTION remove_proc(void)
+{
+  remove_proc_entry(DRIVERLNAME, proc_net_isdn_eicon);
+  remove_proc_entry(main_proc_dir, proc_net_isdn);
+
+  if ((proc_net_isdn) && (!proc_net_isdn->subdir)){
+    remove_proc_entry(dir_in_proc_net, proc_net);
+  }
+}
+
+static int DIVA_INIT_FUNCTION
+divadidd_init(void)
+{
+  char tmprev[32];
+  int ret = 0;
+
+  MOD_INC_USE_COUNT;
+
+  printk(KERN_INFO "%s\n", DRIVERNAME);
+  printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE);
+  strcpy(tmprev, main_revision);
+  printk("%s  Build:%s(%s)\n", getrev(tmprev),
+        diva_didd_common_code_build, DIVA_BUILD);
+
+  if (!create_proc()) {
+    printk(KERN_ERR "%s: could not create proc entry\n", DRIVERLNAME);
+    ret = -EIO;
+    goto out;
+  }
+
+  if(!diddfunc_init()) {
+    printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME);
+  	remove_proc();
+    ret = -EIO;
+    goto out;
+  }
+
+out:
+  MOD_DEC_USE_COUNT;
+  return (ret);
+}
+
+void DIVA_EXIT_FUNCTION
+divadidd_exit(void)
+{
+  diddfunc_finit();
+  remove_proc();
+  printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divadidd_init);
+module_exit(divadidd_exit);
+
diff -Nru a/drivers/isdn/hardware/eicon/diva_dma.c b/drivers/isdn/hardware/eicon/diva_dma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/diva_dma.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,95 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "diva_dma.h"
+/*
+  Every entry has length of PAGE_SIZE
+  and represents one single physical page
+  */
+struct _diva_dma_map_entry {
+  int   busy;
+  dword phys_bus_addr;  /* 32bit address as seen by the card */
+  void* local_ram_addr; /* local address as seen by the host */
+  void* addr_handle;    /* handle uset to free allocated memory */
+};
+/*
+  Create local mapping structure and init it to default state
+  */
+struct _diva_dma_map_entry* diva_alloc_dma_map (void* os_context, int nentries) {
+  diva_dma_map_entry_t* pmap;
+  if (!(pmap = diva_os_malloc (0, sizeof(*pmap)*(nentries+1))))
+    return (0);
+  memset (pmap, 0x00, sizeof(*pmap)*(nentries+1));
+  return (pmap);
+}
+/*
+  Free local map (context should be freed before) if any
+  */
+void diva_free_dma_mapping (struct _diva_dma_map_entry* pmap) {
+  if (pmap) {
+    diva_os_free (0, pmap);
+  }
+}
+/*
+  Set information saved on the map entry
+  */
+void diva_init_dma_map_entry (struct _diva_dma_map_entry* pmap,
+                              int nr, void* virt, dword phys,
+                              void* addr_handle) {
+  pmap[nr].phys_bus_addr  = phys;
+  pmap[nr].local_ram_addr = virt;
+  pmap[nr].addr_handle    = addr_handle;
+}
+/*
+  Allocate one single entry in the map
+  */
+int diva_alloc_dma_map_entry (struct _diva_dma_map_entry* pmap) {
+  int i;
+  for (i = 0; (pmap && pmap[i].local_ram_addr); i++) {
+    if (!pmap[i].busy) {
+      pmap[i].busy = 1;
+      return (i);
+    }
+  }
+  return (-1);
+}
+/*
+  Free one single entry in the map
+  */
+void diva_free_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr) {
+  pmap[nr].busy = 0;
+}
+/*
+  Get information saved on the map entry
+  */
+void diva_get_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr,
+                             void** pvirt, dword* pphys) {
+  *pphys = pmap[nr].phys_bus_addr;
+  *pvirt = pmap[nr].local_ram_addr;
+}
+void* diva_get_entry_handle (struct _diva_dma_map_entry* pmap, int nr) {
+  return (pmap[nr].addr_handle);
+}
diff -Nru a/drivers/isdn/hardware/eicon/diva_dma.h b/drivers/isdn/hardware/eicon/diva_dma.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/diva_dma.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,48 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_DMA_MAPPING_IFC_H__
+#define __DIVA_DMA_MAPPING_IFC_H__
+typedef struct _diva_dma_map_entry  diva_dma_map_entry_t;
+struct _diva_dma_map_entry* diva_alloc_dma_map (void* os_context, int nentries);
+void diva_init_dma_map_entry (struct _diva_dma_map_entry* pmap,
+                              int nr, void* virt, dword phys,
+                              void* addr_handle);
+int diva_alloc_dma_map_entry (struct _diva_dma_map_entry* pmap);
+void diva_free_dma_map_entry (struct _diva_dma_map_entry* pmap, int entry);
+void diva_get_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr,
+                             void** pvirt, dword* pphys);
+void diva_free_dma_mapping (struct _diva_dma_map_entry* pmap);
+/*
+  Functionality to be implemented by OS wrapper
+  and running in process context
+  */
+void diva_init_dma_map (void* hdev,
+                        struct _diva_dma_map_entry** ppmap,
+                        int nentries);
+void diva_free_dma_map (void* hdev,
+                        struct _diva_dma_map_entry* pmap);
+void* diva_get_entry_handle (struct _diva_dma_map_entry* pmap, int nr);
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/diva_pci.h b/drivers/isdn/hardware/eicon/diva_pci.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/diva_pci.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,19 @@
+/* $Id: diva_pci.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#ifndef __DIVA_PCI_INTERFACE_H__
+#define __DIVA_PCI_INTERFACE_H__
+
+void*  divasa_remap_pci_bar (unsigned long  bar,
+                             unsigned long area_length);
+void  divasa_unmap_pci_bar (void* bar);
+unsigned long divasa_get_pci_irq (unsigned char bus,
+                                  unsigned char func,
+                                  void* pci_dev_handle);
+unsigned long divasa_get_pci_bar (unsigned char bus,
+                                  unsigned char func,
+                                  int bar,
+                                  void* pci_dev_handle);
+byte diva_os_get_pci_bus (void* pci_dev_handle);
+byte diva_os_get_pci_func (void* pci_dev_handle);
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/divacapi.h b/drivers/isdn/hardware/eicon/divacapi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/divacapi.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1360 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+
+/*#define DEBUG */
+
+
+
+
+  
+  
+
+
+
+
+
+#define IMPLEMENT_DTMF 1
+#define IMPLEMENT_LINE_INTERCONNECT2 1
+#define IMPLEMENT_ECHO_CANCELLER 1
+#define IMPLEMENT_RTP 1
+#define IMPLEMENT_T38 1
+#define IMPLEMENT_FAX_SUB_SEP_PWD 1
+#define IMPLEMENT_V18 1
+#define IMPLEMENT_DTMF_TONE 1
+#define IMPLEMENT_PIAFS 1
+#define IMPLEMENT_FAX_PAPER_FORMATS 1
+#define IMPLEMENT_VOWN 1
+#define IMPLEMENT_CAPIDTMF 1
+#define IMPLEMENT_FAX_NONSTANDARD 1
+#define VSWITCH_SUPPORT 1
+
+
+#define IMPLEMENT_LINE_INTERCONNECT 0
+#define IMPLEMENT_MARKED_OK_AFTER_FC 1
+
+#include "capidtmf.h"
+
+/*------------------------------------------------------------------*/
+/* Common API internal definitions                                  */
+/*------------------------------------------------------------------*/
+
+#define MAX_APPL 240
+#define MAX_NCCI           127
+
+#define MSG_IN_QUEUE_SIZE  ((4096 + 3) & 0xfffc)  /* must be multiple of 4 */
+
+
+#define MSG_IN_OVERHEAD    sizeof(APPL   *)
+
+#define MAX_NL_CHANNEL     255
+#define MAX_DATA_B3        8
+#define MAX_DATA_ACK       MAX_DATA_B3
+#define MAX_MULTI_IE       6
+#define MAX_MSG_SIZE       256
+#define MAX_MSG_PARMS      10
+#define MAX_CPN_MASK_SIZE  16
+#define MAX_MSN_CONFIG     10
+#define EXT_CONTROLLER     0x80
+#define CODEC              0x01
+#define CODEC_PERMANENT    0x02
+#define ADV_VOICE          0x03
+#define MAX_CIP_TYPES      5  /* kind of CIP types for group optimization */
+#define C_IND_MASK_DWORDS  ((MAX_APPL+32) >> 5)
+
+
+#define FAX_CONNECT_INFO_BUFFER_SIZE  256
+#define NCPI_BUFFER_SIZE              256
+
+#define MAX_CHANNELS_PER_PLCI         8
+#define MAX_INTERNAL_COMMAND_LEVELS   4
+#define INTERNAL_REQ_BUFFER_SIZE      272
+
+#define INTERNAL_IND_BUFFER_SIZE      768
+
+#define DTMF_PARAMETER_BUFFER_SIZE    12
+#define ADV_VOICE_COEF_BUFFER_SIZE    50
+
+#define LI_PLCI_B_QUEUE_ENTRIES       256
+
+
+
+typedef struct _APPL APPL;
+typedef struct _PLCI PLCI;
+typedef struct _NCCI NCCI;
+typedef struct _DIVA_CAPI_ADAPTER DIVA_CAPI_ADAPTER;
+typedef struct _DATA_B3_DESC DATA_B3_DESC;
+typedef struct _DATA_ACK_DESC DATA_ACK_DESC;
+typedef struct manufacturer_profile_s MANUFACTURER_PROFILE;
+typedef struct fax_ncpi_s FAX_NCPI;
+typedef struct api_parse_s API_PARSE;
+typedef struct api_save_s API_SAVE;
+typedef struct msn_config_s MSN_CONFIG;
+typedef struct msn_config_max_s MSN_CONFIG_MAX;
+typedef struct msn_ld_s MSN_LD;
+
+struct manufacturer_profile_s {
+  dword private_options;
+  dword rtp_primary_payloads;
+  dword rtp_additional_payloads;
+};
+
+struct fax_ncpi_s {
+  word options;
+  word format;
+};
+
+struct msn_config_s {
+  byte msn[MAX_CPN_MASK_SIZE];
+};
+
+struct msn_config_max_s {
+  MSN_CONFIG    msn_conf[MAX_MSN_CONFIG];
+};
+
+struct msn_ld_s {
+  dword low;
+  dword high;
+};
+
+struct api_parse_s {
+  word          length;
+  byte   *    info;
+};
+
+struct api_save_s {
+  API_PARSE     parms[MAX_MSG_PARMS+1];
+  byte          info[MAX_MSG_SIZE];
+};
+
+struct _DATA_B3_DESC {
+  word          Handle;
+  word          Number;
+  word          Flags;
+  word          Length;
+  void   *    P;
+};
+
+struct _DATA_ACK_DESC {
+  word          Handle;
+  word          Number;
+};
+
+typedef void (* t_std_internal_command)(dword Id, PLCI   *plci, byte Rc);
+
+/************************************************************************/
+/* Don't forget to adapt dos.asm after changing the _APPL structure!!!! */
+struct _APPL {
+  word          Id;
+  word          NullCREnable;
+  word          CDEnable;
+  dword         S_Handle;
+
+
+
+
+
+
+  LIST_ENTRY    s_function;
+  dword         s_context;
+  word          s_count;
+  APPL *        s_next;
+  byte *        xbuffer_used;
+  void **       xbuffer_internal;
+  void **       xbuffer_ptr;
+
+
+
+
+
+
+  byte   *    queue;
+  word          queue_size;
+  word          queue_free;
+  word          queue_read;
+  word          queue_write;
+  word          queue_signal;
+  byte          msg_lost;
+  byte          appl_flags;
+  word          Number;
+
+  word          MaxBuffer;
+  byte          MaxNCCI;
+  byte          MaxNCCIData;
+  word          MaxDataLength;
+  word          NCCIDataFlowCtrlTimer;
+  byte   *    ReceiveBuffer;
+  word   *    DataNCCI;
+  word   *    DataFlags;
+};
+
+
+struct _PLCI {
+  ENTITY        Sig;
+  ENTITY        NL;
+  word          RNum;
+  word          RFlags;
+  BUFFERS       RData[2];
+  BUFFERS       XData[1];
+  BUFFERS       NData[2];
+
+  DIVA_CAPI_ADAPTER   *adapter;
+  APPL      *appl;
+  PLCI      *relatedPTYPLCI;
+  byte          Id;
+  byte          State;
+  byte          sig_req;
+  byte          nl_req;
+  byte          SuppState;
+  byte          channels;
+  byte          tel;
+  byte          B1_resource;
+  byte          B2_prot;
+  byte          B3_prot;
+
+  word          command;
+  word          m_command;
+  word          internal_command;
+  word          number;
+  word          req_in_start;
+  word          req_in;
+  word          req_out;
+  word          msg_in_write_pos;
+  word          msg_in_read_pos;
+  word          msg_in_wrap_pos;
+
+  void   *    data_sent_ptr;
+  byte          data_sent;
+  byte          send_disc;
+  byte          sig_global_req;
+  byte          sig_remove_id;
+  byte          nl_global_req;
+  byte          nl_remove_id;
+  byte          b_channel;
+  byte          adv_nl;
+  byte          manufacturer;
+  byte          call_dir;
+  byte          hook_state;
+  byte          spoofed_msg;
+  byte          ptyState;
+  byte          cr_enquiry;
+  word          hangup_flow_ctrl_timer;
+
+  word          ncci_ring_list;
+  byte          inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI];
+  t_std_internal_command internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS];
+  dword         c_ind_mask_table[C_IND_MASK_DWORDS];
+  dword         group_optimization_mask_table[C_IND_MASK_DWORDS];
+  byte          RBuffer[200];
+  dword         msg_in_queue[MSG_IN_QUEUE_SIZE/sizeof(dword)];
+  API_SAVE      saved_msg;
+  API_SAVE      B_protocol;
+  byte          fax_connect_info_length;
+  byte          fax_connect_info_buffer[FAX_CONNECT_INFO_BUFFER_SIZE];
+  byte          fax_edata_ack_length;
+  word          nsf_control_bits;
+  byte          ncpi_state;
+  byte          ncpi_buffer[NCPI_BUFFER_SIZE];
+
+  byte          internal_req_buffer[INTERNAL_REQ_BUFFER_SIZE];
+  byte          internal_ind_buffer[INTERNAL_IND_BUFFER_SIZE + 3];
+  dword         requested_options_conn;
+  dword         requested_options;
+  word          B1_facilities;
+  API_SAVE   *adjust_b_parms_msg;
+  word          adjust_b_facilities;
+  word          adjust_b_command;
+  word          adjust_b_ncci;
+  word          adjust_b_mode;
+  word          adjust_b_state;
+  byte          adjust_b_restore;
+
+  byte          dtmf_rec_active;
+  word          dtmf_rec_pulse_ms;
+  word          dtmf_rec_pause_ms;
+  byte          dtmf_send_requests;
+  word          dtmf_send_pulse_ms;
+  word          dtmf_send_pause_ms;
+  word          dtmf_cmd;
+  word          dtmf_msg_number_queue[8];
+  byte          dtmf_parameter_length;
+  byte          dtmf_parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE];
+
+
+  t_capidtmf_state capidtmf_state;
+
+
+  byte          li_bchannel_id;    /* BRI: 1..2, PRI: 1..32 */
+  byte          li_channel_bits;
+  byte          li_notify_update;
+  word          li_cmd;
+  word          li_write_command;
+  word          li_write_channel;
+  word          li_plci_b_write_pos;
+  word          li_plci_b_read_pos;
+  word          li_plci_b_req_pos;
+  dword         li_plci_b_queue[LI_PLCI_B_QUEUE_ENTRIES];
+
+
+  word          ec_cmd;
+  word          ec_idi_options;
+  word          ec_tail_length;
+
+
+  byte          tone_last_indication_code;
+
+  byte          vswitchstate;
+  byte          vsprot;
+  byte          vsprotdialect;
+  byte          notifiedcall; /* Flag if it is a spoofed call */
+
+  int           rx_dma_descriptor;
+  dword         rx_dma_magic;
+};
+
+
+struct _NCCI {
+  byte          data_out;
+  byte          data_pending;
+  byte          data_ack_out;
+  byte          data_ack_pending;
+  DATA_B3_DESC  DBuffer[MAX_DATA_B3];
+  DATA_ACK_DESC DataAck[MAX_DATA_ACK];
+};
+
+
+struct _DIVA_CAPI_ADAPTER {
+  IDI_CALL      request;
+  byte          Id;
+  byte          max_plci;
+  byte          max_listen;
+  byte          listen_active;
+  PLCI      *plci;
+  byte          ch_ncci[MAX_NL_CHANNEL+1];
+  byte          ncci_ch[MAX_NCCI+1];
+  byte          ncci_plci[MAX_NCCI+1];
+  byte          ncci_state[MAX_NCCI+1];
+  byte          ncci_next[MAX_NCCI+1];
+  NCCI          ncci[MAX_NCCI+1];
+
+  byte          ch_flow_control[MAX_NL_CHANNEL+1];  /* Used by XON protocol */
+  byte          ch_flow_control_pending;
+  byte          ch_flow_plci[MAX_NL_CHANNEL+1];
+  int           last_flow_control_ch;
+
+  dword         Info_Mask[MAX_APPL];
+  dword         CIP_Mask[MAX_APPL];
+
+  dword         Notification_Mask[MAX_APPL];
+  PLCI      *codec_listen[MAX_APPL];
+  dword         requested_options_table[MAX_APPL];
+  API_PROFILE   profile;
+  MANUFACTURER_PROFILE man_profile;
+  dword         manufacturer_features;
+
+  byte          AdvCodecFLAG;
+  PLCI      *AdvCodecPLCI;
+  PLCI      *AdvSignalPLCI;
+  APPL      *AdvSignalAppl;
+  byte          TelOAD[23];
+  byte          TelOSA[23];
+  byte          scom_appl_disable;
+  PLCI      *automatic_lawPLCI;
+  byte          automatic_law;
+  byte          u_law;
+
+  byte          adv_voice_coef_length;
+  byte          adv_voice_coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE];
+
+  byte          li_pri;
+  byte          li_channels;
+  word          li_base;
+
+  byte adapter_disabled;
+  byte group_optimization_enabled; /* use application groups if enabled */
+  dword sdram_bar;
+  byte flag_dynamic_l1_down; /* for hunt groups:down layer 1 if no appl present*/
+  byte FlowControlIdTable[256];
+  byte FlowControlSkipTable[256];
+  void* os_card; /* pointer to associated OS dependent adapter structure */
+};
+
+
+/*------------------------------------------------------------------*/
+/* Application flags                                                */
+/*------------------------------------------------------------------*/
+
+#define APPL_FLAG_OLD_LI_SPEC           0x01
+#define APPL_FLAG_PRIV_EC_SPEC          0x02
+
+
+/*------------------------------------------------------------------*/
+/* API parameter definitions                                        */
+/*------------------------------------------------------------------*/
+
+#define X75_TTX         1       /* x.75 for ttx                     */
+#define TRF             2       /* transparent with hdlc framing    */
+#define TRF_IN          3       /* transparent with hdlc fr. inc.   */
+#define SDLC            4       /* sdlc, sna layer-2                */
+#define X75_BTX         5       /* x.75 for btx                     */
+#define LAPD            6       /* lapd (Q.921)                     */
+#define X25_L2          7       /* x.25 layer-2                     */
+#define V120_L2         8       /* V.120 layer-2 protocol           */
+#define V42_IN          9       /* V.42 layer-2 protocol, incomming */
+#define V42            10       /* V.42 layer-2 protocol            */
+#define MDM_ATP        11       /* AT Parser built in the L2        */
+#define X75_V42BIS     12       /* ISO7776 (X.75 SLP) modified to support V.42 bis compression */
+#define RTPL2_IN       13       /* RTP layer-2 protocol, incomming  */
+#define RTPL2          14       /* RTP layer-2 protocol             */
+#define V120_V42BIS    15       /* V.120 layer-2 protocol supporting V.42 bis compression */
+
+#define T70NL           1
+#define X25PLP          2
+#define T70NLX          3
+#define TRANSPARENT_NL  4
+#define ISO8208         5
+#define T30             6
+
+
+/*------------------------------------------------------------------*/
+/* FAX interface to IDI                                             */
+/*------------------------------------------------------------------*/
+
+#define CAPI_MAX_HEAD_LINE_SPACE        89
+#define CAPI_MAX_DATE_TIME_LENGTH       18
+
+#define T30_MAX_STATION_ID_LENGTH       20
+#define T30_MAX_SUBADDRESS_LENGTH       20
+#define T30_MAX_PASSWORD_LENGTH         20
+
+typedef struct t30_info_s T30_INFO;
+struct t30_info_s {
+  byte          code;
+  byte          rate_div_2400;
+  byte          resolution;
+  byte          data_format;
+  byte          pages_low;
+  byte          pages_high;
+  byte          operating_mode;
+  byte          control_bits_low;
+  byte          control_bits_high;
+  byte          feature_bits_low;
+  byte          feature_bits_high;
+  byte          recording_properties;
+  byte          universal_6;
+  byte          universal_7;
+  byte          station_id_len;
+  byte          head_line_len;
+  byte          station_id[T30_MAX_STATION_ID_LENGTH];
+/* byte          head_line[];      */
+/* byte          sub_sep_length;   */
+/* byte          sub_sep_field[];  */
+/* byte          pwd_length;       */
+/* byte          pwd_field[];      */
+/* byte          nsf_info_length;   */
+/* byte          nsf_info_field[];  */
+};
+
+
+#define T30_RESOLUTION_R8_0385          0x00
+#define T30_RESOLUTION_R8_0770_OR_200   0x01
+#define T30_RESOLUTION_R8_1540          0x02
+#define T30_RESOLUTION_R16_1540_OR_400  0x04
+#define T30_RESOLUTION_R4_0385_OR_100   0x08
+#define T30_RESOLUTION_300_300          0x10
+#define T30_RESOLUTION_INCH_BASED       0x40
+#define T30_RESOLUTION_METRIC_BASED     0x80
+
+#define T30_RECORDING_WIDTH_ISO_A4      0
+#define T30_RECORDING_WIDTH_ISO_B4      1
+#define T30_RECORDING_WIDTH_ISO_A3      2
+#define T30_RECORDING_WIDTH_COUNT       3
+
+#define T30_RECORDING_LENGTH_ISO_A4     0
+#define T30_RECORDING_LENGTH_ISO_B4     1
+#define T30_RECORDING_LENGTH_UNLIMITED  2
+#define T30_RECORDING_LENGTH_COUNT      3
+
+#define T30_MIN_SCANLINE_TIME_00_00_00  0
+#define T30_MIN_SCANLINE_TIME_05_05_05  1
+#define T30_MIN_SCANLINE_TIME_10_05_05  2
+#define T30_MIN_SCANLINE_TIME_10_10_10  3
+#define T30_MIN_SCANLINE_TIME_20_10_10  4
+#define T30_MIN_SCANLINE_TIME_20_20_20  5
+#define T30_MIN_SCANLINE_TIME_40_20_20  6
+#define T30_MIN_SCANLINE_TIME_40_40_40  7
+#define T30_MIN_SCANLINE_TIME_RES_8     8
+#define T30_MIN_SCANLINE_TIME_RES_9     9
+#define T30_MIN_SCANLINE_TIME_RES_10    10
+#define T30_MIN_SCANLINE_TIME_10_10_05  11
+#define T30_MIN_SCANLINE_TIME_20_10_05  12
+#define T30_MIN_SCANLINE_TIME_20_20_10  13
+#define T30_MIN_SCANLINE_TIME_40_20_10  14
+#define T30_MIN_SCANLINE_TIME_40_40_20  15
+#define T30_MIN_SCANLINE_TIME_COUNT     16
+
+#define T30_DATA_FORMAT_SFF             0
+#define T30_DATA_FORMAT_ASCII           1
+#define T30_DATA_FORMAT_NATIVE          2
+#define T30_DATA_FORMAT_COUNT           3
+
+
+#define T30_OPERATING_MODE_STANDARD     0
+#define T30_OPERATING_MODE_CLASS2       1
+#define T30_OPERATING_MODE_CLASS1       2
+#define T30_OPERATING_MODE_CAPI         3
+#define T30_OPERATING_MODE_CAPI_NEG     4
+#define T30_OPERATING_MODE_COUNT        5
+
+        /* EDATA transmit messages */
+#define EDATA_T30_DIS         0x01
+#define EDATA_T30_FTT         0x02
+#define EDATA_T30_MCF         0x03
+#define EDATA_T30_PARAMETERS  0x04
+
+        /* EDATA receive messages */
+#define EDATA_T30_DCS         0x81
+#define EDATA_T30_TRAIN_OK    0x82
+#define EDATA_T30_EOP         0x83
+#define EDATA_T30_MPS         0x84
+#define EDATA_T30_EOM         0x85
+#define EDATA_T30_DTC         0x86
+#define EDATA_T30_PAGE_END    0x87   /* Indicates end of page data. Reserved, but not implemented ! */
+#define EDATA_T30_EOP_CAPI    0x88
+
+
+#define T30_SUCCESS                        0
+#define T30_ERR_NO_DIS_RECEIVED            1
+#define T30_ERR_TIMEOUT_NO_RESPONSE        2
+#define T30_ERR_RETRY_NO_RESPONSE          3
+#define T30_ERR_TOO_MANY_REPEATS           4
+#define T30_ERR_UNEXPECTED_MESSAGE         5
+#define T30_ERR_UNEXPECTED_DCN             6
+#define T30_ERR_DTC_UNSUPPORTED            7
+#define T30_ERR_ALL_RATES_FAILED           8
+#define T30_ERR_TOO_MANY_TRAINS            9
+#define T30_ERR_RECEIVE_CORRUPTED          10
+#define T30_ERR_UNEXPECTED_DISC            11
+#define T30_ERR_APPLICATION_DISC           12
+#define T30_ERR_INCOMPATIBLE_DIS           13
+#define T30_ERR_INCOMPATIBLE_DCS           14
+#define T30_ERR_TIMEOUT_NO_COMMAND         15
+#define T30_ERR_RETRY_NO_COMMAND           16
+#define T30_ERR_TIMEOUT_COMMAND_TOO_LONG   17
+#define T30_ERR_TIMEOUT_RESPONSE_TOO_LONG  18
+#define T30_ERR_NOT_IDENTIFIED             19
+#define T30_ERR_SUPERVISORY_TIMEOUT        20
+#define T30_ERR_TOO_LONG_SCAN_LINE         21
+/* #define T30_ERR_RETRY_NO_PAGE_AFTER_MPS    22 */
+#define T30_ERR_RETRY_NO_PAGE_RECEIVED     23
+#define T30_ERR_RETRY_NO_DCS_AFTER_FTT     24
+#define T30_ERR_RETRY_NO_DCS_AFTER_EOM     25
+#define T30_ERR_RETRY_NO_DCS_AFTER_MPS     26
+#define T30_ERR_RETRY_NO_DCN_AFTER_MCF     27
+#define T30_ERR_RETRY_NO_DCN_AFTER_RTN     28
+#define T30_ERR_RETRY_NO_CFR               29
+#define T30_ERR_RETRY_NO_MCF_AFTER_EOP     30
+#define T30_ERR_RETRY_NO_MCF_AFTER_EOM     31
+#define T30_ERR_RETRY_NO_MCF_AFTER_MPS     32
+#define T30_ERR_SUB_SEP_UNSUPPORTED        33
+#define T30_ERR_PWD_UNSUPPORTED            34
+#define T30_ERR_SUB_SEP_PWD_UNSUPPORTED    35
+#define T30_ERR_INVALID_COMMAND_FRAME      36
+#define T30_ERR_UNSUPPORTED_PAGE_CODING    37
+#define T30_ERR_INVALID_PAGE_CODING        38
+#define T30_ERR_INCOMPATIBLE_PAGE_CONFIG   39
+#define T30_ERR_TIMEOUT_FROM_APPLICATION   40
+#define T30_ERR_V34FAX_NO_REACTION_ON_MARK 41
+#define T30_ERR_V34FAX_TRAINING_TIMEOUT    42
+#define T30_ERR_V34FAX_UNEXPECTED_V21      43
+#define T30_ERR_V34FAX_PRIMARY_CTS_ON      44
+#define T30_ERR_V34FAX_TURNAROUND_POLLING  45
+#define T30_ERR_V34FAX_V8_INCOMPATIBILITY  46
+
+
+#define T30_CONTROL_BIT_DISABLE_FINE       0x0001
+#define T30_CONTROL_BIT_ENABLE_ECM         0x0002
+#define T30_CONTROL_BIT_ECM_64_BYTES       0x0004
+#define T30_CONTROL_BIT_ENABLE_2D_CODING   0x0008
+#define T30_CONTROL_BIT_ENABLE_T6_CODING   0x0010
+#define T30_CONTROL_BIT_ENABLE_UNCOMPR     0x0020
+#define T30_CONTROL_BIT_ACCEPT_POLLING     0x0040
+#define T30_CONTROL_BIT_REQUEST_POLLING    0x0080
+#define T30_CONTROL_BIT_MORE_DOCUMENTS     0x0100
+#define T30_CONTROL_BIT_ACCEPT_SUBADDRESS  0x0200
+#define T30_CONTROL_BIT_ACCEPT_SEL_POLLING 0x0400
+#define T30_CONTROL_BIT_ACCEPT_PASSWORD    0x0800
+#define T30_CONTROL_BIT_ENABLE_V34FAX      0x1000
+#define T30_CONTROL_BIT_EARLY_CONNECT      0x2000
+
+#define T30_CONTROL_BIT_ALL_FEATURES  (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |   T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR |   T30_CONTROL_BIT_ENABLE_V34FAX)
+
+#define T30_FEATURE_BIT_FINE               0x0001
+#define T30_FEATURE_BIT_ECM                0x0002
+#define T30_FEATURE_BIT_ECM_64_BYTES       0x0004
+#define T30_FEATURE_BIT_2D_CODING          0x0008
+#define T30_FEATURE_BIT_T6_CODING          0x0010
+#define T30_FEATURE_BIT_UNCOMPR_ENABLED    0x0020
+#define T30_FEATURE_BIT_POLLING            0x0040
+#define T30_FEATURE_BIT_MORE_DOCUMENTS     0x0100
+#define T30_FEATURE_BIT_V34FAX             0x1000
+
+
+#define T30_NSF_CONTROL_BIT_ENABLE_NSF     0x0001
+#define T30_NSF_CONTROL_BIT_RAW_INFO       0x0002
+#define T30_NSF_CONTROL_BIT_NEGOTIATE_IND  0x0004
+#define T30_NSF_CONTROL_BIT_NEGOTIATE_RESP 0x0008
+
+#define T30_NSF_ELEMENT_NSF_FIF            0x00
+#define T30_NSF_ELEMENT_NSC_FIF            0x01
+#define T30_NSF_ELEMENT_NSS_FIF            0x02
+#define T30_NSF_ELEMENT_COMPANY_NAME       0x03
+
+
+/*------------------------------------------------------------------*/
+/* Analog modem definitions                                         */
+/*------------------------------------------------------------------*/
+
+typedef struct async_s ASYNC_FORMAT;
+struct async_s {
+  unsigned pe:    1;
+  unsigned parity:2;
+  unsigned spare: 2;
+  unsigned stp:   1;
+  unsigned ch_len:2;   // 3th octett in CAI
+};
+
+
+/*------------------------------------------------------------------*/
+/* PLCI/NCCI states                                                 */
+/*------------------------------------------------------------------*/
+
+#define IDLE                    0
+#define OUTG_CON_PENDING        1
+#define INC_CON_PENDING         2
+#define INC_CON_ALERT           3
+#define INC_CON_ACCEPT          4
+#define INC_ACT_PENDING         5
+#define LISTENING               6
+#define CONNECTED               7
+#define OUTG_DIS_PENDING        8
+#define INC_DIS_PENDING         9
+#define LOCAL_CONNECT           10
+#define INC_RES_PENDING         11
+#define OUTG_RES_PENDING        12
+#define SUSPENDING              13
+#define ADVANCED_VOICE_SIG      14
+#define ADVANCED_VOICE_NOSIG    15
+#define RESUMING                16
+#define INC_CON_CONNECTED_ALERT 17
+#define OUTG_REJ_PENDING        18
+
+
+/*------------------------------------------------------------------*/
+/* auxilliary states for supplementary services                     */
+/*------------------------------------------------------------------*/
+
+#define IDLE                0
+#define HOLD_REQUEST        1
+#define HOLD_INDICATE       2
+#define CALL_HELD           3
+#define RETRIEVE_REQUEST    4
+#define RETRIEVE_INDICATION 5
+
+/*------------------------------------------------------------------*/
+/* Capi IE + Msg types                                              */
+/*------------------------------------------------------------------*/
+#define ESC_CAUSE        0x800|CAU          /* Escape cause element */
+#define ESC_MSGTYPE      0x800|MSGTYPEIE    /* Escape message type  */
+#define ESC_CHI          0x800|CHI          /* Escape channel id    */
+#define ESC_LAW          0x800|BC           /* Escape law info      */
+#define ESC_CR           0x800|CRIE         /* Escape CallReference */
+#define ESC_PROFILE      0x800|PROFILEIE    /* Escape profile       */
+#define ESC_SSEXT        0x800|SSEXTIE      /* Escape Supplem. Serv.*/
+#define ESC_VSWITCH      0x800|VSWITCHIE    /* Escape VSwitch       */
+#define CST              0x14               /* Call State i.e.      */
+#define PI               0x1E               /* Progress Indicator   */
+#define NI               0x27               /* Notification Ind     */
+#define CONN_NR          0x4C               /* Connected Number     */
+#define CONG_RNR         0xBF               /* Congestion RNR       */
+#define CONG_RR          0xB0               /* Congestion RR        */
+#define RESERVED         0xFF               /* Res. for future use  */
+#define ON_BOARD_CODEC   0x02               /* external controller  */
+#define HANDSET          0x04               /* Codec+Handset(Pro11) */
+#define HOOK_SUPPORT     0x01               /* activate Hook signal */
+#define SCR              0x7a               /* unscreened number    */
+
+#define HOOK_OFF_REQ     0x9001             /* internal conn req    */
+#define HOOK_ON_REQ      0x9002             /* internal disc req    */
+#define SUSPEND_REQ      0x9003             /* internal susp req    */
+#define RESUME_REQ       0x9004             /* internal resume req  */
+#define USELAW_REQ       0x9005             /* internal law    req  */
+#define LISTEN_SIG_ASSIGN_PEND  0x9006
+#define PERM_LIST_REQ    0x900a             /* permanent conn DCE   */
+#define C_HOLD_REQ       0x9011
+#define C_RETRIEVE_REQ   0x9012
+#define C_NCR_FAC_REQ    0x9013
+#define PERM_COD_ASSIGN  0x9014
+#define PERM_COD_CALL    0x9015
+#define PERM_COD_HOOK    0x9016
+#define PERM_COD_CONN_PEND 0x9017           /* wait for connect_con */
+#define PTY_REQ_PEND     0x9018
+#define CD_REQ_PEND      0x9019
+#define CF_START_PEND    0x901a
+#define CF_STOP_PEND     0x901b
+#define ECT_REQ_PEND     0x901c
+#define GETSERV_REQ_PEND 0x901d
+#define BLOCK_PLCI       0x901e
+#define INTERR_NUMBERS_REQ_PEND         0x901f
+#define INTERR_DIVERSION_REQ_PEND       0x9020
+#define MWI_ACTIVATE_REQ_PEND           0x9021
+#define MWI_DEACTIVATE_REQ_PEND         0x9022
+#define SSEXT_REQ_COMMAND               0x9023
+#define SSEXT_NC_REQ_COMMAND            0x9024
+#define START_L1_SIG_ASSIGN_PEND        0x9025
+#define REM_L1_SIG_ASSIGN_PEND          0x9026
+#define CONF_BEGIN_REQ_PEND             0x9027
+#define CONF_ADD_REQ_PEND               0x9028
+#define CONF_SPLIT_REQ_PEND             0x9029
+#define CONF_DROP_REQ_PEND              0x902a
+#define CONF_ISOLATE_REQ_PEND           0x902b
+#define CONF_REATTACH_REQ_PEND          0x902c
+#define VSWITCH_REQ_PEND                0x902d
+#define GET_MWI_STATE                   0x902e
+#define CCBS_REQUEST_REQ_PEND           0x902f
+#define CCBS_DEACTIVATE_REQ_PEND        0x9030
+#define CCBS_INTERROGATE_REQ_PEND       0x9031
+
+#define NO_INTERNAL_COMMAND             0
+#define DTMF_COMMAND_1                  1
+#define DTMF_COMMAND_2                  2
+#define DTMF_COMMAND_3                  3
+#define MIXER_COMMAND_1                 4
+#define MIXER_COMMAND_2                 5
+#define MIXER_COMMAND_3                 6
+#define ADV_VOICE_COMMAND_CONNECT_1     7
+#define ADV_VOICE_COMMAND_CONNECT_2     8
+#define ADV_VOICE_COMMAND_CONNECT_3     9
+#define ADV_VOICE_COMMAND_DISCONNECT_1  10
+#define ADV_VOICE_COMMAND_DISCONNECT_2  11
+#define ADV_VOICE_COMMAND_DISCONNECT_3  12
+#define ADJUST_B_RESTORE_1              13
+#define ADJUST_B_RESTORE_2              14
+#define RESET_B3_COMMAND_1              15
+#define SELECT_B_COMMAND_1              16
+#define FAX_CONNECT_INFO_COMMAND_1      17
+#define FAX_CONNECT_INFO_COMMAND_2      18
+#define FAX_ADJUST_B23_COMMAND_1        19
+#define FAX_ADJUST_B23_COMMAND_2        20
+#define EC_COMMAND_1                    21
+#define EC_COMMAND_2                    22
+#define EC_COMMAND_3                    23
+#define RTP_CONNECT_B3_REQ_COMMAND_1    24
+#define RTP_CONNECT_B3_REQ_COMMAND_2    25
+#define RTP_CONNECT_B3_REQ_COMMAND_3    26
+#define RTP_CONNECT_B3_RES_COMMAND_1    27
+#define RTP_CONNECT_B3_RES_COMMAND_2    28
+#define RTP_CONNECT_B3_RES_COMMAND_3    29
+#define HOLD_SAVE_COMMAND_1             30
+#define RETRIEVE_RESTORE_COMMAND_1      31
+#define FAX_DISCONNECT_COMMAND_1        32
+#define FAX_DISCONNECT_COMMAND_2        33
+#define FAX_DISCONNECT_COMMAND_3        34
+#define FAX_EDATA_ACK_COMMAND_1         35
+#define FAX_EDATA_ACK_COMMAND_2         36
+#define FAX_CONNECT_ACK_COMMAND_1       37
+#define FAX_CONNECT_ACK_COMMAND_2       38
+#define STD_INTERNAL_COMMAND_COUNT      39
+
+#define UID              0x2d               /* User Id for Mgmt      */
+
+#define CALL_DIR_OUT             0x01       /* call direction of initial call */
+#define CALL_DIR_IN              0x02
+#define CALL_DIR_ORIGINATE       0x04       /* DTE/DCE direction according to */
+#define CALL_DIR_ANSWER          0x08       /*   state of B-Channel Operation */
+#define CALL_DIR_FORCE_OUTG_NL   0x10       /* for RESET_B3 reconnect, after DISC_B3... */
+
+#define AWAITING_MANUF_CON 0x80             /* command spoofing flags */
+#define SPOOFING_REQUIRED  0xff
+#define AWAITING_SELECT_B  0xef
+
+/*------------------------------------------------------------------*/
+/* B_CTRL / DSP_CTRL                                                */
+/*------------------------------------------------------------------*/
+
+#define DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS     0x01
+#define DSP_CTRL_SET_BCHANNEL_PASSIVATION_BRI   0x02
+#define DSP_CTRL_SET_DTMF_PARAMETERS            0x03
+
+#define MANUFACTURER_FEATURE_SLAVE_CODEC          0x00000001L
+#define MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS   0x00000002L
+#define MANUFACTURER_FEATURE_HARDDTMF             0x00000004L
+#define MANUFACTURER_FEATURE_SOFTDTMF_SEND        0x00000008L
+#define MANUFACTURER_FEATURE_DTMF_PARAMETERS      0x00000010L
+#define MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE     0x00000020L
+#define MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD      0x00000040L
+#define MANUFACTURER_FEATURE_V18                  0x00000080L
+#define MANUFACTURER_FEATURE_MIXER_CH_CH          0x00000100L
+#define MANUFACTURER_FEATURE_MIXER_CH_PC          0x00000200L
+#define MANUFACTURER_FEATURE_MIXER_PC_CH          0x00000400L
+#define MANUFACTURER_FEATURE_MIXER_PC_PC          0x00000800L
+#define MANUFACTURER_FEATURE_ECHO_CANCELLER       0x00001000L
+#define MANUFACTURER_FEATURE_RTP                  0x00002000L
+#define MANUFACTURER_FEATURE_T38                  0x00004000L
+#define MANUFACTURER_FEATURE_TRANSP_DELIVERY_CONF 0x00008000L
+#define MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL  0x00010000L
+#define MANUFACTURER_FEATURE_OOB_CHANNEL          0x00020000L
+#define MANUFACTURER_FEATURE_IN_BAND_CHANNEL      0x00040000L
+#define MANUFACTURER_FEATURE_IN_BAND_FEATURE      0x00080000L
+#define MANUFACTURER_FEATURE_PIAFS                0x00100000L
+#define MANUFACTURER_FEATURE_DTMF_TONE            0x00200000L
+#define MANUFACTURER_FEATURE_FAX_PAPER_FORMATS    0x00400000L
+#define MANUFACTURER_FEATURE_OK_FC_LABEL          0x00800000L
+#define MANUFACTURER_FEATURE_VOWN                 0x01000000L
+#define MANUFACTURER_FEATURE_XCONNECT             0x02000000L
+#define MANUFACTURER_FEATURE_DMACONNECT           0x04000000L
+#define MANUFACTURER_FEATURE_AUDIO_TAP            0x08000000L
+#define MANUFACTURER_FEATURE_FAX_NONSTANDARD      0x10000000L
+
+/*------------------------------------------------------------------*/
+/* DTMF interface to IDI                                            */
+/*------------------------------------------------------------------*/
+
+
+#define DTMF_DIGIT_TONE_LOW_GROUP_697_HZ        0x00
+#define DTMF_DIGIT_TONE_LOW_GROUP_770_HZ        0x01
+#define DTMF_DIGIT_TONE_LOW_GROUP_852_HZ        0x02
+#define DTMF_DIGIT_TONE_LOW_GROUP_941_HZ        0x03
+#define DTMF_DIGIT_TONE_LOW_GROUP_MASK          0x03
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ      0x00
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ      0x04
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ      0x08
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ      0x0c
+#define DTMF_DIGIT_TONE_HIGH_GROUP_MASK         0x0c
+#define DTMF_DIGIT_TONE_CODE_0                  0x07
+#define DTMF_DIGIT_TONE_CODE_1                  0x00
+#define DTMF_DIGIT_TONE_CODE_2                  0x04
+#define DTMF_DIGIT_TONE_CODE_3                  0x08
+#define DTMF_DIGIT_TONE_CODE_4                  0x01
+#define DTMF_DIGIT_TONE_CODE_5                  0x05
+#define DTMF_DIGIT_TONE_CODE_6                  0x09
+#define DTMF_DIGIT_TONE_CODE_7                  0x02
+#define DTMF_DIGIT_TONE_CODE_8                  0x06
+#define DTMF_DIGIT_TONE_CODE_9                  0x0a
+#define DTMF_DIGIT_TONE_CODE_STAR               0x03
+#define DTMF_DIGIT_TONE_CODE_HASHMARK           0x0b
+#define DTMF_DIGIT_TONE_CODE_A                  0x0c
+#define DTMF_DIGIT_TONE_CODE_B                  0x0d
+#define DTMF_DIGIT_TONE_CODE_C                  0x0e
+#define DTMF_DIGIT_TONE_CODE_D                  0x0f
+
+#define DTMF_UDATA_REQUEST_SEND_DIGITS            16
+#define DTMF_UDATA_REQUEST_ENABLE_RECEIVER        17
+#define DTMF_UDATA_REQUEST_DISABLE_RECEIVER       18
+#define DTMF_UDATA_INDICATION_DIGITS_SENT         16
+#define DTMF_UDATA_INDICATION_DIGITS_RECEIVED     17
+#define DTMF_UDATA_INDICATION_MODEM_CALLING_TONE  18
+#define DTMF_UDATA_INDICATION_FAX_CALLING_TONE    19
+#define DTMF_UDATA_INDICATION_ANSWER_TONE         20
+
+#define UDATA_REQUEST_MIXER_TAP_DATA        27
+#define UDATA_INDICATION_MIXER_TAP_DATA     27
+
+#define DTMF_LISTEN_ACTIVE_FLAG        0x01
+#define DTMF_SEND_DIGIT_FLAG           0x01
+
+
+/*------------------------------------------------------------------*/
+/* Mixer interface to IDI                                           */
+/*------------------------------------------------------------------*/
+
+
+#define LI2_FLAG_PCCONNECT_A_B 0x40000000
+#define LI2_FLAG_PCCONNECT_B_A 0x80000000
+
+#define MIXER_BCHANNELS_BRI    2
+#define MIXER_IC_CHANNELS_BRI  MIXER_BCHANNELS_BRI
+#define MIXER_IC_CHANNEL_BASE  MIXER_BCHANNELS_BRI
+#define MIXER_CHANNELS_BRI     (MIXER_BCHANNELS_BRI + MIXER_IC_CHANNELS_BRI)
+#define MIXER_CHANNELS_PRI     32
+
+typedef struct li_config_s LI_CONFIG;
+
+struct xconnect_card_address_s {
+  dword low;
+  dword high;
+};
+
+struct xconnect_transfer_address_s {
+  struct xconnect_card_address_s card_address;
+  dword offset;
+};
+
+struct li_config_s {
+  DIVA_CAPI_ADAPTER   *adapter;
+  PLCI   *plci;
+  struct xconnect_transfer_address_s send_b;
+  struct xconnect_transfer_address_s send_pc;
+  byte   *flag_table;  /* dword aligned and sized */
+  byte   *coef_table;  /* dword aligned and sized */
+  byte channel;
+  byte curchnl;
+  byte chflags;
+};
+
+extern LI_CONFIG   *li_config_table;
+extern word li_total_channels;
+
+#define LI_CHANNEL_INVOLVED        0x01
+#define LI_CHANNEL_ACTIVE          0x02
+#define LI_CHANNEL_TX_DATA         0x04
+#define LI_CHANNEL_RX_DATA         0x08
+#define LI_CHANNEL_CONFERENCE      0x10
+#define LI_CHANNEL_ADDRESSES_SET   0x80
+
+#define LI_CHFLAG_MONITOR          0x01
+#define LI_CHFLAG_MIX              0x02
+#define LI_CHFLAG_LOOP             0x04
+
+#define LI_FLAG_INTERCONNECT       0x01
+#define LI_FLAG_MONITOR            0x02
+#define LI_FLAG_MIX                0x04
+#define LI_FLAG_PCCONNECT          0x08
+#define LI_FLAG_CONFERENCE         0x10
+#define LI_FLAG_ANNOUNCEMENT       0x20
+
+#define LI_COEF_CH_CH              0x01
+#define LI_COEF_CH_PC              0x02
+#define LI_COEF_PC_CH              0x04
+#define LI_COEF_PC_PC              0x08
+#define LI_COEF_CH_CH_SET          0x10
+#define LI_COEF_CH_PC_SET          0x20
+#define LI_COEF_PC_CH_SET          0x40
+#define LI_COEF_PC_PC_SET          0x80
+
+#define LI_REQ_SILENT_UPDATE       0xffff
+
+#define LI_PLCI_B_LAST_FLAG        ((dword) 0x80000000L)
+#define LI_PLCI_B_DISC_FLAG        ((dword) 0x40000000L)
+#define LI_PLCI_B_SKIP_FLAG        ((dword) 0x20000000L)
+#define LI_PLCI_B_FLAG_MASK        ((dword) 0xe0000000L)
+
+#define UDATA_REQUEST_SET_MIXER_COEFS_BRI       24
+#define UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC  25
+#define UDATA_REQUEST_SET_MIXER_COEFS_PRI_ASYN  26
+#define UDATA_INDICATION_MIXER_COEFS_SET        24
+
+#define MIXER_FEATURE_ENABLE_TX_DATA        0x0001
+#define MIXER_FEATURE_ENABLE_RX_DATA        0x0002
+
+#define MIXER_COEF_LINE_CHANNEL_MASK        0x1f
+#define MIXER_COEF_LINE_FROM_PC_FLAG        0x20
+#define MIXER_COEF_LINE_TO_PC_FLAG          0x40
+#define MIXER_COEF_LINE_ROW_FLAG            0x80
+
+#define UDATA_REQUEST_XCONNECT_FROM         28
+#define UDATA_INDICATION_XCONNECT_FROM      28
+#define UDATA_REQUEST_XCONNECT_TO           29
+#define UDATA_INDICATION_XCONNECT_TO        29
+
+#define XCONNECT_CHANNEL_PORT_B             0x0000
+#define XCONNECT_CHANNEL_PORT_PC            0x8000
+#define XCONNECT_CHANNEL_PORT_MASK          0x8000
+#define XCONNECT_CHANNEL_NUMBER_MASK        0x7fff
+#define XCONNECT_CHANNEL_PORT_COUNT         2
+
+#define XCONNECT_SUCCESS           0x0000
+#define XCONNECT_ERROR             0x0001
+
+
+/*------------------------------------------------------------------*/
+/* Echo canceller interface to IDI                                  */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_ECHO_CANCELLER         0
+
+#define PRIV_SELECTOR_ECHO_CANCELLER   255
+
+#define EC_ENABLE_OPERATION            1
+#define EC_DISABLE_OPERATION           2
+#define EC_FREEZE_COEFFICIENTS         3
+#define EC_RESUME_COEFFICIENT_UPDATE   4
+#define EC_RESET_COEFFICIENTS          5
+
+#define EC_DISABLE_NON_LINEAR_PROCESSING     0x0001
+#define EC_DO_NOT_REQUIRE_REVERSALS          0x0002
+#define EC_DETECT_DISABLE_TONE               0x0004
+
+#define EC_SUCCESS                           0
+#define EC_UNSUPPORTED_OPERATION             1
+
+#define EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ   1
+#define EC_BYPASS_DUE_TO_REVERSED_2100HZ     2
+#define EC_BYPASS_RELEASED                   3
+
+#define DSP_CTRL_SET_LEC_PARAMETERS          0x05
+
+#define LEC_ENABLE_ECHO_CANCELLER            0x0001
+#define LEC_ENABLE_2100HZ_DETECTOR           0x0002
+#define LEC_REQUIRE_2100HZ_REVERSALS         0x0004
+#define LEC_MANUAL_DISABLE                   0x0008
+#define LEC_ENABLE_NONLINEAR_PROCESSING      0x0010
+#define LEC_FREEZE_COEFFICIENTS              0x0020
+#define LEC_RESET_COEFFICIENTS               0x8000
+
+#define LEC_MAX_SUPPORTED_TAIL_LENGTH        32
+
+#define LEC_UDATA_INDICATION_DISABLE_DETECT  9
+
+#define LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ  0x00
+#define LEC_DISABLE_TYPE_REVERSED_2100HZ     0x01
+#define LEC_DISABLE_RELEASED                 0x02
+
+
+/*------------------------------------------------------------------*/
+/* RTP interface to IDI                                             */
+/*------------------------------------------------------------------*/
+
+
+#define B1_RTP                  31
+#define B2_RTP                  31
+#define B3_RTP                  31
+
+#define PRIVATE_RTP                    1
+
+#define RTP_PRIM_PAYLOAD_PCMU_8000     0
+#define RTP_PRIM_PAYLOAD_1016_8000     1
+#define RTP_PRIM_PAYLOAD_G726_32_8000  2
+#define RTP_PRIM_PAYLOAD_GSM_8000      3
+#define RTP_PRIM_PAYLOAD_G723_8000     4
+#define RTP_PRIM_PAYLOAD_DVI4_8000     5
+#define RTP_PRIM_PAYLOAD_DVI4_16000    6
+#define RTP_PRIM_PAYLOAD_LPC_8000      7
+#define RTP_PRIM_PAYLOAD_PCMA_8000     8
+#define RTP_PRIM_PAYLOAD_G722_16000    9
+#define RTP_PRIM_PAYLOAD_QCELP_8000    12
+#define RTP_PRIM_PAYLOAD_G728_8000     14
+#define RTP_PRIM_PAYLOAD_G729_8000     18
+#define RTP_PRIM_PAYLOAD_GSM_HR_8000   30
+#define RTP_PRIM_PAYLOAD_GSM_EFR_8000  31
+
+#define RTP_ADD_PAYLOAD_BASE           32
+#define RTP_ADD_PAYLOAD_RED            32
+#define RTP_ADD_PAYLOAD_CN_8000        33
+#define RTP_ADD_PAYLOAD_DTMF           34
+
+#define RTP_SUCCESS                         0
+#define RTP_ERR_SSRC_OR_PAYLOAD_CHANGE      1
+
+#define UDATA_REQUEST_RTP_RECONFIGURE       64
+#define UDATA_INDICATION_RTP_CHANGE         65
+#define BUDATA_REQUEST_QUERY_RTCP_REPORT    1
+#define BUDATA_INDICATION_RTCP_REPORT       1
+
+#define RTP_CONNECT_OPTION_DISC_ON_SSRC_CHANGE    0x00000001L
+#define RTP_CONNECT_OPTION_DISC_ON_PT_CHANGE      0x00000002L
+#define RTP_CONNECT_OPTION_DISC_ON_UNKNOWN_PT     0x00000004L
+#define RTP_CONNECT_OPTION_NO_SILENCE_TRANSMIT    0x00010000L
+
+#define RTP_PAYLOAD_OPTION_VOICE_ACTIVITY_DETECT  0x0001
+#define RTP_PAYLOAD_OPTION_DISABLE_POST_FILTER    0x0002
+#define RTP_PAYLOAD_OPTION_G723_LOW_CODING_RATE   0x0100
+
+#define RTP_PACKET_FILTER_IGNORE_UNKNOWN_SSRC     0x00000001L
+
+#define RTP_CHANGE_FLAG_SSRC_CHANGE               0x00000001L
+#define RTP_CHANGE_FLAG_PAYLOAD_TYPE_CHANGE       0x00000002L
+#define RTP_CHANGE_FLAG_UNKNOWN_PAYLOAD_TYPE      0x00000004L
+
+
+/*------------------------------------------------------------------*/
+/* T.38 interface to IDI                                            */
+/*------------------------------------------------------------------*/
+
+
+#define B1_T38                  30
+#define B2_T38                  30
+#define B3_T38                  30
+
+#define PRIVATE_T38                    2
+
+
+/*------------------------------------------------------------------*/
+/* PIAFS interface to IDI                                            */
+/*------------------------------------------------------------------*/
+
+
+#define B1_PIAFS                29
+#define B2_PIAFS                29
+
+#define PRIVATE_PIAFS           29 
+
+/*
+  B2 configuration for PIAFS:
++---------------------+------+-----------------------------------------+
+| PIAFS Protocol      | byte | Bit 1 - Protocol Speed                  |
+| Speed configuration |      |         0 - 32K                         |
+|                     |      |         1 - 64K (default)               |
+|                     |      | Bit 2 - Variable Protocol Speed         |
+|                     |      |         0 - Speed is fix                |
+|                     |      |         1 - Speed is variable (default) |
++---------------------+------+-----------------------------------------+
+| Direction           | word | Enable compression/decompression for    |
+|                     |      | 0: All direction                        |
+|                     |      | 1: disable outgoing data                |
+|                     |      | 2: disable incomming data               |
+|                     |      | 3: disable both direction (default)     |
++---------------------+------+-----------------------------------------+
+| Number of code      | word | Parameter P1 of V.42bis in accordance   |
+| words               |      | with V.42bis                            |
++---------------------+------+-----------------------------------------+
+| Maximum String      | word | Parameter P2 of V.42bis in accordance   |
+| Length              |      | with V.42bis                            |
++---------------------+------+-----------------------------------------+
+| control (UDATA)     | byte | enable PIAFS control communication      |
+| abilities           |      |                                         |
++---------------------+------+-----------------------------------------+
+*/
+#define PIAFS_UDATA_ABILITIES  0x80
+
+/*------------------------------------------------------------------*/
+/* FAX SUB/SEP/PWD extension                                        */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_FAX_SUB_SEP_PWD        3
+
+
+
+/*------------------------------------------------------------------*/
+/* V.18 extension                                                   */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_V18                    4
+
+
+
+/*------------------------------------------------------------------*/
+/* DTMF TONE extension                                              */
+/*------------------------------------------------------------------*/
+
+
+#define DTMF_GET_SUPPORTED_DETECT_CODES  0xf8
+#define DTMF_GET_SUPPORTED_SEND_CODES    0xf9
+#define DTMF_LISTEN_TONE_START           0xfa
+#define DTMF_LISTEN_TONE_STOP            0xfb
+#define DTMF_SEND_TONE                   0xfc
+#define DTMF_LISTEN_MF_START             0xfd
+#define DTMF_LISTEN_MF_STOP              0xfe
+#define DTMF_SEND_MF                     0xff
+
+#define DTMF_MF_DIGIT_TONE_CODE_1               0x10
+#define DTMF_MF_DIGIT_TONE_CODE_2               0x11
+#define DTMF_MF_DIGIT_TONE_CODE_3               0x12
+#define DTMF_MF_DIGIT_TONE_CODE_4               0x13
+#define DTMF_MF_DIGIT_TONE_CODE_5               0x14
+#define DTMF_MF_DIGIT_TONE_CODE_6               0x15
+#define DTMF_MF_DIGIT_TONE_CODE_7               0x16
+#define DTMF_MF_DIGIT_TONE_CODE_8               0x17
+#define DTMF_MF_DIGIT_TONE_CODE_9               0x18
+#define DTMF_MF_DIGIT_TONE_CODE_0               0x19
+#define DTMF_MF_DIGIT_TONE_CODE_K1              0x1a
+#define DTMF_MF_DIGIT_TONE_CODE_K2              0x1b
+#define DTMF_MF_DIGIT_TONE_CODE_KP              0x1c
+#define DTMF_MF_DIGIT_TONE_CODE_S1              0x1d
+#define DTMF_MF_DIGIT_TONE_CODE_ST              0x1e
+
+#define DTMF_DIGIT_CODE_COUNT                   16
+#define DTMF_MF_DIGIT_CODE_BASE                 DSP_DTMF_DIGIT_CODE_COUNT
+#define DTMF_MF_DIGIT_CODE_COUNT                15
+#define DTMF_TOTAL_DIGIT_CODE_COUNT             (DSP_MF_DIGIT_CODE_BASE + DSP_MF_DIGIT_CODE_COUNT)
+
+#define DTMF_TONE_DIGIT_BASE                    0x80
+
+#define DTMF_SIGNAL_NO_TONE                     (DTMF_TONE_DIGIT_BASE + 0)
+#define DTMF_SIGNAL_UNIDENTIFIED_TONE           (DTMF_TONE_DIGIT_BASE + 1)
+
+#define DTMF_SIGNAL_DIAL_TONE                   (DTMF_TONE_DIGIT_BASE + 2)
+#define DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE     (DTMF_TONE_DIGIT_BASE + 3)
+#define DTMF_SIGNAL_SPECIAL_DIAL_TONE           (DTMF_TONE_DIGIT_BASE + 4)   /* stutter dial tone */
+#define DTMF_SIGNAL_SECOND_DIAL_TONE            (DTMF_TONE_DIGIT_BASE + 5)
+#define DTMF_SIGNAL_RINGING_TONE                (DTMF_TONE_DIGIT_BASE + 6)
+#define DTMF_SIGNAL_SPECIAL_RINGING_TONE        (DTMF_TONE_DIGIT_BASE + 7)
+#define DTMF_SIGNAL_BUSY_TONE                   (DTMF_TONE_DIGIT_BASE + 8)
+#define DTMF_SIGNAL_CONGESTION_TONE             (DTMF_TONE_DIGIT_BASE + 9)   /* reorder tone */
+#define DTMF_SIGNAL_SPECIAL_INFORMATION_TONE    (DTMF_TONE_DIGIT_BASE + 10)
+#define DTMF_SIGNAL_COMFORT_TONE                (DTMF_TONE_DIGIT_BASE + 11)
+#define DTMF_SIGNAL_HOLD_TONE                   (DTMF_TONE_DIGIT_BASE + 12)
+#define DTMF_SIGNAL_RECORD_TONE                 (DTMF_TONE_DIGIT_BASE + 13)
+#define DTMF_SIGNAL_CALLER_WAITING_TONE         (DTMF_TONE_DIGIT_BASE + 14)
+#define DTMF_SIGNAL_CALL_WAITING_TONE           (DTMF_TONE_DIGIT_BASE + 15)
+#define DTMF_SIGNAL_PAY_TONE                    (DTMF_TONE_DIGIT_BASE + 16)
+#define DTMF_SIGNAL_POSITIVE_INDICATION_TONE    (DTMF_TONE_DIGIT_BASE + 17)
+#define DTMF_SIGNAL_NEGATIVE_INDICATION_TONE    (DTMF_TONE_DIGIT_BASE + 18)
+#define DTMF_SIGNAL_WARNING_TONE                (DTMF_TONE_DIGIT_BASE + 19)
+#define DTMF_SIGNAL_INTRUSION_TONE              (DTMF_TONE_DIGIT_BASE + 20)
+#define DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE   (DTMF_TONE_DIGIT_BASE + 21)
+#define DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE   (DTMF_TONE_DIGIT_BASE + 22)
+#define DTMF_SIGNAL_CPE_ALERTING_SIGNAL         (DTMF_TONE_DIGIT_BASE + 23)
+#define DTMF_SIGNAL_OFF_HOOK_WARNING_TONE       (DTMF_TONE_DIGIT_BASE + 24)
+
+#define DTMF_SIGNAL_INTERCEPT_TONE              (DTMF_TONE_DIGIT_BASE + 63)
+
+#define DTMF_SIGNAL_MODEM_CALLING_TONE          (DTMF_TONE_DIGIT_BASE + 64)
+#define DTMF_SIGNAL_FAX_CALLING_TONE            (DTMF_TONE_DIGIT_BASE + 65)
+#define DTMF_SIGNAL_ANSWER_TONE                 (DTMF_TONE_DIGIT_BASE + 66)
+#define DTMF_SIGNAL_REVERSED_ANSWER_TONE        (DTMF_TONE_DIGIT_BASE + 67)
+#define DTMF_SIGNAL_ANSAM_TONE                  (DTMF_TONE_DIGIT_BASE + 68)
+#define DTMF_SIGNAL_REVERSED_ANSAM_TONE         (DTMF_TONE_DIGIT_BASE + 69)
+#define DTMF_SIGNAL_BELL103_ANSWER_TONE         (DTMF_TONE_DIGIT_BASE + 70)
+#define DTMF_SIGNAL_FAX_FLAGS                   (DTMF_TONE_DIGIT_BASE + 71)
+#define DTMF_SIGNAL_G2_FAX_GROUP_ID             (DTMF_TONE_DIGIT_BASE + 72)
+#define DTMF_SIGNAL_HUMAN_SPEECH                (DTMF_TONE_DIGIT_BASE + 73)
+#define DTMF_SIGNAL_ANSWERING_MACHINE_390       (DTMF_TONE_DIGIT_BASE + 74)
+
+#define DTMF_MF_LISTEN_ACTIVE_FLAG     0x02
+#define DTMF_SEND_MF_FLAG              0x02
+#define DTMF_TONE_LISTEN_ACTIVE_FLAG   0x04
+#define DTMF_SEND_TONE_FLAG            0x04
+
+#define PRIVATE_DTMF_TONE              5
+
+
+/*------------------------------------------------------------------*/
+/* FAX paper format extension                                       */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_FAX_PAPER_FORMATS      6
+
+
+
+/*------------------------------------------------------------------*/
+/* V.OWN extension                                                  */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_VOWN                   7
+
+
+
+/*------------------------------------------------------------------*/
+/* FAX non-standard facilities extension                            */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_FAX_NONSTANDARD        8
+
+
+
+/*------------------------------------------------------------------*/
+/* Advanced voice                                                   */
+/*------------------------------------------------------------------*/
+
+#define ADV_VOICE_WRITE_ACTIVATION    0
+#define ADV_VOICE_WRITE_DEACTIVATION  1
+#define ADV_VOICE_WRITE_UPDATE        2
+
+#define ADV_VOICE_OLD_COEF_COUNT    6
+#define ADV_VOICE_NEW_COEF_BASE     (ADV_VOICE_OLD_COEF_COUNT * sizeof(word))
+
+/*------------------------------------------------------------------*/
+/* B1 resource switching                                            */
+/*------------------------------------------------------------------*/
+
+#define B1_FACILITY_LOCAL  0x01
+#define B1_FACILITY_MIXER  0x02
+#define B1_FACILITY_DTMFX  0x04
+#define B1_FACILITY_DTMFR  0x08
+#define B1_FACILITY_VOICE  0x10
+#define B1_FACILITY_EC     0x20
+
+#define ADJUST_B_MODE_SAVE          0x0001
+#define ADJUST_B_MODE_REMOVE_L23    0x0002
+#define ADJUST_B_MODE_SWITCH_L1     0x0004
+#define ADJUST_B_MODE_NO_RESOURCE   0x0008
+#define ADJUST_B_MODE_ASSIGN_L23    0x0010
+#define ADJUST_B_MODE_USER_CONNECT  0x0020
+#define ADJUST_B_MODE_CONNECT       0x0040
+#define ADJUST_B_MODE_RESTORE       0x0080
+
+#define ADJUST_B_START                     0
+#define ADJUST_B_SAVE_MIXER_1              1
+#define ADJUST_B_SAVE_DTMF_1               2
+#define ADJUST_B_REMOVE_L23_1              3
+#define ADJUST_B_REMOVE_L23_2              4
+#define ADJUST_B_SAVE_EC_1                 5
+#define ADJUST_B_SAVE_DTMF_PARAMETER_1     6
+#define ADJUST_B_SAVE_VOICE_1              7
+#define ADJUST_B_SWITCH_L1_1               8
+#define ADJUST_B_SWITCH_L1_2               9
+#define ADJUST_B_RESTORE_VOICE_1           10
+#define ADJUST_B_RESTORE_VOICE_2           11
+#define ADJUST_B_RESTORE_DTMF_PARAMETER_1  12
+#define ADJUST_B_RESTORE_DTMF_PARAMETER_2  13
+#define ADJUST_B_RESTORE_EC_1              14
+#define ADJUST_B_RESTORE_EC_2              15
+#define ADJUST_B_ASSIGN_L23_1              16
+#define ADJUST_B_ASSIGN_L23_2              17
+#define ADJUST_B_CONNECT_1                 18
+#define ADJUST_B_CONNECT_2                 19
+#define ADJUST_B_CONNECT_3                 20
+#define ADJUST_B_CONNECT_4                 21
+#define ADJUST_B_RESTORE_DTMF_1            22
+#define ADJUST_B_RESTORE_DTMF_2            23
+#define ADJUST_B_RESTORE_MIXER_1           24
+#define ADJUST_B_RESTORE_MIXER_2           25
+#define ADJUST_B_RESTORE_MIXER_3           26
+#define ADJUST_B_RESTORE_MIXER_4           27
+#define ADJUST_B_RESTORE_MIXER_5           28
+#define ADJUST_B_RESTORE_MIXER_6           29
+#define ADJUST_B_RESTORE_MIXER_7           30
+#define ADJUST_B_END                       31
+
+/*------------------------------------------------------------------*/
+/* XON Protocol def's                                               */
+/*------------------------------------------------------------------*/
+#define N_CH_XOFF               0x01
+#define N_XON_SENT              0x02
+#define N_XON_REQ               0x04
+#define N_XON_CONNECT_IND       0x08
+#define N_RX_FLOW_CONTROL_MASK  0x3f
+#define N_OK_FC_PENDING         0x80
+#define N_TX_FLOW_CONTROL_MASK  0xc0
+
+/*------------------------------------------------------------------*/
+/* NCPI state                                                       */
+/*------------------------------------------------------------------*/
+#define NCPI_VALID_CONNECT_B3_IND  0x01
+#define NCPI_VALID_CONNECT_B3_ACT  0x02
+#define NCPI_VALID_DISC_B3_IND     0x04
+#define NCPI_CONNECT_B3_ACT_SENT   0x08
+#define NCPI_NEGOTIATE_B3_SENT     0x10
+#define NCPI_MDM_CTS_ON_RECEIVED   0x40
+#define NCPI_MDM_DCD_ON_RECEIVED   0x80
+
+/*------------------------------------------------------------------*/
diff -Nru a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/divamnt.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,497 @@
+/* $Id: divamnt.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * Maint module
+ *
+ * Copyright 2000,2001 by Armin Schindler (mac@melware.de)
+ * Copyright 2000,2001 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "di_defs.h"
+#include "debug_if.h"
+
+EXPORT_NO_SYMBOLS;
+
+static char *main_revision = "$Revision: 1.1.2.2 $";
+
+static int major = 241;
+
+MODULE_DESCRIPTION(             "Maint driver for Eicon DIVA Server cards");
+MODULE_AUTHOR(                  "Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE(        "DIVA card driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "Major number for /dev/DivasMAINT");
+
+int buffer_length = 128;
+MODULE_PARM(buffer_length, "i");
+unsigned long diva_dbg_mem=0;
+MODULE_PARM(diva_dbg_mem, "l");
+
+static char *DRIVERNAME = "Eicon DIVA - MAINT module (http://www.melware.net)";
+static char *DRIVERLNAME = "diva_mnt";
+char *DRIVERRELEASE = "2.0";
+
+static devfs_handle_t devfs_handle;
+
+static wait_queue_head_t msgwaitq;
+static atomic_t opened; 
+static struct timeval start_time;
+
+extern int mntfunc_init(int *, void **, unsigned long);
+extern void mntfunc_finit(void);
+extern int maint_read_write(void * buf);
+
+/*
+ *  helper functions
+ */
+static char *
+getrev(const char *revision)
+{
+  char *rev;
+  char *p;
+
+  if ((p = strchr(revision, ':'))) {
+    rev = p + 2;
+    p = strchr(rev, '$');
+    *--p = 0;
+  } else rev = "1.0";
+
+  return rev;
+} 
+
+/*
+ * memory alloc
+ */
+void* diva_os_malloc (unsigned long flags, unsigned long size) {
+  return (vmalloc (size));
+}
+void diva_os_free (unsigned long flags, void* ptr) {
+  if (ptr) {
+    vfree (ptr);
+  }
+}
+void *diva_os_malloc_tbuffer(unsigned long flags, unsigned long size) {
+		return(kmalloc(size, GFP_KERNEL));
+}
+void diva_os_free_tbuffer(unsigned long flags, void* ptr) {
+  if (ptr) {
+    kfree (ptr);
+  }
+}
+
+/*
+ * sleep msec
+ */
+void diva_os_sleep (dword mSec)
+{
+	unsigned long timeout = HZ * mSec / 1000 + 1;
+			 
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(timeout);
+} 
+
+/*
+ * kernel/user space copy functions
+ */
+int diva_os_copy_to_user(void* os_handle, void* dst, const void* src, int length)
+{
+	return (copy_to_user(dst, src, length));
+}
+int diva_os_copy_from_user(void* os_handle, void* dst, const void* src, int length)
+{
+	return(copy_from_user(dst, src, length));
+} 
+
+/*
+ * get time
+ */
+void diva_os_get_time (dword* sec, dword* usec) {
+  struct timeval tv;
+
+  do_gettimeofday (&tv);
+
+  if (tv.tv_sec > start_time.tv_sec) {
+    if (start_time.tv_usec > tv.tv_usec) {
+      tv.tv_sec--;
+      tv.tv_usec += 1000000;
+    }
+    *sec  = (dword)(tv.tv_sec  - start_time.tv_sec);
+    *usec = (dword)(tv.tv_usec - start_time.tv_usec);
+  } else if (tv.tv_sec == start_time.tv_sec) {
+    *sec  = 0;
+    if (start_time.tv_usec < tv.tv_usec) {
+      *usec = (dword)(tv.tv_usec - start_time.tv_usec);
+    } else {
+      *usec = 0;
+    }
+  } else {
+    *sec  = (dword)tv.tv_sec;
+    *usec = (dword)tv.tv_usec;
+  }
+}
+
+/*
+ * /proc entries
+ */
+
+extern struct proc_dir_entry *proc_net_isdn_eicon;
+static struct proc_dir_entry *maint_proc_entry = NULL;
+
+/*
+	Read function is provided for compatibility reason - this allows
+  to read unstructured traces, formated as ascii string only
+  */
+static ssize_t
+maint_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+  diva_dbg_entry_head_t* pmsg = 0;
+  diva_os_spin_lock_magic_t old_irql;
+  word size;
+  char* pstr, *dli_label = "UNK";
+	int str_length;
+	int *str_msg;
+
+  if (off != &file->f_pos)
+    return -ESPIPE;
+
+  if (!file->private_data) {
+    for (;;) {
+      while ((pmsg = diva_maint_get_message (&size, &old_irql))) {
+        if (!(pmsg->facility == MSG_TYPE_STRING)) {
+          diva_maint_ack_message (1, &old_irql);
+        } else {
+          break;
+        }
+      }
+
+      if (!pmsg) {
+        if (file->f_flags & O_NONBLOCK) {
+          return (-EAGAIN);
+        }
+        interruptible_sleep_on(&msgwaitq);
+        if (signal_pending(current)) {
+          return (-ERESTARTSYS);
+        }
+      } else {
+        break;
+      }
+    }
+    /*
+      The length of message that shoule be read is:
+      pmsg->data_length + label(25) + DrvID(2) + byte CR + trailing zero
+      */
+    if (!(str_msg = (int*)diva_os_malloc_tbuffer(0, pmsg->data_length + 29 + 2*sizeof(int)))) {
+      diva_maint_ack_message (0, &old_irql);
+      return (-ENOMEM);
+    }
+    pstr = (char*)&str_msg[2];
+
+    switch (pmsg->dli) {
+      case DLI_LOG :
+        dli_label = "LOG";
+        break;
+      case DLI_FTL :
+        dli_label = "FTL";
+        break;
+      case DLI_ERR :
+        dli_label = "ERR";
+        break;
+      case DLI_TRC :
+        dli_label = "TRC";
+        break;
+      case DLI_REG :
+        dli_label = "REG";
+        break;
+      case DLI_MEM :
+        dli_label = "MEM";
+        break;
+      case DLI_SPL :
+        dli_label = "SPL";
+        break;
+      case DLI_IRP :
+        dli_label = "IRP";
+        break;
+      case DLI_TIM :
+        dli_label = "TIM";
+        break;
+      case DLI_TAPI:
+        dli_label = "TAPI";
+        break;
+      case DLI_NDIS:
+        dli_label = "NDIS";
+        break;
+      case DLI_CONN:
+        dli_label = "CONN";
+        break;
+      case DLI_STAT:
+        dli_label = "STAT";
+        break;
+      case DLI_PRV0:
+        dli_label = "PRV0";
+        break;
+      case DLI_PRV1:
+        dli_label = "PRV1";
+        break;
+      case DLI_PRV2:
+        dli_label = "PRV2";
+        break;
+      case DLI_PRV3:
+        dli_label = "PRV3";
+        break;
+    }
+    str_length = sprintf (pstr, "%s %02x %s\n",
+                          dli_label, (byte)pmsg->drv_id, (char*)&pmsg[1]);
+    str_msg[0] = str_length;
+    str_msg[1] = 0;
+    file->private_data = str_msg;
+    diva_maint_ack_message (1, &old_irql);
+  } else {
+    str_msg = (int*)file->private_data;
+    pstr = (char*)&str_msg[2];
+    pstr += str_msg[1]; /* head + offset */
+    str_length = str_msg[0] - str_msg[1]; /* length - offset */
+  }
+  str_length = MIN(str_length, count);
+
+  if (diva_os_copy_to_user(NULL, buf, pstr, str_length)) {
+    diva_os_free_tbuffer(0, str_msg);
+    file->private_data = 0;
+    return (-EFAULT);
+  }
+  str_msg[1] += str_length;
+  if ((str_msg[0] - str_msg[1]) <= 0) {
+    diva_os_free_tbuffer(0, str_msg);
+    file->private_data = 0;
+  }
+
+  return (str_length);
+}
+
+static ssize_t
+maint_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+  return (-ENODEV);
+}                                  
+
+static unsigned int
+maint_poll(struct file *file, poll_table * wait)
+{
+  unsigned int mask = 0;
+
+  poll_wait(file, &msgwaitq, wait);
+  mask = POLLOUT | POLLWRNORM;
+  if (file->private_data || diva_dbg_q_length ()) {
+    mask |= POLLIN | POLLRDNORM;
+  }
+  return (mask);
+}
+
+static int
+maint_open(struct inode *ino, struct file *filep)
+{
+  if (atomic_read(&opened))
+      return(-EBUSY);
+  else
+    atomic_inc(&opened);
+
+  filep->private_data = 0;
+
+  return(0);
+}
+
+static int
+maint_close(struct inode *ino, struct file *filep)
+{
+  if (filep->private_data) {
+    diva_os_free_tbuffer(0, filep->private_data);
+    filep->private_data = 0;
+  }
+
+  atomic_dec(&opened);
+  return(0);
+}
+
+static int maint_ioctl (struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+		return(-EINVAL);
+}
+
+static loff_t
+maint_lseek(struct file *file, loff_t offset, int orig)
+{
+  return(-ESPIPE);
+}
+
+/*
+ * fops
+ */
+static struct file_operations maint_fops =
+{
+	owner:          THIS_MODULE,
+  llseek:         maint_lseek,
+  read:           maint_read,
+  write:          maint_write,
+  poll:           maint_poll,
+  ioctl:          maint_ioctl,
+  open:           maint_open,
+  release:        maint_close,
+};
+
+static int DIVA_INIT_FUNCTION
+create_maint_proc(void)
+{
+  maint_proc_entry = create_proc_entry("maint", S_IFREG | S_IRUGO | S_IWUSR, proc_net_isdn_eicon);
+  if (!maint_proc_entry)
+    return(0);
+
+  maint_proc_entry->proc_fops = &maint_fops;   
+  maint_proc_entry->owner = THIS_MODULE;
+
+  return(1);
+}
+
+static void
+remove_maint_proc(void)
+{
+  if (maint_proc_entry) {
+    remove_proc_entry("maint", proc_net_isdn_eicon);
+    maint_proc_entry = NULL;
+  }
+}
+
+/*
+ * device node operations
+ */
+static ssize_t divas_maint_write(struct file * file, const char * buf,
+            size_t count, loff_t *ppos)
+{
+		return(maint_read_write((char *)buf));
+}
+
+static ssize_t divas_maint_read(struct file * file, char * buf,
+            size_t count, loff_t *ppos)
+{
+		return(maint_read_write(buf));
+}
+
+static struct file_operations divas_maint_fops =
+{
+		owner:			THIS_MODULE,
+		llseek:			maint_lseek,
+		read:				divas_maint_read,
+		write:			divas_maint_write,
+		poll:				maint_poll,
+		ioctl:			maint_ioctl,
+		open:				maint_open,
+		release:		maint_close,
+};
+
+static void divas_maint_unregister_chrdev(void)
+{
+		if (devfs_handle)
+				devfs_unregister (devfs_handle);
+		unregister_chrdev(major, "DivasMAINT");
+}
+
+static int DIVA_INIT_FUNCTION divas_maint_register_chrdev(void)
+{
+		if (register_chrdev (major, "DivasMAINT", &divas_maint_fops))
+		{
+				printk(KERN_ERR "%s: failed to create /dev entry.\n", DRIVERLNAME);
+				return(0);
+		}
+		devfs_handle = devfs_register(NULL, "DivasMAINT", DEVFS_FL_DEFAULT, major, 0,
+					S_IFCHR | S_IRUSR | S_IWUSR, &divas_maint_fops, NULL);
+
+		return(1);
+}
+
+/*
+ * wake up reader
+ */
+void diva_maint_wakeup_read (void)
+{
+		wake_up_interruptible (&msgwaitq);
+}
+
+/*
+ *  Driver Load
+ */
+static int DIVA_INIT_FUNCTION maint_init(void)
+{
+  char tmprev[50];
+  int ret = 0;
+  void* buffer = 0;
+
+  MOD_INC_USE_COUNT;
+
+  do_gettimeofday (&start_time);
+  init_waitqueue_head(&msgwaitq);
+
+  printk(KERN_INFO "%s\n", DRIVERNAME);
+  printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE);
+  strcpy(tmprev, main_revision);
+  printk("%s  Build: %s  Major: %d\n", getrev(tmprev), DIVA_BUILD, major);
+
+	if (!divas_maint_register_chrdev())
+	{
+			ret = -EIO;
+			goto out;
+	}
+  if (!create_maint_proc()) {
+    printk(KERN_ERR "%s: failed to create proc entry.\n", DRIVERLNAME);
+		divas_maint_unregister_chrdev();
+    ret = -EIO;
+    goto out;
+  }
+
+  if (!(mntfunc_init(&buffer_length, &buffer, diva_dbg_mem))) {
+    printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME);
+  	remove_maint_proc();
+		divas_maint_unregister_chrdev();
+    ret = -EIO;
+    goto out;
+  }
+
+  printk(KERN_INFO "%s: trace buffer = %p - %d kBytes, %s \n",
+         DRIVERLNAME, buffer, buffer_length, (diva_dbg_mem == 0) ? "internal" : "external");
+
+out:
+  MOD_DEC_USE_COUNT;
+  return(ret);  
+}
+
+/*
+**  Driver Unload
+*/
+static void DIVA_EXIT_FUNCTION maint_exit(void)
+{
+  remove_maint_proc();
+	divas_maint_unregister_chrdev();
+	mntfunc_finit();
+
+  printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(maint_init);
+module_exit(maint_exit);
+
diff -Nru a/drivers/isdn/hardware/eicon/divasfunc.c b/drivers/isdn/hardware/eicon/divasfunc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/divasfunc.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,244 @@
+/* $Id: divasfunc.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Low level driver for Eicon DIVA Server ISDN cards.
+ *
+ * Copyright 2000-2002 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "di.h"
+#include "io.h"
+#include "divasync.h"
+#include "diva.h"
+#include "xdi_vers.h"
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+extern void DIVA_DIDD_Read (void *, int);
+
+extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+
+#define MAX_DESCRIPTORS  32
+
+extern void diva_run_trap_script (PISDN_ADAPTER IoAdapter, dword ANum);
+extern char *DRIVERRELEASE;
+
+static dword notify_handle;
+static DESCRIPTOR DAdapter;
+static DESCRIPTOR MAdapter;
+
+/* --------------------------------------------------------------------------
+    MAINT driver connector section
+   -------------------------------------------------------------------------- */
+static void no_printf (unsigned char * x ,...)
+{
+  /* dummy debug function */
+}
+DIVA_DI_PRINTF dprintf = no_printf;
+
+#include "debuglib.c"
+
+/*
+ * get the adapters serial number
+ */
+void
+diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf)
+{
+	int contr = 0;
+			 
+	if ((contr = ((IoAdapter->serialNo & 0xff000000) >> 24)))
+	{
+		sprintf(buf, "%d-%d",
+			IoAdapter->serialNo & 0x00ffffff, contr + 1);
+	}
+	else
+	{
+		sprintf(buf, "%d", IoAdapter->serialNo);
+	}
+} 
+
+/*
+ * register a new adapter
+ */
+void diva_xdi_didd_register_adapter (int card)
+{
+  DESCRIPTOR d;
+  IDI_SYNC_REQ req;
+
+  if (card && ((card-1) < MAX_ADAPTER) &&
+      IoAdapters[card-1] && Requests[card-1]) {
+    d.type = IoAdapters[card-1]->Properties.DescType;
+    d.request  = Requests[card-1];
+    d.channels = IoAdapters[card-1]->Properties.Channels;
+    d.features = IoAdapters[card-1]->Properties.Features;
+    DBG_TRC(("DIDD register A(%d) channels=%d", card, d.channels))
+    /* workaround for different Name in structure */
+    strncpy(IoAdapters[card-1]->Name, IoAdapters[card-1]->Properties.Name,
+            MIN(30, strlen(IoAdapters[card-1]->Properties.Name)));
+    req.didd_remove_adapter.e.Req = 0;
+    req.didd_add_adapter.e.Rc = IDI_SYNC_REQ_DIDD_ADD_ADAPTER;
+    req.didd_add_adapter.info.descriptor = (void *)&d;
+    DAdapter.request((ENTITY *)&req);
+    if (req.didd_add_adapter.e.Rc != 0xff) {
+      DBG_ERR(("DIDD register A(%d) failed !", card))
+    } else {
+      IoAdapters[card-1]->os_trap_nfy_Fnc = diva_run_trap_script;
+    }
+  }
+}
+
+/*
+ * remove an adapter
+ */
+void diva_xdi_didd_remove_adapter (int card)
+{
+  IDI_SYNC_REQ req;
+  ADAPTER *a = &IoAdapters[card-1]->a;
+
+  IoAdapters[card-1]->os_trap_nfy_Fnc = NULL;
+  DBG_TRC(("DIDD de-register A(%d)", card))
+  req.didd_remove_adapter.e.Req = 0;
+  req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER;
+  req.didd_remove_adapter.info.p_request = (IDI_CALL)Requests[card-1];
+  DAdapter.request((ENTITY *)&req);
+  memset(&(a->IdTable), 0x00, 256);
+}
+
+/*
+ * start debug
+ */
+static void start_dbg(void)
+{
+  DbgRegister("DIVAS", DRIVERRELEASE, DBG_DEFAULT);
+  DBG_LOG(("DIVA ISDNXDI BUILD (%s[%s]-%s-%s)",
+    DIVA_BUILD, diva_xdi_common_code_build, __DATE__, __TIME__))
+}
+
+/*
+ * stop debug
+ */
+static void stop_dbg(void)
+{
+		DbgDeregister();
+		memset(&MAdapter, 0, sizeof(MAdapter));
+		dprintf = no_printf;
+}
+
+/*
+ * didd callback function
+ */
+static void * didd_callback(void *context, DESCRIPTOR* adapter, int removal)
+{
+  if (adapter->type == IDI_DADAPTER)
+  {
+    DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
+		return(NULL);
+  }
+
+  if (adapter->type == IDI_DIMAINT)
+  {
+    if (removal)
+    {
+				stop_dbg();
+    }
+    else
+    {
+      memcpy(&MAdapter, adapter, sizeof(MAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      start_dbg();
+    }
+  }  return(NULL);
+}
+
+/*
+ * connect to didd
+ */
+static int DIVA_INIT_FUNCTION connect_didd(void)
+{
+  int x = 0;
+  int dadapter = 0;
+  IDI_SYNC_REQ req;
+  DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+  DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+  for (x = 0; x < MAX_DESCRIPTORS; x++)
+  {
+    if (DIDD_Table[x].type == IDI_DADAPTER)
+    {  /* DADAPTER found */
+      dadapter = 1;
+      memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      req.didd_notify.e.Req = 0;
+      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+      req.didd_notify.info.callback = didd_callback;
+      req.didd_notify.info.context = 0;
+      DAdapter.request((ENTITY *)&req);
+      if (req.didd_notify.e.Rc != 0xff)
+			{
+					stop_dbg();
+					return(0);
+			}
+      notify_handle = req.didd_notify.info.handle;
+    } 
+    else if (DIDD_Table[x].type == IDI_DIMAINT)
+    {  /* MAINT found */
+      memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      start_dbg();
+    }
+  }
+
+	if (!dadapter)
+	{
+			stop_dbg();
+	}
+	
+  return(dadapter);
+}
+
+/*
+ * disconnect from didd
+ */
+static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+{
+  IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+  req.didd_notify.e.Req = 0;
+  req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+  req.didd_notify.info.handle = notify_handle;
+  DAdapter.request((ENTITY *)&req);
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION divasfunc_init(void)
+{
+  if(!connect_didd()) {
+    DBG_ERR(("divasfunc: failed to connect to DIDD."))
+    return(0);
+  }
+
+  divasa_xdi_driver_entry ();
+
+  return(1);  
+}
+
+/*
+ * exit
+ */
+void DIVA_EXIT_FUNCTION divasfunc_exit(void)
+{
+  divasa_xdi_driver_unload ();
+  disconnect_didd ();
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/divasi.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,597 @@
+/* $Id: divasi.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * User Mode IDI Interface 
+ *
+ * Copyright 2000,2001 by Armin Schindler (mac@melware.de)
+ * Copyright 2000,2001 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "um_xdi.h"
+#include "um_idi.h"
+
+EXPORT_NO_SYMBOLS;
+
+static char *main_revision = "$Revision: 1.1.2.2 $";
+
+static int major = 242;
+
+MODULE_DESCRIPTION(             "User IDI Interface for Eicon ISDN cards");
+MODULE_AUTHOR(                  "Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE(        "DIVA card driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "Major number for /dev/DivasIDI");
+
+typedef struct _diva_um_idi_os_context {
+	wait_queue_head_t read_wait;
+	wait_queue_head_t close_wait;
+	struct  timer_list diva_timer_id;
+	int aborted;
+} diva_um_idi_os_context_t;
+
+static char *DRIVERNAME = "Eicon DIVA - User IDI (http://www.melware.net)";
+static char *DRIVERLNAME = "diva_idi";
+char *DRIVERRELEASE = "2.0";
+
+static devfs_handle_t devfs_handle;
+
+extern int idifunc_init(void);
+extern void idifunc_finit(void);
+
+/*
+ *  helper functions
+ */
+static char *
+getrev(const char *revision)
+{
+  char *rev;
+  char *p;
+  if ((p = strchr(revision, ':'))) {
+     rev = p + 2;
+     p = strchr(rev, '$');
+     *--p = 0;
+  } else rev = "1.0";
+  return rev;
+}
+
+/*
+ *  LOCALS
+ */
+static loff_t um_idi_lseek (struct file *file, loff_t offset, int orig);
+static ssize_t um_idi_read (struct file *file, char *buf, size_t count, loff_t *offset);
+static ssize_t um_idi_write (struct file *file, const char *buf, size_t count, loff_t *offset);
+static unsigned int um_idi_poll (struct file *file, poll_table *wait);
+static int um_idi_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int um_idi_open (struct inode *inode, struct file *file);
+static int um_idi_release (struct inode *inode, struct file *file);
+static int remove_entity (void* entity);
+static void diva_um_timer_function (unsigned long data);
+
+/*
+ * malloc
+ */
+void* diva_os_malloc (unsigned long flags, unsigned long size)
+{
+  void* ret = NULL;
+
+  if (size) {
+      ret = (void*)vmalloc ((unsigned int)size);
+  }
+  return (ret);
+}
+
+/*
+ * free
+ */
+void diva_os_free (unsigned long unused, void* ptr)
+{
+  if (ptr) {
+    vfree (ptr);
+  }
+}
+
+/*
+ * proc entry
+ */
+extern struct proc_dir_entry *proc_net_isdn_eicon;
+static struct proc_dir_entry *um_idi_proc_entry = NULL;
+
+static int
+um_idi_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+  int len = 0;
+  char tmprev[32];
+
+  len += sprintf(page+len, "%s\n", DRIVERNAME);
+  len += sprintf(page+len, "name     : %s\n", DRIVERLNAME);
+  len += sprintf(page+len, "release  : %s\n", DRIVERRELEASE);
+  strcpy(tmprev, main_revision);
+  len += sprintf(page+len, "revision : %s\n", getrev(tmprev));
+  len += sprintf(page+len, "build    : %s\n", DIVA_BUILD);
+
+  if (off + count >= len)
+    *eof = 1;
+  if (len < off)
+    return 0;
+  *start = page + off;
+  return((count < len-off) ? count : len-off);
+}
+
+static int DIVA_INIT_FUNCTION
+create_um_idi_proc(void)
+{
+  um_idi_proc_entry = create_proc_entry(DRIVERLNAME,
+                     S_IFREG | S_IRUGO | S_IWUSR, proc_net_isdn_eicon);
+  if (!um_idi_proc_entry)
+    return(0);
+
+  um_idi_proc_entry->read_proc = um_idi_proc_read;
+  um_idi_proc_entry->owner = THIS_MODULE;
+
+  return(1);
+}
+
+static void
+remove_um_idi_proc(void)
+{
+  if (um_idi_proc_entry) {
+    remove_proc_entry(DRIVERLNAME, proc_net_isdn_eicon);
+    um_idi_proc_entry = NULL;
+  }
+}
+
+static struct file_operations divas_idi_fops =
+{
+	owner:      THIS_MODULE,
+  llseek:      um_idi_lseek,
+  read:        um_idi_read,
+  write:       um_idi_write,
+  poll:        um_idi_poll,
+  ioctl:       um_idi_ioctl,
+  open:        um_idi_open,
+  release:     um_idi_release,
+};
+
+static void divas_idi_unregister_chrdev(void)
+{
+		if (devfs_handle)
+				devfs_unregister (devfs_handle);
+		unregister_chrdev(major, "DivasIDI");
+}
+
+static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void)
+{
+		if (register_chrdev (major, "DivasIDI", &divas_idi_fops))
+		{
+				printk(KERN_ERR "%s: failed to create /dev entry.\n", DRIVERLNAME);
+				return(0);
+		}
+		devfs_handle = devfs_register(NULL, "DivasIDI", DEVFS_FL_DEFAULT, major, 0,
+					S_IFCHR | S_IRUSR | S_IWUSR, &divas_idi_fops, NULL);
+
+		return(1);
+}
+
+/*
+** Driver Load
+*/
+static int DIVA_INIT_FUNCTION
+divasi_init(void)
+{
+  char tmprev[50];
+  int ret = 0;
+
+  MOD_INC_USE_COUNT;
+
+  printk(KERN_INFO "%s\n", DRIVERNAME);
+  printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE);
+  strcpy(tmprev, main_revision);
+  printk("%s  Build: %s Major: %d\n", getrev(tmprev), DIVA_BUILD, major);
+
+	if (!divas_idi_register_chrdev())
+	{
+    ret = -EIO;
+    goto out;
+	}
+	
+	if(!create_um_idi_proc()) {
+		divas_idi_unregister_chrdev();
+		printk(KERN_ERR "%s: failed to create proc entry.\n", DRIVERLNAME);
+		ret = -EIO;
+		goto out;
+	}
+
+	if(!(idifunc_init())) {
+		remove_um_idi_proc();
+		divas_idi_unregister_chrdev();
+		printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME);
+		ret = -EIO;
+		goto out;
+	}
+
+out:
+  MOD_DEC_USE_COUNT;
+  return (ret);
+}
+
+
+/*
+** Driver Unload
+*/
+static void DIVA_EXIT_FUNCTION
+divasi_exit(void)
+{
+	idifunc_finit();
+  remove_um_idi_proc();
+	divas_idi_unregister_chrdev();
+
+  printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divasi_init);
+module_exit(divasi_exit);
+
+
+/*
+ *  FILE OPERATIONS
+ */
+
+static loff_t
+um_idi_lseek(struct file *file, loff_t offset, int orig)
+{
+  return (-ESPIPE);
+}
+
+static int
+divas_um_idi_copy_to_user (void* os_handle, void* dst, const void* src, int length)
+{
+  memcpy (dst, src, length);
+  return (length);
+}
+
+static ssize_t
+um_idi_read (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	diva_um_idi_os_context_t* p_os;
+	int ret = -EINVAL;
+	void *data;
+
+  if (!file->private_data) {
+    return (-ENODEV);
+  }
+
+	if (!(p_os = (diva_um_idi_os_context_t*)diva_um_id_get_os_context(file->private_data))) {
+			return (-ENODEV);
+	}
+	if (p_os->aborted) {
+			return (-ENODEV);
+	}
+	
+  if(!(data = diva_os_malloc(0, count))) {
+    return (-ENOMEM);
+  }
+
+   ret = diva_um_idi_read (file->private_data,
+                           file, data, count,
+                           divas_um_idi_copy_to_user);
+   switch(ret) {
+     case   0 : /* no message available */
+       ret = (-EAGAIN);
+       break;
+     case (-1): /* adapter was removed */
+       ret  = (-ENODEV);
+       break;
+     case (-2): /* message_length > length of user buffer */
+       ret = (-EFAULT);
+       break;
+   }
+
+   if(ret > 0) {
+     if (copy_to_user(buf, data, ret)) {
+       ret = (-EFAULT);
+     }
+   }
+
+  diva_os_free (0, data);
+  DBG_TRC(("read: ret %d", ret));
+  return (ret);
+}
+
+
+static int
+divas_um_idi_copy_from_user (void* os_handle, void* dst, const void* src, int length)
+{
+  memcpy(dst, src, length);
+  return (length);
+}
+
+static int
+um_idi_open_adapter(struct file *file, int adapter_nr)
+{
+  diva_um_idi_os_context_t* p_os;
+  void* e = divas_um_idi_create_entity ((dword)adapter_nr, (void*)file);
+
+  if (!(file->private_data = e)) {
+    return (0);
+  }
+  p_os = (diva_um_idi_os_context_t*)diva_um_id_get_os_context(e);
+  init_waitqueue_head(&p_os->read_wait);
+  init_waitqueue_head(&p_os->close_wait);
+	init_timer (&p_os->diva_timer_id);
+	p_os->diva_timer_id.function = (void *)diva_um_timer_function;
+	p_os->diva_timer_id.data     = (unsigned long)p_os;
+	p_os->aborted = 0;
+  return (1);
+}
+
+static ssize_t
+um_idi_write (struct file *file, const char *buf, size_t count, loff_t *offset)
+{
+	diva_um_idi_os_context_t* p_os;
+	int ret = -EINVAL;
+	void *data;
+	int adapter_nr = 0;
+
+  if (!file->private_data) {
+		/* the first write() selects the adapter_nr */
+		if (count == sizeof(int)) {
+				if (copy_from_user((void *)&adapter_nr, buf, count))
+						return(-EFAULT);
+				if (!(um_idi_open_adapter(file, adapter_nr)))
+						return(-ENODEV);
+				return(count);
+		} else
+		    return (-ENODEV);
+  }
+
+	if (!(p_os = (diva_um_idi_os_context_t*)diva_um_id_get_os_context(file->private_data))) {
+			return (-ENODEV);
+	}
+	if (p_os->aborted) {
+			return (-ENODEV);
+	}
+	
+  if(!(data = diva_os_malloc(0, count))) {
+    return (-ENOMEM);
+  }
+
+  if (copy_from_user(data, buf, count)) {
+    ret = -EFAULT;
+  }	else {
+    ret = diva_um_idi_write (file->private_data,
+                               file, data, count,
+                               divas_um_idi_copy_from_user);
+    switch (ret) {
+      case   0 : /* no space available */
+        ret = (-EAGAIN);
+        break;
+      case (-1): /* adapter was removed */
+        ret = (-ENODEV);
+        break;
+      case (-2): /* length of user buffer > max message_length */
+        ret = (-EFAULT);
+        break;
+    }
+  }
+  diva_os_free (0, data);
+  DBG_TRC(("write: ret %d", ret));
+  return (ret);
+}
+
+static unsigned int
+um_idi_poll (struct file *file, poll_table *wait)
+{
+  diva_um_idi_os_context_t* p_os;
+
+  if (!file->private_data) {
+    return (POLLERR);
+  }
+
+	if ((!(p_os = (diva_um_idi_os_context_t*)diva_um_id_get_os_context (file->private_data))) ||
+		p_os->aborted) {
+			return (POLLERR);
+	}
+
+  poll_wait (file, &p_os->read_wait, wait);
+
+	if (p_os->aborted) {
+			return (POLLERR);
+	}
+
+  switch (diva_user_mode_idi_ind_ready (file->private_data, file)) {
+    case (-1):
+      return (POLLERR);
+
+    case 0:
+      return (0);
+  }
+
+  return (POLLIN | POLLRDNORM);
+}
+
+static int 
+um_idi_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+  return (-EINVAL);
+}
+
+static int
+um_idi_open (struct inode *inode, struct file *file)
+{
+  return (0);
+}
+
+
+static int
+um_idi_release (struct inode *inode, struct file *file)
+{
+  unsigned int adapter_nr = minor(inode->i_rdev);
+  int ret = 0;
+
+  if (!(file->private_data)) {
+    ret = -ENODEV;
+    goto out;
+  }
+
+  if ((ret = remove_entity (file->private_data))) {
+    goto out;
+  }
+
+  if (divas_um_idi_delete_entity ((int)adapter_nr, file->private_data)) {
+    ret = -ENODEV;
+    goto out;
+  }
+
+out:
+  return(ret);
+}
+
+int
+diva_os_get_context_size (void)
+{
+  return (sizeof(diva_um_idi_os_context_t));
+}
+
+void
+diva_os_wakeup_read (void* os_context)
+{
+  diva_um_idi_os_context_t* p_os = (diva_um_idi_os_context_t*)os_context;
+  wake_up_interruptible (&p_os->read_wait);
+}
+
+void
+diva_os_wakeup_close (void* os_context)
+{
+  diva_um_idi_os_context_t* p_os = (diva_um_idi_os_context_t*)os_context;
+  wake_up_interruptible (&p_os->close_wait);
+}
+
+static
+void diva_um_timer_function (unsigned long data)
+{
+		diva_um_idi_os_context_t* p_os = (diva_um_idi_os_context_t*)data;
+
+		p_os->aborted = 1;
+		wake_up_interruptible (&p_os->read_wait);
+		wake_up_interruptible (&p_os->close_wait);
+		DBG_ERR(("entity removal watchdog"))
+}
+
+/*
+**  If application exits without entity removal this function will remove
+**  entity and block until removal is complete
+*/
+static int
+remove_entity (void* entity)
+{
+  struct task_struct *curtask = current;
+  diva_um_idi_os_context_t* p_os;
+
+	diva_um_idi_stop_wdog (entity);
+
+	if (!entity) {
+			DBG_FTL(("Zero entity on remove"))
+			return (0);
+	}
+
+	if (!(p_os = (diva_um_idi_os_context_t*)diva_um_id_get_os_context(entity))) {
+			DBG_FTL(("Zero entity os context on remove"))
+			return (0);
+	}
+
+	if (!divas_um_idi_entity_assigned(entity) || p_os->aborted) {
+			/*
+				Entity is not assigned, also can be removed
+				*/
+			return (0);
+	}
+
+	DBG_TRC(("E(%08x) check remove", entity))
+
+	/*
+		If adapter not answers on remove request inside of
+		10 Sec, then adapter is dead
+		*/
+	diva_um_idi_start_wdog (entity);
+
+	{
+			DECLARE_WAITQUEUE(wait, curtask);
+
+			add_wait_queue (&p_os->close_wait, &wait);
+			for (;;) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					if (!divas_um_idi_entity_start_remove (entity) || p_os->aborted) {
+							break;
+					}
+					schedule();
+			}
+			set_current_state(TASK_RUNNING);
+  		remove_wait_queue (&p_os->close_wait, &wait);
+	}
+
+	DBG_TRC(("E(%08x) start remove", entity))
+
+	{
+			DECLARE_WAITQUEUE(wait, curtask);
+
+			add_wait_queue (&p_os->close_wait, &wait);
+			for (;;) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					if (!divas_um_idi_entity_assigned (entity) || p_os->aborted) {
+							break;
+					}
+					schedule();
+			}
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue (&p_os->close_wait, &wait);
+	}
+
+	DBG_TRC(("E(%08x) remove complete, aborted:%d", entity, p_os->aborted))
+
+	diva_um_idi_stop_wdog (entity);
+
+	p_os->aborted = 0;
+	
+  return (0);
+}
+
+/*
+ * timer watchdog
+ */
+void diva_um_idi_start_wdog (void* entity) {
+		diva_um_idi_os_context_t* p_os;
+
+		if (entity &&
+				((p_os = (diva_um_idi_os_context_t*)diva_um_id_get_os_context(entity)))) {
+			mod_timer (&p_os->diva_timer_id, jiffies + 10*HZ);
+		}
+}
+
+void diva_um_idi_stop_wdog (void* entity) {
+		diva_um_idi_os_context_t* p_os;
+
+		if (entity &&
+				((p_os = (diva_um_idi_os_context_t*)diva_um_id_get_os_context(entity)))) {
+			del_timer (&p_os->diva_timer_id);
+		}
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/divasmain.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,941 @@
+/* $Id: divasmain.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Low level driver for Eicon DIVA Server ISDN cards.
+ *
+ * Copyright 2000-2002 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/unistd.h>
+#include <linux/vmalloc.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/tqueue.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <linux/kmod.h>
+
+#include "platform.h"
+#undef ID_MASK
+#undef N_DATA
+#include "pc.h"
+#include "dlist.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "diva.h"
+#include "diva_pci.h"
+#include "di.h"
+#include "io.h"
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "xdi_vers.h"
+#include "diva_dma.h"
+
+EXPORT_NO_SYMBOLS;
+static char *main_revision = "$Revision: 1.1.2.2 $";
+
+int errno = 0;
+static int major = 240;
+
+MODULE_DESCRIPTION( "Kernel driver for Eicon DIVA Server cards");
+MODULE_AUTHOR(      "Cytronics & Melware, Eicon Networks");
+MODULE_LICENSE("GPL");
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "Major number for /dev/Divas");
+
+static char *DRIVERNAME = "Eicon DIVA Server driver (http://www.melware.net)";
+static char *DRIVERLNAME = "divas";
+char *DRIVERRELEASE = "2.0";
+
+extern void diva_os_irq_wrapper (int irq, void* context, struct pt_regs* regs);
+extern int create_divas_proc(void);
+extern void remove_divas_proc(void);
+extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
+extern int divasfunc_init(void);
+extern void divasfunc_exit(void);
+
+static devfs_handle_t devfs_handle;
+
+typedef struct _diva_os_thread_dpc {
+	struct tasklet_struct divas_task;
+  diva_os_soft_isr_t*   psoft_isr;
+	struct tq_struct      trap_script_task;
+  int                   card_failed;
+} diva_os_thread_dpc_t;
+
+/* --------------------------------------------------------------------------
+    PCI driver interface section
+   -------------------------------------------------------------------------- */
+/*
+  vendor, device	Vendor and device ID to match (or PCI_ANY_ID)
+  subvendor,	Subsystem vendor and device ID to match (or PCI_ANY_ID)
+  subdevice
+  class,		Device class to match. The class_mask tells which bits
+  class_mask	of the class are honored during the comparison.
+  driver_data	Data private to the driver.
+  */
+
+/*
+  List should be sorted
+  */
+#if !defined(PCI_DEVICE_ID_EICON_4BRI)
+#define PCI_DEVICE_ID_EICON_4BRI             0xE012
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_4BRI_2)
+#define PCI_DEVICE_ID_EICON_4BRI_2           0xE013
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_MAESTRAP_2)
+#define PCI_DEVICE_ID_EICON_MAESTRAP_2       0xE015
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_4BRI_VOIP)
+#define PCI_DEVICE_ID_EICON_4BRI_VOIP        0xE016
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_4BRI_2_VOIP)
+#define PCI_DEVICE_ID_EICON_4BRI_2_VOIP      0xE017
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_BRI2M_2)
+#define PCI_DEVICE_ID_EICON_BRI2M_2          0xE018
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP)
+#define PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP  0xE019
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_2F)
+#define PCI_DEVICE_ID_EICON_2F               0xE01A
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_BRI2M_2_VOIP)
+#define PCI_DEVICE_ID_EICON_BRI2M_2_VOIP     0xE01B
+#endif
+
+/*
+  This table should be sorted by PCI device ID
+  */
+static struct pci_device_id divas_pci_tbl[] __devinitdata = {
+/* Diva Server BRI-2M PCI 0xE010 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRA,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_MAESTRA_PCI },
+/* Diva Server 4BRI-8M PCI 0xE012 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_PCI },
+/* Diva Server 4BRI-8M 2.0 PCI 0xE013 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_2,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_V2_PCI },
+/* Diva Server PRI-30M PCI 0xE014 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_PCI },
+/* Diva Server PRI 2.0 adapter 0xE015 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_V2_PCI },
+/* Diva Server Voice 4BRI-8M PCI 0xE016 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_VOIP,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_PCI },
+/* Diva Server Voice 4BRI-8M 2.0 PCI 0xE017 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_2_VOIP,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI },
+/* Diva Server BRI-2M 2.0 PCI 0xE018 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2M_V2_PCI },
+/* Diva Server Voice PRI 2.0 PCI 0xE019 */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI },
+/* Diva Server 2FX 0xE01A */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_2F,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2F_PCI },
+/* Diva Server Voice BRI-2M 2.0 PCI 0xE01B */
+  { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2_VOIP,
+    PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI },
+  {0,}  /* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, divas_pci_tbl);
+
+static int divas_init_one (struct pci_dev *pdev,
+                           const struct pci_device_id *ent);
+static void divas_remove_one (struct pci_dev *pdev);
+
+static struct pci_driver diva_pci_driver = {
+  name:     "divas",
+  probe:    divas_init_one,
+  remove:   divas_remove_one,
+  id_table: divas_pci_tbl,
+};
+
+/*********************************************************
+ ** little helper functions
+ *********************************************************/
+static char *
+getrev(const char *revision)
+{
+        char *rev;
+        char *p;
+        if ((p = strchr(revision, ':'))) {
+                rev = p + 2;
+                p = strchr(rev, '$');
+                *--p = 0;
+        } else rev = "1.0";
+        return rev;
+} 
+
+void
+diva_os_sleep (dword mSec)
+{
+  unsigned long timeout = HZ * mSec / 1000 + 1;
+
+  set_current_state(TASK_UNINTERRUPTIBLE);
+  schedule_timeout(timeout);
+}
+
+void
+diva_os_wait (dword mSec)
+{
+  mdelay (mSec);
+} 
+
+void
+diva_log_info(unsigned char * format, ...)
+{
+  va_list args;
+  unsigned char line[160];
+
+  va_start(args, format);
+  vsprintf(line, format, args);  
+  va_end(args);
+
+  printk(KERN_INFO "%s: %s\n", DRIVERLNAME, line);
+}
+
+void
+divas_get_version(char *p)
+{
+  char tmprev[32];
+
+  strcpy(tmprev, main_revision);
+  sprintf(p, "%s: %s(%s) %s(%s)\n", DRIVERLNAME, DRIVERRELEASE,
+                          getrev(tmprev),
+                          diva_xdi_common_code_build,
+                          DIVA_BUILD);
+}
+
+/*********************************************************
+ ** malloc / free
+ *********************************************************/
+
+void* diva_os_malloc (unsigned long flags, unsigned long size)
+{
+  void* ret = NULL;
+ 
+  if (size) {
+      ret = (void*)vmalloc ((unsigned int)size);
+  }
+  return (ret);
+}
+
+void
+diva_os_free (unsigned long unused, void* ptr)
+{
+  if (ptr) {
+    vfree (ptr);
+  }
+}
+
+/* --------------------------------------------------------------------------
+    Nonify user mode helper about card failure
+   -------------------------------------------------------------------------- */
+#define TRAP_PROG  "/usr/sbin/divas_trap.rc"
+
+static void diva_adapter_trapped (void* context) {
+  diva_os_thread_dpc_t* pdpc = (diva_os_thread_dpc_t*)context;
+
+  if (pdpc && pdpc->card_failed) {
+    char * envp[] = { "HOME=/",
+                      "TERM=linux",
+                      "PATH=/usr/sbin:/sbin:/bin:/usr/bin", 0 };
+    char *argv[] = { TRAP_PROG, "trap", 0, 0 };
+    char adapter[8];
+    int ret;
+
+    sprintf (adapter, "%d", pdpc->card_failed-1);
+    pdpc->card_failed = 0;
+    argv[2] = &adapter[0];
+
+    ret = call_usermodehelper (argv[0], argv, envp);
+
+    if (ret) {
+      printk(KERN_ERR "%s: couldn't start trap script, errno %d\n",
+            DRIVERLNAME, ret);
+    }
+  }
+}
+
+/*
+ * run the trap script
+ */
+void diva_run_trap_script (PISDN_ADAPTER IoAdapter, dword ANum)
+{
+  diva_os_soft_isr_t* psoft_isr  = &IoAdapter->isr_soft_isr;
+  diva_os_thread_dpc_t* context = (diva_os_thread_dpc_t*)psoft_isr->object;
+
+  if (context && !context->card_failed) {
+    context->card_failed = ANum+1;
+    schedule_task(&context->trap_script_task);
+	}
+}
+
+/* --------------------------------------------------------------------------
+    PCI Bus services  
+   -------------------------------------------------------------------------- */
+byte diva_os_get_pci_bus (void* pci_dev_handle)
+{
+  struct pci_dev *pdev = (struct pci_dev*)pci_dev_handle;
+  return ((byte)pdev->bus->number);
+}
+
+byte diva_os_get_pci_func (void* pci_dev_handle)
+{
+  struct pci_dev *pdev = (struct pci_dev*)pci_dev_handle;
+  return ((byte)pdev->devfn);
+}
+
+unsigned long divasa_get_pci_irq (unsigned char bus, unsigned char func, void* pci_dev_handle)
+{
+  unsigned char irq = 0;
+  struct pci_dev	*dev = (struct pci_dev*)pci_dev_handle;
+
+	irq = dev->irq;
+ 
+  return ((unsigned long)irq);
+} 
+
+unsigned long divasa_get_pci_bar (unsigned char bus, unsigned char func, int bar, void* pci_dev_handle)
+{
+  unsigned long ret = 0;
+  struct pci_dev	*dev = (struct pci_dev*)pci_dev_handle;
+
+  if (bar < 6) {
+    ret = dev->resource[bar].start;
+  }
+
+  DBG_TRC(("GOT BAR[%d]=%08x", bar, ret));
+
+  {
+    unsigned long type = (ret & 0x00000001);
+    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+        DBG_TRC(("  I/O"));
+        ret &= PCI_BASE_ADDRESS_IO_MASK;
+    } else {
+        DBG_TRC(("  memory"));
+        ret &= PCI_BASE_ADDRESS_MEM_MASK;
+    }
+    DBG_TRC(("  final=%08x", ret));  
+  }
+
+  return(ret);
+}
+
+void PCIwrite (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle)
+{
+  struct pci_dev	*dev = (struct pci_dev*)pci_dev_handle;
+
+  switch (length) {
+      case 1: /* byte */
+          pci_write_config_byte (dev, offset, *(unsigned char*)data);
+          break;
+      case 2: /* word */
+          pci_write_config_word (dev, offset, *(unsigned short*)data);
+          break;
+      case 4: /* dword */
+          pci_write_config_dword (dev, offset, *(unsigned int*)data);
+          break;
+ 
+      default: /* buffer */
+          if (!(length % 4) && !(length & 0x03)) { /* Copy as dword */ 
+            dword* p = (dword*) data;
+            length /= 4;
+ 
+            while (length--) {
+              pci_write_config_dword (dev, offset, *(unsigned int*)p++);
+            }
+          } else { /* copy as byte stream */
+            byte* p = (byte*)data;
+ 
+            while (length--) {
+              pci_write_config_byte (dev, offset, *(unsigned char*)p++);
+            }
+          }
+  } 
+}
+
+void PCIread (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle)
+{
+  struct pci_dev	*dev = (struct pci_dev*)pci_dev_handle;
+
+  switch (length) {
+      case 1: /* byte */
+          pci_read_config_byte (dev, offset, (unsigned char*)data);
+          break;
+      case 2: /* word */
+          pci_read_config_word (dev, offset, (unsigned short*)data);
+          break;
+      case 4: /* dword */
+          pci_read_config_dword (dev, offset, (unsigned int*)data);
+          break;
+ 
+      default: /* buffer */
+          if (!(length % 4) && !(length & 0x03)) { /* Copy as dword */
+              dword* p = (dword*)data;
+              length /= 4;
+ 
+              while (length--) {
+                pci_read_config_dword (dev, offset, (unsigned int*)p++);
+              }
+          } else { /* copy as byte stream */
+              byte* p = (byte*) data;
+ 
+              while (length--) {
+                pci_read_config_byte (dev, offset, (unsigned char*)p++);
+              }
+          }
+  }
+} 
+
+/*
+  Init map with DMA pages. It is not problem if some allocations fail -
+  the channels that will not get one DMA page will use standard PIO
+  interface
+  */
+static void *diva_pci_alloc_consistent (struct pci_dev *hwdev,
+                                        size_t size,
+                                        dma_addr_t * dma_handle,
+                                        void** addr_handle) {
+  void* addr = pci_alloc_consistent (hwdev, size, dma_handle);
+
+  *addr_handle = addr;
+
+  return (addr);
+}
+
+void diva_init_dma_map (void* hdev,
+                        struct _diva_dma_map_entry** ppmap,
+                        int nentries) {
+	struct pci_dev* pdev = (struct pci_dev*)hdev;
+	struct _diva_dma_map_entry* pmap = diva_alloc_dma_map (hdev, nentries);
+
+  if (pmap) {
+    int i;
+    dma_addr_t dma_handle;
+    void* cpu_addr;
+    void* addr_handle;
+
+    for (i = 0; i < nentries; i++) {
+      if (!(cpu_addr = diva_pci_alloc_consistent (pdev,
+                                             PAGE_SIZE,
+                                             &dma_handle,
+                                             &addr_handle))) {
+        break;
+      }
+      diva_init_dma_map_entry (pmap, i, cpu_addr,
+                               (dword)dma_handle, addr_handle);
+      DBG_TRC(("dma map alloc [%d]=(%08lx:%08x:%08lx)",
+               i, (unsigned long)cpu_addr, (dword)dma_handle, (unsigned long)addr_handle))
+    }
+  }
+
+  *ppmap = pmap;
+}
+
+/*
+  Free all contained in the map entries and memory used by the map
+  Should be always called after adapter removal from DIDD array
+  */
+void diva_free_dma_map (void* hdev,
+                        struct _diva_dma_map_entry* pmap) {
+  struct pci_dev* pdev = (struct pci_dev*)hdev;
+  int i;
+  dword      phys_addr;
+  void*      cpu_addr;
+  dma_addr_t dma_handle;
+  void* addr_handle;
+
+  for (i = 0; (pmap != 0); i++) {
+    diva_get_dma_map_entry (pmap, i, &cpu_addr, &phys_addr);
+    if (!cpu_addr) {
+      break;
+    }
+    addr_handle = diva_get_entry_handle (pmap, i);
+    dma_handle = (dma_addr_t)phys_addr;
+    pci_free_consistent (pdev, PAGE_SIZE, addr_handle, dma_handle);
+    DBG_TRC(("dma map free [%d]=(%08lx:%08x:%08lx)",
+             i, (unsigned long)cpu_addr, (dword)dma_handle, (unsigned long)addr_handle))
+  }
+
+  diva_free_dma_mapping (pmap);
+}
+
+
+/*********************************************************
+ ** I/O port utilities  
+ *********************************************************/
+
+int
+diva_os_register_io_port (int on, unsigned long port, unsigned long length, const char* name)
+{
+  int ret;
+
+  if (on) {
+    if ((ret = check_region (port, length)) < 0) {
+        DBG_ERR(("A: I/O: can't register port=%08x, error=%d", port, ret))
+        return (-1);
+    }
+    request_region (port, length, name);
+  } else {
+    release_region (port, length);
+  }
+  return (0);
+}
+
+void *
+divasa_remap_pci_bar (unsigned long  bar, unsigned long area_length)
+{
+  void *ret;
+
+  ret = (void*)ioremap(bar, area_length);
+  DBG_TRC(("remap(%08x)->%08x", bar, ret));
+  return (ret);
+}
+
+void
+divasa_unmap_pci_bar (void* bar)
+{
+  if (bar) {
+    iounmap (bar);
+  }
+}
+
+/*********************************************************
+ ** I/O port access 
+ *********************************************************/
+byte __inline__
+inpp (void* addr) {
+  return (inb((unsigned long)addr));
+}
+
+word __inline__
+inppw (void* addr)
+{
+  return (inw((unsigned long)addr));
+}
+
+void __inline__
+inppw_buffer (void* addr, void* P, int length)
+{
+  insw ((unsigned long)addr, (word*)P, length>>1);
+}
+
+void __inline__
+outppw_buffer (void* addr, void* P, int length)
+{
+  outsw ((unsigned long)addr, (word*)P, length>>1);
+}
+
+void __inline__
+outppw (void* addr, word w)
+{
+  outw (w, (unsigned long)addr);
+}
+
+void __inline__
+outpp (void* addr, word p)
+{
+  outb (p, (unsigned long)addr);
+}
+
+/* --------------------------------------------------------------------------
+    IRQ request / remove  
+   -------------------------------------------------------------------------- */
+int diva_os_register_irq (void* context, byte irq, const char* name) {
+  int result = request_irq (irq, diva_os_irq_wrapper,
+                            SA_INTERRUPT | SA_SHIRQ, name, context);
+  return (result);
+}
+
+void diva_os_remove_irq (void* context, byte irq) {
+  free_irq (irq, context);
+}
+
+/* --------------------------------------------------------------------------
+    DPC framework implementation
+   -------------------------------------------------------------------------- */
+static void diva_os_dpc_proc(unsigned long context)
+{
+  diva_os_thread_dpc_t* psoft_isr = (diva_os_thread_dpc_t*)context;
+  diva_os_soft_isr_t* pisr = psoft_isr->psoft_isr;
+
+	(*(pisr->callback))(pisr, pisr->callback_context);
+}
+
+int diva_os_initialize_soft_isr (diva_os_soft_isr_t* psoft_isr,
+                                 diva_os_soft_isr_callback_t callback,
+                                 void*   callback_context)
+{
+  diva_os_thread_dpc_t* pdpc;
+
+  pdpc = (diva_os_thread_dpc_t*)diva_os_malloc (0, sizeof (*pdpc));
+  if (!(psoft_isr->object = pdpc)) {
+		return (-1);
+	}
+  memset (pdpc, 0x00, sizeof (*pdpc));
+  psoft_isr->callback         = callback;
+  psoft_isr->callback_context = callback_context;
+  pdpc->psoft_isr             = psoft_isr;
+  INIT_TQUEUE(&pdpc->trap_script_task, diva_adapter_trapped, pdpc);
+	tasklet_init(&pdpc->divas_task, diva_os_dpc_proc, (unsigned long)pdpc);
+
+  return (0);
+}
+
+int diva_os_schedule_soft_isr (diva_os_soft_isr_t* psoft_isr)
+{
+  if (psoft_isr && psoft_isr->object) {
+  	diva_os_thread_dpc_t* pdpc = (diva_os_thread_dpc_t*)psoft_isr->object;
+
+		tasklet_schedule(&pdpc->divas_task);
+	}
+
+  return (1);
+}
+
+int diva_os_cancel_soft_isr (diva_os_soft_isr_t* psoft_isr)
+{
+  if (psoft_isr && psoft_isr->object) {
+  	diva_os_thread_dpc_t* pdpc = (diva_os_thread_dpc_t*)psoft_isr->object;
+		tasklet_kill(&pdpc->divas_task);
+	}
+  return (0);
+} 
+  
+void diva_os_remove_soft_isr (diva_os_soft_isr_t* psoft_isr)
+{
+  if (psoft_isr && psoft_isr->object) {
+    diva_os_thread_dpc_t* pdpc = (diva_os_thread_dpc_t*)psoft_isr->object;
+    void* mem;
+
+		tasklet_kill(&pdpc->divas_task);
+
+    mem = psoft_isr->object;
+    psoft_isr->object = 0;
+		flush_scheduled_tasks();
+    diva_os_free (0, mem);
+	}
+}
+
+/*
+ * kernel/user space copy functions
+ */
+static int
+xdi_copy_to_user(void* os_handle, void* dst, const void* src, int length)
+{
+		if (copy_to_user (dst, src, length)) {
+				return (-EFAULT);
+		}
+		return (length);
+} 
+
+static int
+xdi_copy_from_user (void* os_handle, void* dst, const void* src, int length)
+{
+		if (copy_from_user(dst, src, length)) {
+				return (-EFAULT);
+		}
+		return (length);
+}
+
+/*
+ * device node operations
+ */
+static int divas_open(struct inode * inode, struct file * file)
+{
+		return(0);
+}
+
+static int divas_release(struct inode * inode, struct file * file)
+{
+		if (file->private_data) {
+				diva_xdi_close_adapter (file->private_data, file);
+		}
+		return(0);
+}
+
+static int divas_ioctl(struct inode *inode, struct file *file,
+            unsigned int cmd, unsigned long arg)
+{
+		return(-EINVAL);
+}
+
+static ssize_t divas_write(struct file * file, const char * buf,
+            size_t count, loff_t *ppos)
+{
+		int ret = -EINVAL;
+
+		if (!file->private_data) {
+				file->private_data = diva_xdi_open_adapter(file, buf,
+									count, xdi_copy_from_user);
+		}
+		if (!file->private_data) {
+				return (-ENODEV);
+		}
+
+		ret = diva_xdi_write(file->private_data, file,
+													buf, count, xdi_copy_from_user);
+		switch(ret) {
+				case -1:	/* Message should be removed from rx mailbox first */
+					ret = -EBUSY;
+					break;
+				case -2:	/* invalid adapter was specified in this call */
+					ret = -ENOMEM;
+					break;
+				case -3:
+					ret = -ENXIO;
+					break;
+		}
+		DBG_TRC(("write: ret %d", ret));
+		return(ret);
+}
+
+static ssize_t divas_read(struct file * file, char * buf,
+            size_t count, loff_t *ppos)
+{
+		int ret = -EINVAL;
+
+		if (!file->private_data) {
+				file->private_data = diva_xdi_open_adapter(file, buf,
+									count, xdi_copy_from_user);
+		}
+		if (!file->private_data) {
+				return (-ENODEV);
+		}
+
+		ret = diva_xdi_read(file->private_data, file,
+													buf, count, xdi_copy_to_user);
+		switch(ret) {
+				case -1:	/* RX mailbox is empty */
+					ret = -EAGAIN;
+					break;
+				case -2:	/* no memory, mailbox was cleared, last command is failed */
+					ret = -ENOMEM;
+					break;
+				case -3:	/* can't copy to user, retry */
+					ret = -EFAULT;
+					break;
+		}
+		DBG_TRC(("read: ret %d", ret));
+		return(ret);
+}
+
+static unsigned int divas_poll(struct file *file, poll_table * wait)
+{
+		if (!file->private_data) {
+				return (POLLERR);
+		}
+		return (POLLIN | POLLRDNORM);
+}
+
+
+static loff_t divas_lseek(struct file *file, loff_t offset, int orig)
+{
+		return(-ESPIPE);
+}
+
+static struct file_operations divas_fops =
+{
+		owner:			THIS_MODULE,
+		llseek:			divas_lseek,
+		read:				divas_read,
+		write:			divas_write,
+		poll:				divas_poll,
+		ioctl:			divas_ioctl,
+		open:				divas_open,
+		release:		divas_release,
+};
+
+static void divas_unregister_chrdev(void)
+{
+		if (devfs_handle)
+				devfs_unregister (devfs_handle);
+		unregister_chrdev(major, "Divas");
+}
+
+static int DIVA_INIT_FUNCTION divas_register_chrdev(void)
+{
+		if (register_chrdev (major, "Divas", &divas_fops))
+		{
+				printk(KERN_ERR "%s: failed to create /dev entry.\n", DRIVERLNAME);
+				return(0);
+		}
+		devfs_handle = devfs_register(NULL, "Divas", DEVFS_FL_DEFAULT, major, 0,
+					S_IFCHR | S_IRUSR | S_IWUSR, &divas_fops, NULL);
+
+		return(1);
+}
+
+/* --------------------------------------------------------------------------
+    PCI driver section
+   -------------------------------------------------------------------------- */
+static int __devinit divas_init_one (struct pci_dev *pdev,
+                                     const struct pci_device_id *ent) {
+  void* pdiva = 0;
+  u8 pci_latency;
+  u8 new_latency = 32;
+
+  DBG_TRC(("%s bus: %08x fn: %08x insertion.\n",
+          CardProperties[ent->driver_data].Name,
+          pdev->bus->number, pdev->devfn))
+  printk(KERN_INFO "%s: %s bus: %08x fn: %08x insertion.\n",
+         DRIVERLNAME, CardProperties[ent->driver_data].Name,
+         pdev->bus->number, pdev->devfn);
+
+  if (pci_enable_device (pdev)) {
+    DBG_TRC(("%s: %s bus: %08x fn: %08x device init failed.\n",
+           DRIVERLNAME, CardProperties[ent->driver_data].Name,
+           pdev->bus->number, pdev->devfn))
+    printk(KERN_ERR "%s: %s bus: %08x fn: %08x device init failed.\n",
+           DRIVERLNAME, CardProperties[ent->driver_data].Name,
+           pdev->bus->number, pdev->devfn);
+    return (-EIO);
+  }
+
+  pci_set_master (pdev);
+
+  pci_read_config_byte (pdev, PCI_LATENCY_TIMER, &pci_latency);
+  if (!pci_latency) {
+    DBG_TRC(("%s: bus: %08x fn: %08x fix latency.\n",
+           DRIVERLNAME, pdev->bus->number, pdev->devfn))
+    printk(KERN_INFO "%s: bus: %08x fn: %08x fix latency.\n",
+           DRIVERLNAME, pdev->bus->number, pdev->devfn);
+    pci_write_config_byte (pdev, PCI_LATENCY_TIMER, new_latency);
+  }
+
+  if (!(pdiva = diva_driver_add_card (pdev, ent->driver_data))) {
+    DBG_TRC(("%s: %s bus: %08x fn: %08x card init failed.\n",
+           DRIVERLNAME, CardProperties[ent->driver_data].Name,
+           pdev->bus->number, pdev->devfn))
+    printk(KERN_ERR "%s: %s bus: %08x fn: %08x card init failed.\n",
+           DRIVERLNAME, CardProperties[ent->driver_data].Name,
+           pdev->bus->number, pdev->devfn);
+    return (-EIO);
+  }
+
+  pci_set_drvdata(pdev, pdiva);
+
+  return (0);
+}
+
+static void __devexit divas_remove_one (struct pci_dev *pdev) {
+  void* pdiva = pci_get_drvdata (pdev);
+
+  DBG_TRC(("bus: %08x fn: %08x removal.\n",
+          pdev->bus->number, pdev->devfn))
+  printk(KERN_INFO "%s: bus: %08x fn: %08x removal.\n",
+         DRIVERLNAME, pdev->bus->number, pdev->devfn);
+
+  if (pdiva) {
+    diva_driver_remove_card (pdiva);
+  }
+
+}
+
+/* --------------------------------------------------------------------------
+    Driver Load / Startup  
+   -------------------------------------------------------------------------- */
+static int DIVA_INIT_FUNCTION divas_init(void) {
+  char tmprev[50];
+  int ret = 0;
+
+  MOD_INC_USE_COUNT;
+
+  printk(KERN_INFO "%s\n", DRIVERNAME);
+  printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE);
+  strcpy(tmprev, main_revision);
+  printk("%s  Build: %s(%s) Major: %d\n", getrev(tmprev),
+        diva_xdi_common_code_build, DIVA_BUILD, major);
+  printk(KERN_INFO "%s: support for: ", DRIVERLNAME);
+#ifdef CONFIG_ISDN_DIVAS_BRIPCI
+  printk("BRI/PCI ");
+#endif
+#ifdef CONFIG_ISDN_DIVAS_4BRIPCI
+  printk("4BRI/PCI ");
+#endif
+#ifdef CONFIG_ISDN_DIVAS_PRIPCI
+  printk("PRI/PCI ");
+#endif
+  printk("\n");
+
+  if(!divasfunc_init()) {
+    printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME);
+    ret = -EIO;
+    goto out;
+  }
+
+	if (!divas_register_chrdev())
+	{
+    divasfunc_exit();
+    ret = -EIO;
+    goto out;
+	}
+
+  if(!create_divas_proc()) {
+    remove_divas_proc();
+		divas_unregister_chrdev();
+    divasfunc_exit();
+    printk(KERN_ERR "%s: failed to create proc entry.\n", DRIVERLNAME);
+    ret = -EIO;
+    goto out;
+  }
+
+  if ((ret = pci_module_init(&diva_pci_driver))) {
+    remove_divas_proc();
+		divas_unregister_chrdev();
+    divasfunc_exit();
+    printk(KERN_ERR "%s: failed to init pci driver.\n", DRIVERLNAME);
+    goto out;
+  }
+
+out:
+  MOD_DEC_USE_COUNT;
+  return(ret);  
+}
+
+/* --------------------------------------------------------------------------
+    Driver Unload
+   -------------------------------------------------------------------------- */
+static void DIVA_EXIT_FUNCTION divas_exit(void) {
+  pci_unregister_driver (&diva_pci_driver);
+  remove_divas_proc ();
+	divas_unregister_chrdev();
+	divasfunc_exit();
+
+  printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divas_init);
+module_exit(divas_exit);
+
diff -Nru a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/divasproc.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,412 @@
+/* $Id: divasproc.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Low level driver for Eicon DIVA Server ISDN cards.
+ * /proc functions
+ *
+ * Copyright 2000,2001 by Armin Schindler (mac@melware.de)
+ * Copyright 2000,2001 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+
+#include "platform.h"
+#include "debuglib.h"
+#include "dlist.h"
+#undef ID_MASK
+#undef N_DATA
+#include "pc.h"
+#include "diva_pci.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "di.h"
+#include "io.h"
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "diva.h"
+
+
+EXPORT_NO_SYMBOLS;
+
+extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+extern diva_entity_queue_t adapter_queue;
+extern void divas_get_version(char *);
+extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
+
+/*********************************************************
+ ** Functions for /proc interface / File operations
+ *********************************************************/
+
+static char *divas_proc_name = "divas";
+static char *adapter_dir_name = "adapter";
+static char *info_proc_name = "info";
+static char *grp_opt_proc_name = "group_optimization";
+static char *d_l1_down_proc_name = "dynamic_l1_down";
+
+/*
+** "divas" entry
+*/
+
+extern struct proc_dir_entry *proc_net_isdn_eicon;
+static struct proc_dir_entry *divas_proc_entry = NULL;
+
+static ssize_t
+divas_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+  int len = 0;
+  int cadapter;
+  char tmpbuf[80];
+  char tmpser[16];
+
+  if (*off)
+      return 0;
+  if (off != &file->f_pos)
+      return -ESPIPE;
+
+  divas_get_version(tmpbuf);
+  if(copy_to_user(buf+len, &tmpbuf, strlen(tmpbuf)))
+      return -EFAULT;
+  len += strlen(tmpbuf);
+
+  for(cadapter = 0; cadapter < MAX_ADAPTER; cadapter++) {
+    if (IoAdapters[cadapter]) {
+      diva_get_vserial_number(IoAdapters[cadapter], tmpser);
+      sprintf(tmpbuf, "%2d: %-30s Serial:%-10s IRQ:%2d\n", cadapter + 1,
+          IoAdapters[cadapter]->Properties.Name,
+          tmpser,
+          IoAdapters[cadapter]->irq_info.irq_nr);
+      if((strlen(tmpbuf)+len) > count)
+        break;
+      if(copy_to_user(buf+len, &tmpbuf, strlen(tmpbuf)))
+        return -EFAULT;
+      len += strlen(tmpbuf);
+    }
+  }
+
+  *off += len;
+  return(len);
+}
+
+static ssize_t
+divas_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+  return (-ENODEV);
+}                                  
+
+static unsigned int
+divas_poll(struct file *file, poll_table * wait)
+{
+  return (POLLERR);
+}
+
+static int
+divas_open(struct inode *inode, struct file *file)
+{
+  return(0);
+}
+
+static int
+divas_close(struct inode *inode, struct file *file)
+{
+  return(0);
+}
+
+static int
+divas_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+		return(-EINVAL);
+}
+
+static loff_t
+divas_lseek(struct file *file, loff_t offset, int orig)
+{
+  return(-ESPIPE);
+}
+
+static struct file_operations divas_fops =
+{
+	owner: 					THIS_MODULE,
+  llseek:         divas_lseek,
+  read:           divas_read,
+  write:          divas_write,
+  poll:           divas_poll,
+  ioctl:          divas_ioctl,
+  open:           divas_open,
+  release:        divas_close,
+};
+
+int
+create_divas_proc(void)
+{
+  divas_proc_entry = create_proc_entry(divas_proc_name,
+                     S_IFREG | S_IRUGO , proc_net_isdn_eicon);
+  if (!divas_proc_entry)
+    return(0);
+
+  divas_proc_entry->proc_fops = &divas_fops;   
+  divas_proc_entry->owner = THIS_MODULE;
+
+  return(1);
+}
+
+void
+remove_divas_proc(void)
+{
+  if (divas_proc_entry) {
+    remove_proc_entry(divas_proc_name, proc_net_isdn_eicon);
+    divas_proc_entry = NULL;
+  }
+}
+
+/*
+** write group_optimization 
+*/
+static int
+write_grp_opt(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t *)data;
+  PISDN_ADAPTER IoAdapter = IoAdapters[a->controller-1];
+  
+  if ((count == 1) || (count == 2)) {
+    switch(buffer[0]) {
+        case '0':
+          IoAdapter->capi_cfg.cfg_1 &= ~DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON;
+          break;
+        case '1':
+          IoAdapter->capi_cfg.cfg_1 |= DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON;
+          break;
+        default:
+          return(-EINVAL);
+    }
+    return(count);
+  }
+  return(-EINVAL);
+}
+
+/*
+** write dynamic_l1_down
+*/
+static int
+write_d_l1_down(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t *)data;
+  PISDN_ADAPTER IoAdapter = IoAdapters[a->controller-1];
+
+  if ((count == 1) || (count == 2)) {
+    switch(buffer[0]) {
+        case '0':
+          IoAdapter->capi_cfg.cfg_1 &= ~DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON;
+          break;
+        case '1':
+          IoAdapter->capi_cfg.cfg_1 |= DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON;
+          break;
+        default:
+          return(-EINVAL);
+    }
+    return(count);
+  }
+  return(-EINVAL);
+}
+
+
+/*
+** read dynamic_l1_down 
+*/
+static int
+read_d_l1_down(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+  int len = 0;
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t *)data;
+  PISDN_ADAPTER IoAdapter = IoAdapters[a->controller-1];
+
+  len += sprintf(page+len, "%s\n",
+         (IoAdapter->capi_cfg.cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ?
+          "1" : "0");
+
+  if (off + count >= len)
+    *eof = 1;
+  if (len < off)
+    return 0;
+  *start = page + off;
+  return((count < len-off) ? count : len-off);
+}
+
+/*
+** read group_optimization
+*/
+static int
+read_grp_opt(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+  int len = 0;
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t *)data;
+  PISDN_ADAPTER IoAdapter = IoAdapters[a->controller-1];
+
+  len += sprintf(page+len, "%s\n",
+         (IoAdapter->capi_cfg.cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) ?
+          "1" : "0");
+
+  if (off + count >= len)
+    *eof = 1;
+  if (len < off)
+    return 0;
+  *start = page + off;
+  return((count < len-off) ? count : len-off);
+}
+
+/*
+** info write
+*/
+static int
+info_write(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t *)data;
+  PISDN_ADAPTER IoAdapter = IoAdapters[a->controller-1];
+
+  /* this is for test purposes only */
+  if ((count > 4) && (!memcmp(buffer, "trap", 4))) {
+    (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum);
+    return(count);
+  }
+  return(-EINVAL);
+}
+
+/*
+** info read
+*/
+static int
+info_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+  int i = 0;
+  int len = 0;
+  char *p;
+  char tmpser[16];
+  diva_os_xdi_adapter_t* a = (diva_os_xdi_adapter_t*)data;
+  PISDN_ADAPTER IoAdapter = IoAdapters[a->controller-1];
+
+  len += sprintf(page+len, "Name        : %s\n", IoAdapter->Properties.Name);
+  len += sprintf(page+len, "DSP state   : %08x\n", a->dsp_mask);
+  len += sprintf(page+len, "Channels    : %02d\n",
+                                          IoAdapter->Properties.Channels);
+  len += sprintf(page+len, "E. max/used : %03d/%03d\n",
+                                          IoAdapter->e_max, IoAdapter->e_count);
+  diva_get_vserial_number(IoAdapter, tmpser);
+  len += sprintf(page+len, "Serial      : %s\n", tmpser);
+  len += sprintf(page+len, "IRQ         : %d\n", IoAdapter->irq_info.irq_nr);
+  len += sprintf(page+len, "CardIndex   : %d\n", a->CardIndex);
+  len += sprintf(page+len, "CardOrdinal : %d\n", a->CardOrdinal);
+  len += sprintf(page+len, "Controller  : %d\n", a->controller);
+  len += sprintf(page+len, "Bus-Type    : %s\n",
+      (a->Bus == DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA":"PCI");
+  len += sprintf(page+len, "Port-Name   : %s\n", a->port_name);
+  if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) {
+    len += sprintf(page+len, "PCI-bus     : %d\n", a->resources.pci.bus);
+    len += sprintf(page+len, "PCI-func    : %d\n", a->resources.pci.func);
+    for(i = 0; i < 8; i++) {
+      if(a->resources.pci.bar[i]) {
+        len += sprintf(page+len, "Mem / I/O %d : 0x%x / mapped : 0x%lx",
+          i, a->resources.pci.bar[i], (unsigned long)a->resources.pci.addr[i]);
+        if(a->resources.pci.length[i]) {
+          len += sprintf(page+len, " / length : %d",
+               a->resources.pci.length[i]);
+        }
+        len += sprintf(page+len, "\n");
+      }
+    }
+  }
+  if ((!a->xdi_adapter.port) &&
+      ((!a->xdi_adapter.ram) || (!a->xdi_adapter.reset) || (!a->xdi_adapter.cfg)))
+  {
+    if(!IoAdapter->irq_info.irq_nr) {
+      p = "slave";
+    } else {
+      p = "out of service";
+    }
+  } else if (a->xdi_adapter.trapped) {
+     p = "trapped";
+  } else if (a->xdi_adapter.Initialized) {
+     p = "active";
+  } else {
+     p = "ready";
+  }
+  len += sprintf(page+len, "State       : %s\n", p);
+
+  if (off + count >= len)
+    *eof = 1;
+  if (len < off)
+    return 0;
+  *start = page + off;
+  return((count < len-off) ? count : len-off);
+}
+
+/*
+** adapter proc init/de-init
+*/
+
+/* --------------------------------------------------------------------------
+    Create adapter directory and files in proc file system
+   -------------------------------------------------------------------------- */
+int create_adapter_proc (diva_os_xdi_adapter_t* a) {
+  struct proc_dir_entry *de, *pe;
+  char tmp[16];
+
+    sprintf(tmp, "%s%d", adapter_dir_name, a->controller);
+    if(!(de = create_proc_entry(tmp, S_IFDIR, proc_net_isdn_eicon)))
+          return(0);
+    a->proc_adapter_dir = (void *)de;
+
+    if(!(pe = create_proc_entry(info_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de)))
+          return(0);
+    a->proc_info = (void *)pe;
+    pe->write_proc = info_write;
+    pe->read_proc = info_read;
+    pe->data = a; 
+
+    if((pe = create_proc_entry(grp_opt_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de))) {
+      a->proc_grp_opt = (void *)pe;
+      pe->write_proc = write_grp_opt;
+      pe->read_proc = read_grp_opt;
+      pe->data = a; 
+    }
+    if((pe = create_proc_entry(d_l1_down_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de))) {
+      a->proc_d_l1_down = (void *)pe;
+      pe->write_proc = write_d_l1_down;
+      pe->read_proc = read_d_l1_down;
+      pe->data = a; 
+    }
+  
+    DBG_TRC(("proc entry %s created", tmp));
+
+    return(1);
+}
+
+/* --------------------------------------------------------------------------
+    Remove adapter directory and files in proc file system
+   -------------------------------------------------------------------------- */
+void remove_adapter_proc (diva_os_xdi_adapter_t* a) {
+  char tmp[16];
+
+    if(a->proc_adapter_dir) {
+      if(a->proc_d_l1_down) {
+      remove_proc_entry (d_l1_down_proc_name,
+                         (struct proc_dir_entry *)a->proc_adapter_dir);
+      }
+      if(a->proc_grp_opt) {
+      remove_proc_entry (grp_opt_proc_name,
+                         (struct proc_dir_entry *)a->proc_adapter_dir);
+      }
+      if(a->proc_info) {
+      remove_proc_entry (info_proc_name,
+                         (struct proc_dir_entry *)a->proc_adapter_dir);
+      }
+      sprintf(tmp, "%s%d", adapter_dir_name, a->controller);
+      remove_proc_entry(tmp, proc_net_isdn_eicon);
+      DBG_TRC(("proc entry %s%d removed", adapter_dir_name, a->controller));
+    }
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/divasync.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,481 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_SYNC__H  
+#define __DIVA_SYNC__H
+#define IDI_SYNC_REQ_REMOVE             0x00
+#define IDI_SYNC_REQ_GET_NAME           0x01
+#define IDI_SYNC_REQ_GET_SERIAL         0x02
+#define IDI_SYNC_REQ_SET_POSTCALL       0x03
+#define IDI_SYNC_REQ_GET_XLOG           0x04
+#define IDI_SYNC_REQ_GET_FEATURES       0x05
+/* Added for DIVA USB support */
+#define IDI_SYNC_REQ_USB_REGISTER       0x06
+#define IDI_SYNC_REQ_USB_RELEASE        0x07
+#define IDI_SYNC_REQ_USB_ADD_DEVICE     0x08
+#define IDI_SYNC_REQ_USB_START_DEVICE   0x09
+#define IDI_SYNC_REQ_USB_STOP_DEVICE    0x0A
+#define IDI_SYNC_REQ_USB_REMOVE_DEVICE  0x0B
+/* Added for Diva Server Monitor */
+#define IDI_SYNC_REQ_GET_CARDTYPE       0x0C
+#define IDI_SYNC_REQ_GET_DBG_XLOG       0x0D
+#define IDI_SYNC_REQ_GET_LINE_IDX   0x0E
+#define DIVA_USB
+#define DIVA_USB_REQ                    0xAC
+#define DIVA_USB_TEST                   0xAB
+#define DIVA_USB_ADD_ADAPTER            0xAC
+#define DIVA_USB_REMOVE_ADAPTER         0xAD
+/******************************************************************************/
+#define IDI_SYNC_REQ_SERIAL_HOOK        0x80
+#define IDI_SYNC_REQ_XCHANGE_STATUS     0x81
+#define IDI_SYNC_REQ_USB_HOOK           0x82
+#define IDI_SYNC_REQ_PORTDRV_HOOK       0x83
+#define IDI_SYNC_REQ_SLI           (0x84)   /*  SLI request from 3signal modem drivers */
+#define IDI_SYNC_REQ_RECONFIGURE        0x85
+#define IDI_SYNC_REQ_RESET              0x86
+#define IDI_SYNC_REQ_LOCK_85X                   0x88
+#define IDI_SYNC_REQ_GET_85X_EXT_PORT_TYPE      0xA0
+#define IDI_SYNC_REQ_DIPORT_GET_85X_TX_CTRL_FN  0x98
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES  0x92
+/*
+   To receive XDI features:
+   1. set 'buffer_length_in_bytes' to length of you buffer
+   2. set 'features' to pointer to your buffer
+   3. issue synchronous request to XDI
+   4. Check that feature 'DIVA_XDI_EXTENDED_FEATURES_VALID' is present
+      after call. This feature does indicate that your request
+      was processed and XDI does support this synchronous request
+   5. if on return bit 31 (0x80000000) in 'buffer_length_in_bytes' is
+      set then provided buffer was too small, and bits 30-0 does
+      contain necessary length of buffer.
+      in this case only features that do find place in the buffer
+      are indicated to caller
+*/
+typedef struct _diva_xdi_get_extended_xdi_features {
+  dword buffer_length_in_bytes;
+  byte  *features;
+} diva_xdi_get_extended_xdi_features_t;
+/*
+   features[0]
+  */
+#define DIVA_XDI_EXTENDED_FEATURES_VALID          0x01
+#define DIVA_XDI_EXTENDED_FEATURE_CMA             0x02
+#define DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR       0x04
+#define DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS       0x08
+#define DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC    0x10
+#define DIVA_XDI_EXTENDED_FEATURE_RX_DMA          0x20
+#define DIVA_XDI_EXTENDED_FEATURES_MAX_SZ    1
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR   0x93
+typedef struct _diva_xdi_get_adapter_sdram_bar {
+ dword bar;
+} diva_xdi_get_adapter_sdram_bar_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS   0x94
+/*
+  CAPI Parameters will be written in the caller's buffer
+  */
+typedef struct _diva_xdi_get_capi_parameters {
+  dword structure_length;
+  byte flag_dynamic_l1_down;
+  byte group_optimization_enabled;
+} diva_xdi_get_capi_parameters_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER   0x95
+/*
+  Get logical adapter number, as assigned by XDI
+  'controller' is starting with zero 'sub' controller number
+  in case of one adapter that supports multiple interfaces
+  'controller' is zero for Master adapter (and adapter that supports
+  only one interface)
+  */
+typedef struct _diva_xdi_get_logical_adapter_number {
+  dword logical_adapter_number;
+  dword controller;
+} diva_xdi_get_logical_adapter_number_s_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_UP1DM_OPERATION   0x96
+/******************************************************************************/
+#define IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION 0x97
+#define IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC     0x01
+#define IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE      0x02
+typedef struct _diva_xdi_dma_descriptor_operation {
+  int   operation;
+  int   descriptor_number;
+  void* descriptor_address;
+  dword descriptor_magic;
+} diva_xdi_dma_descriptor_operation_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY   0x01
+#define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY     0x02
+#define IDI_SYNC_REQ_DIDD_ADD_ADAPTER               0x03
+#define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER            0x04
+#define IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY        0x05
+typedef struct _diva_didd_adapter_notify {
+ dword handle; /* Notification handle */
+ void   * callback;
+ void   * context;
+} diva_didd_adapter_notify_t;
+typedef struct _diva_didd_add_adapter {
+ void   * descriptor;
+} diva_didd_add_adapter_t;
+typedef struct _diva_didd_remove_adapter {
+ IDI_CALL p_request;
+} diva_didd_remove_adapter_t;
+typedef struct _diva_didd_read_adapter_array {
+ void   * buffer;
+ dword length;
+} diva_didd_read_adapter_array_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_STREAM    0x91
+#define DIVA_XDI_SYNCHRONOUS_SERVICE   0x01
+#define DIVA_XDI_DMA_SERVICE           0x02
+#define DIVA_XDI_AUTO_SERVICE          0x03
+#define DIVA_ISTREAM_COMPLETE_NOTIFY   0
+#define DIVA_ISTREAM_COMPLETE_READ     1
+#define DIVA_ISTREAM_COMPLETE_WRITE    2
+typedef struct _diva_xdi_stream_interface {
+  unsigned char  Id;                 /* filled by XDI client */
+ unsigned char provided_service;    /* filled by XDI        */
+ unsigned char requested_service;   /* filled by XDI Client */
+ void* xdi_context;    /* filled by XDI     */
+ void* client_context;   /* filled by XDI client */
+ int (*write)(void* context,
+               int Id,
+               void* data,
+               int length,
+               int final,
+               byte usr1,
+               byte usr2);
+ int (*read)(void* context,
+              int Id,
+              void* data,
+              int max_length,
+              int* final,
+              byte* usr1,
+              byte* usr2);
+ int (*complete)(void* client_context,
+         int Id,
+          int what,
+         void* data,
+         int length,
+         int* final);
+} diva_xdi_stream_interface_t;
+/******************************************************************************/
+/*
+ * IDI_SYNC_REQ_SERIAL_HOOK - special interface for the DIVA Mobile card
+ */
+typedef struct
+{ unsigned char LineState;         /* Modem line state (STATUS_R) */
+#define SERIAL_GSM_CELL 0x01   /* GSM or CELL cable attached  */
+ unsigned char CardState;          /* PCMCIA card state (0 = down) */
+ unsigned char IsdnState;          /* ISDN layer 1 state (0 = down)*/
+ unsigned char HookState;          /* current logical hook state */
+#define SERIAL_ON_HOOK 0x02   /* set in DIVA CTRL_R register */
+} SERIAL_STATE;
+typedef int (  * SERIAL_INT_CB) (void *Context) ;
+typedef int (  * SERIAL_DPC_CB) (void *Context) ;
+typedef unsigned char (  * SERIAL_I_SYNC) (void *Context) ;
+typedef struct
+{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+ unsigned char Req;             /* request (must be always 0) */
+ unsigned char Rc;              /* return code (is the request) */
+ unsigned char Function;           /* private function code  */
+#define SERIAL_HOOK_ATTACH 0x81
+#define SERIAL_HOOK_STATUS 0x82
+#define SERIAL_HOOK_I_SYNC 0x83
+#define SERIAL_HOOK_NOECHO 0x84
+#define SERIAL_HOOK_RING 0x85
+#define SERIAL_HOOK_DETACH 0x8f
+ unsigned char Flags;           /* function refinements   */
+ /* parameters passed by the the ATTACH request      */
+ SERIAL_INT_CB InterruptHandler; /* called on each interrupt  */
+ SERIAL_DPC_CB DeferredHandler; /* called on hook state changes */
+ void   *HandlerContext; /* context for both handlers */
+ /* return values for both the ATTACH and the STATUS request   */
+ unsigned long IoBase;    /* IO port assigned to UART  */
+ SERIAL_STATE State;
+ /* parameters and return values for the I_SYNC function    */
+ SERIAL_I_SYNC SyncFunction;  /* to be called synchronized */
+ void   *SyncContext;  /* context for this function */
+ unsigned char SyncResult;   /* return value of function  */
+} SERIAL_HOOK;
+/*
+ * IDI_SYNC_REQ_XCHANGE_STATUS - exchange the status between IDI and WMP
+ * IDI_SYNC_REQ_RECONFIGURE - reconfiguration of IDI from WMP
+ */
+typedef struct
+{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+ unsigned char Req;             /* request (must be always 0) */
+ unsigned char Rc;              /* return code (is the request) */
+#define DRIVER_STATUS_BOOT  0xA1
+#define DRIVER_STATUS_INIT_DEV 0xA2
+#define DRIVER_STATUS_RUNNING 0xA3
+#define DRIVER_STATUS_SHUTDOWN 0xAF
+#define DRIVER_STATUS_TRAPPED 0xAE
+ unsigned char wmpStatus;          /* exported by WMP              */
+ unsigned char idiStatus;   /* exported by IDI              */
+ unsigned long wizProto ;   /* from WMP registry to IDI     */
+ /* the cardtype value is defined by cardtype.h */
+ unsigned long cardType ;   /* from IDI registry to WMP     */
+ unsigned long nt2 ;    /* from IDI registry to WMP     */
+ unsigned long permanent ;   /* from IDI registry to WMP     */
+ unsigned long stableL2 ;   /* from IDI registry to WMP     */
+ unsigned long tei ;    /* from IDI registry to WMP     */
+#define CRC4_MASK   0x00000003
+#define L1_TRISTATE_MASK 0x00000004
+#define WATCHDOG_MASK  0x00000008
+#define NO_ORDER_CHECK_MASK 0x00000010
+#define LOW_CHANNEL_MASK 0x00000020
+#define NO_HSCX30_MASK  0x00000040
+#define MODE_MASK   0x00000080
+#define SET_BOARD   0x00001000
+#define SET_CRC4   0x00030000
+#define SET_L1_TRISTATE  0x00040000
+#define SET_WATCHDOG  0x00080000
+#define SET_NO_ORDER_CHECK 0x00100000
+#define SET_LOW_CHANNEL  0x00200000
+#define SET_NO_HSCX30  0x00400000
+#define SET_MODE   0x00800000
+#define SET_PROTO   0x02000000
+#define SET_CARDTYPE  0x04000000
+#define SET_NT2    0x08000000
+#define SET_PERMANENT  0x10000000
+#define SET_STABLEL2  0x20000000
+#define SET_TEI    0x40000000
+#define SET_NUMBERLEN  0x80000000
+ unsigned long Flag ;  /* |31-Type-16|15-Mask-0| */
+ unsigned long NumberLen ; /* reconfiguration: union is empty */
+ union {
+  struct {    /* possible reconfiguration, but ... ; SET_BOARD */
+   unsigned long SerialNumber ;
+   char     *pCardname ; /* di_defs.h: BOARD_NAME_LENGTH */
+  } board ;
+  struct {      /* reset: need resources */
+   void * pRawResources ;
+   void * pXlatResources ;
+  } res ;
+  struct { /* reconfiguration: wizProto == PROTTYPE_RBSCAS */
+#define GLARE_RESOLVE_MASK 0x00000001
+#define DID_MASK   0x00000002
+#define BEARER_CAP_MASK  0x0000000c
+#define SET_GLARE_RESOLVE 0x00010000
+#define SET_DID    0x00020000
+#define SET_BEARER_CAP  0x000c0000
+   unsigned long Flag ;  /* |31-Type-16|15-VALUE-0| */
+   unsigned short DigitTimeout ;
+   unsigned short AnswerDelay ;
+  } rbs ;
+  struct { /* reconfiguration: wizProto == PROTTYPE_QSIG */
+#define CALL_REF_LENGTH1_MASK 0x00000001
+#define BRI_CHANNEL_ID_MASK  0x00000002
+#define SET_CALL_REF_LENGTH  0x00010000
+#define SET_BRI_CHANNEL_ID  0x00020000
+   unsigned long Flag ;  /* |31-Type-16|15-VALUE-0| */
+  } qsig ;
+  struct { /* reconfiguration: NumberLen != 0 */
+#define SET_SPID1   0x00010000
+#define SET_NUMBER1   0x00020000
+#define SET_SUBADDRESS1  0x00040000
+#define SET_SPID2   0x00100000
+#define SET_NUMBER2   0x00200000
+#define SET_SUBADDRESS2  0x00400000
+#define MASK_SET   0xffff0000
+   unsigned long Flag ;   /* |31-Type-16|15-Channel-0| */
+   unsigned char *pBuffer ; /* number value */
+  } isdnNo ;
+ }
+parms
+;
+} isdnProps ;
+/*
+ * IDI_SYNC_REQ_PORTDRV_HOOK - signal plug/unplug (Award Cardware only)
+ */
+typedef void (  * PORTDRV_HOOK_CB) (void *Context, int Plug) ;
+typedef struct
+{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+ unsigned char Req;             /* request (must be always 0) */
+ unsigned char Rc;              /* return code (is the request) */
+ unsigned char Function;           /* private function code  */
+ unsigned char Flags;           /* function refinements   */
+ PORTDRV_HOOK_CB Callback;   /* to be called on plug/unplug */
+ void   *Context;   /* context for callback   */
+ unsigned long Info;    /* more info if needed   */
+} PORTDRV_HOOK ;
+/*  Codes for the 'Rc' element in structure below. */
+#define SLI_INSTALL     (0xA1)
+#define SLI_UNINSTALL   (0xA2)
+typedef int ( * SLIENTRYPOINT)(void* p3SignalAPI, void* pContext);
+typedef struct
+{   /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+    unsigned char   Req;                /* request (must be always 0)   */
+    unsigned char   Rc;                 /* return code (is the request) */
+    unsigned char   Function;           /* private function code        */
+    unsigned char   Flags;              /* function refinements         */
+    SLIENTRYPOINT   Callback;           /* to be called on plug/unplug  */
+    void            *Context;           /* context for callback         */
+    unsigned long   Info;               /* more info if needed          */
+} SLIENTRYPOINT_REQ ;
+/******************************************************************************/
+/*
+ *  Definitions for DIVA USB
+ */
+typedef int  (  * USB_SEND_REQ) (unsigned char PipeIndex, unsigned char Type,void *Data, int sizeData);
+typedef int  (  * USB_START_DEV) (void *Adapter, void *Ipac) ;
+/* called from WDM */
+typedef void (  * USB_RECV_NOTIFY) (void *Ipac, void *msg) ;
+typedef void (  * USB_XMIT_NOTIFY) (void *Ipac, unsigned char PipeIndex) ;
+/******************************************************************************/
+/*
+ * Parameter description for synchronous requests.
+ *
+ * Sorry, must repeat some parts of di_defs.h here because
+ * they are not defined for all operating environments
+ */
+typedef union
+{ ENTITY Entity;
+ struct
+ { /* 'Req' and 'Rc' are at the same place as in the ENTITY struct */
+  unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (is the request) */
+ }   Request;
+ struct
+ { unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (0x01)   */
+  unsigned char   name[BOARD_NAME_LENGTH];
+ }   GetName;
+ struct
+ { unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (0x02)   */
+  unsigned long   serial; /* serial number    */
+ }   GetSerial;
+ struct
+ { unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (0x02)   */
+  unsigned long   lineIdx;/* line, 0 if card has only one */
+ }   GetLineIdx;
+ struct
+ { unsigned char  Req;     /* request (must be always 0) */
+  unsigned char  Rc;      /* return code (0x02)   */
+  unsigned long  cardtype;/* card type        */
+ }   GetCardType;
+ struct
+ { unsigned short command;/* command = 0x0300 */
+  unsigned short dummy; /* not used */
+  IDI_CALL       callback;/* routine to call back */
+  ENTITY      *contxt; /* ptr to entity to use */
+ }   PostCall;
+ struct
+ { unsigned char  Req;  /* request (must be always 0) */
+  unsigned char  Rc;   /* return code (0x04)   */
+  unsigned char  pcm[1]; /* buffer (a pc_maint struct) */
+ }   GetXlog;
+ struct
+ { unsigned char  Req;  /* request (must be always 0) */
+  unsigned char  Rc;   /* return code (0x05)   */
+  unsigned short features;/* feature defines see below */
+ }   GetFeatures;
+ SERIAL_HOOK  SerialHook;
+/* Added for DIVA USB */
+ struct
+ { unsigned char   Req;
+  unsigned char   Rc;
+  USB_SEND_REQ    UsbSendRequest; /* function in Diva Usb WDM driver in usb_os.c, */
+                                        /* called from usb_drv.c to send a message to our device */
+                                        /* eg UsbSendRequest (USB_PIPE_SIGNAL, USB_IPAC_START, 0, 0) ; */
+  USB_RECV_NOTIFY usb_recv;       /* called from usb_os.c to pass a received message and ptr to IPAC */
+                                        /* on to usb_drv.c by a call to usb_recv(). */
+  USB_XMIT_NOTIFY usb_xmit;       /* called from usb_os.c in DivaUSB.sys WDM to indicate a completed transmit */
+                                        /* to usb_drv.c by a call to usb_xmit(). */
+  USB_START_DEV   UsbStartDevice; /* Start the USB Device, in usb_os.c */
+  IDI_CALL        callback;       /* routine to call back */
+  ENTITY          *contxt;     /* ptr to entity to use */
+  void            ** ipac_ptr;    /* pointer to struct IPAC in VxD */
+ } Usb_Msg_old;
+/* message used by WDM and VXD to pass pointers of function and IPAC* */
+ struct
+ { unsigned char Req;
+  unsigned char Rc;
+        USB_SEND_REQ    pUsbSendRequest;/* function in Diva Usb WDM driver in usb_os.c, */
+                                        /* called from usb_drv.c to send a message to our device */
+                                        /* eg UsbSendRequest (USB_PIPE_SIGNAL, USB_IPAC_START, 0, 0) ; */
+        USB_RECV_NOTIFY p_usb_recv;     /* called from usb_os.c to pass a received message and ptr to IPAC */
+                                        /* on to usb_drv.c by a call to usb_recv(). */
+        USB_XMIT_NOTIFY p_usb_xmit;     /* called from usb_os.c in DivaUSB.sys WDM to indicate a completed transmit */
+                                        /* to usb_drv.c by a call to usb_xmit().*/
+  void            *ipac_ptr;      /* &Diva.ipac pointer to struct IPAC in VxD */
+ } Usb_Msg;
+ PORTDRV_HOOK PortdrvHook;
+    SLIENTRYPOINT_REQ   sliEntryPointReq;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_stream_interface_t info;
+  } xdi_stream_info;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_get_extended_xdi_features_t info;
+  } xdi_extended_features;
+ struct {
+    unsigned char Req;
+    unsigned char Rc;
+  diva_xdi_get_adapter_sdram_bar_t info;
+ } xdi_sdram_bar;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_get_capi_parameters_t info;
+  } xdi_capi_prms;
+ struct {
+  ENTITY           e;
+  diva_didd_adapter_notify_t info;
+ } didd_notify;
+ struct {
+  ENTITY           e;
+  diva_didd_add_adapter_t   info;
+ } didd_add_adapter;
+ struct {
+  ENTITY           e;
+  diva_didd_remove_adapter_t info;
+ } didd_remove_adapter;
+ struct {
+  ENTITY             e;
+  diva_didd_read_adapter_array_t info;
+ } didd_read_adapter_array;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_get_logical_adapter_number_s_t info;
+  } xdi_logical_adapter_number;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_dma_descriptor_operation_t info;
+  } xdi_dma_descriptor_operation;
+} IDI_SYNC_REQ;
+/******************************************************************************/
+#endif /* __DIVA_SYNC__H */  
diff -Nru a/drivers/isdn/hardware/eicon/dlist.c b/drivers/isdn/hardware/eicon/dlist.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dlist.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,108 @@
+/* $Id: dlist.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#include "platform.h"
+#include "dlist.h"
+
+/*
+**  Initialize linked list
+*/
+
+void
+diva_q_init (diva_entity_queue_t* q)
+{
+  memset (q, 0x00, sizeof(*q));
+}
+
+/*
+**  Remove element from linked list
+*/
+void
+diva_q_remove (diva_entity_queue_t* q, diva_entity_link_t* what)
+{
+  if(!what->prev) {
+    if ((q->head = what->next)) {
+      q->head->prev = 0;
+    } else {
+      q->tail = 0;
+    }
+  } else if (!what->next) {
+    q->tail = what->prev;
+    q->tail->next = 0;
+  } else {
+    what->prev->next = what->next;
+    what->next->prev = what->prev;
+  }
+  what->prev = what->next = 0;
+}
+
+/*
+**  Add element to the tail of linked list
+*/
+void
+diva_q_add_tail (diva_entity_queue_t* q, diva_entity_link_t* what)
+{
+  what->next = 0;
+  if (!q->head) {
+    what->prev = 0;
+    q->head = q->tail = what;
+  } else {
+    what->prev = q->tail;
+    q->tail->next = what;
+    q->tail = what;
+  }
+}
+
+diva_entity_link_t*
+diva_q_find (const diva_entity_queue_t* q, const void* what,
+             diva_q_cmp_fn_t cmp_fn)
+{
+  diva_entity_link_t* diva_current = q->head;
+
+  while (diva_current) {
+    if (!(*cmp_fn)(what, diva_current)) {
+      break;
+    }
+    diva_current = diva_current->next;
+  }
+
+  return (diva_current);
+}
+
+diva_entity_link_t*
+diva_q_get_head (diva_entity_queue_t* q)
+{
+  return (q->head);
+}
+
+diva_entity_link_t*
+diva_q_get_tail (diva_entity_queue_t* q)
+{
+  return (q->tail);
+}
+
+diva_entity_link_t*
+diva_q_get_next	(diva_entity_link_t* what)
+{
+  return ((what) ? what->next : 0);
+}
+
+diva_entity_link_t*
+diva_q_get_prev	(diva_entity_link_t* what)
+{
+  return ((what) ? what->prev : 0);
+}
+
+int
+diva_q_get_nr_of_entries (const diva_entity_queue_t* q)
+{
+  int i = 0;
+  const diva_entity_link_t* diva_current = q->head;
+
+  while (diva_current) {
+    i++;
+    diva_current = diva_current->next;
+  }
+
+  return (i);
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/dlist.h b/drivers/isdn/hardware/eicon/dlist.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dlist.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,32 @@
+/* $Id: dlist.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#ifndef __DIVA_LINK_H__
+#define __DIVA_LINK_H__
+
+struct _diva_entity_link;
+typedef struct _diva_entity_link {
+	struct _diva_entity_link* prev;
+	struct _diva_entity_link* next;
+} diva_entity_link_t;
+
+typedef struct _diva_entity_queue {
+	diva_entity_link_t* head;
+	diva_entity_link_t* tail;
+} diva_entity_queue_t;
+
+typedef int (*diva_q_cmp_fn_t)(const void* what,
+                               const diva_entity_link_t*);
+
+void diva_q_remove   (diva_entity_queue_t* q, diva_entity_link_t* what);
+void diva_q_add_tail (diva_entity_queue_t* q, diva_entity_link_t* what);
+diva_entity_link_t* diva_q_find (const diva_entity_queue_t* q,
+                                 const void* what, diva_q_cmp_fn_t cmp_fn);
+
+diva_entity_link_t* diva_q_get_head	(diva_entity_queue_t* q);
+diva_entity_link_t* diva_q_get_tail	(diva_entity_queue_t* q);
+diva_entity_link_t* diva_q_get_next	(diva_entity_link_t* what);
+diva_entity_link_t* diva_q_get_prev	(diva_entity_link_t* what);
+int diva_q_get_nr_of_entries (const diva_entity_queue_t* q);
+void diva_q_init (diva_entity_queue_t* q);
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/dqueue.c b/drivers/isdn/hardware/eicon/dqueue.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dqueue.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,117 @@
+/* $Id: dqueue.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * User Mode IDI Interface
+ *
+ * Copyright 2000,2001 by Armin Schindler (mac@melware.de)
+ * Copyright 2000,2001 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "dqueue.h"
+
+int
+diva_data_q_init(diva_um_idi_data_queue_t* q,
+                 int max_length,
+                 int max_segments)
+{
+  int i;
+
+  q->max_length	= max_length;
+  q->segments = max_segments;
+	
+  for (i = 0; i < q->segments; i++) {
+    q->data[i] = 0;
+    q->length[i]  = 0;
+  }
+  q->read = q->write = q->count = q->segment_pending = 0;
+
+  for (i = 0; i < q->segments; i++) {
+    if (!(q->data[i] = diva_os_malloc (0, q->max_length))) {
+      diva_data_q_finit (q);
+      return (-1);
+    }
+  }
+
+  return (0);
+}
+
+int
+diva_data_q_finit(diva_um_idi_data_queue_t* q)
+{
+  int i;
+
+  for (i = 0; i < q->segments; i++) {
+    if (q->data[i]) {
+      diva_os_free (0, q->data[i]);
+    }
+    q->data[i] = 0;
+    q->length[i] = 0;
+  }
+  q->read = q->write = q->count = q->segment_pending = 0;
+
+  return (0);
+}
+
+int
+diva_data_q_get_max_length(const diva_um_idi_data_queue_t* q)
+{
+  return (q->max_length);
+}
+
+void*
+diva_data_q_get_segment4write(diva_um_idi_data_queue_t* q)
+{
+  if ((!q->segment_pending) && (q->count < q->segments)) {
+    q->segment_pending = 1;
+    return (q->data[q->write]);
+  }
+
+  return (0);
+}
+
+void
+diva_data_q_ack_segment4write(diva_um_idi_data_queue_t* q, int length)
+{
+  if (q->segment_pending) {
+    q->length[q->write] = length;
+    q->count++;
+    q->write++;
+    if (q->write >= q->segments) {
+      q->write = 0;
+    }
+    q->segment_pending = 0;
+  }
+}
+
+const void*
+diva_data_q_get_segment4read(const diva_um_idi_data_queue_t* q)
+{
+  if (q->count) {
+    return (q->data[q->read]);
+  }
+  return (0);
+}
+
+int
+diva_data_q_get_segment_length(const diva_um_idi_data_queue_t* q)
+{
+  return (q->length[q->read]);
+}
+
+void
+diva_data_q_ack_segment4read(diva_um_idi_data_queue_t* q)
+{
+  if (q->count) {
+    q->length[q->read] = 0;
+    q->count--;
+    q->read++;
+    if (q->read >= q->segments) {
+      q->read = 0;
+    }
+  }
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/dqueue.h b/drivers/isdn/hardware/eicon/dqueue.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dqueue.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,31 @@
+/* $Id: dqueue.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#ifndef _DIVA_USER_MODE_IDI_DATA_QUEUE_H__
+#define _DIVA_USER_MODE_IDI_DATA_QUEUE_H__
+
+#define DIVA_UM_IDI_MAX_MSGS 64 
+
+typedef struct _diva_um_idi_data_queue {
+	int		segments;
+	int		max_length;
+	int		read;
+	int		write;
+	int		count;
+	int		segment_pending;
+	void*	data[DIVA_UM_IDI_MAX_MSGS];
+	int		length[DIVA_UM_IDI_MAX_MSGS];
+} diva_um_idi_data_queue_t;
+
+int diva_data_q_init(diva_um_idi_data_queue_t* q,
+                      int max_length,
+                      int max_segments);
+int diva_data_q_finit(diva_um_idi_data_queue_t* q);
+int diva_data_q_get_max_length (const diva_um_idi_data_queue_t* q);
+void* diva_data_q_get_segment4write (diva_um_idi_data_queue_t* q);
+void diva_data_q_ack_segment4write (diva_um_idi_data_queue_t* q, int length);
+const void* diva_data_q_get_segment4read (const diva_um_idi_data_queue_t* q);
+int diva_data_q_get_segment_length (const diva_um_idi_data_queue_t* q);
+void diva_data_q_ack_segment4read (diva_um_idi_data_queue_t* q);
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/dsp_defs.h b/drivers/isdn/hardware/eicon/dsp_defs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dsp_defs.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,304 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef DSP_DEFS_H_  
+#define DSP_DEFS_H_
+#include "dspdids.h"
+/*---------------------------------------------------------------------------*/
+#define dsp_download_reserve_space(fp,length)
+/*****************************************************************************/
+/*
+ * OS file access abstraction layer
+ *
+ * I/O functions returns -1 on error, 0 on EOF
+ */
+#define OS_SEEK_SET 0
+#define OS_SEEK_CUR 1
+#define OS_SEEK_END 2
+struct _OsFileHandle_;
+typedef long (  * OsFileIo)  (struct _OsFileHandle_    *handle,
+                                void                     *buffer,
+                                long                       size) ;
+typedef long (  * OsFileSeek)(struct _OsFileHandle_    *handle,
+                                long                       position,
+                                int                        mode) ;
+typedef long (  * OsCardLoad)(struct _OsFileHandle_    *handle,
+                                long                       length,
+                                void                         *   *addr) ;
+typedef struct _OsFileHandle_
+{ void       *sysFileDesc ;
+ unsigned long sysFileSize ;
+ OsFileIo      sysFileRead ;
+ OsFileSeek    sysFileSeek ;
+ void       *sysLoadDesc ;
+ OsCardLoad    sysCardLoad ;
+} OsFileHandle ;
+extern OsFileHandle *OsOpenFile (char *path_name) ;
+extern void          OsCloseFile (OsFileHandle *fp) ;
+/*****************************************************************************/
+#define DSP_TELINDUS_FILE "dspdload.bin"
+/* special DSP file for BRI cards for Qsig and CornetN because of missing memory */
+#define DSP_QSIG_TELINDUS_FILE "dspdqsig.bin"
+#define DSP_MDM_TELINDUS_FILE "dspdvmdm.bin"
+#define DSP_FAX_TELINDUS_FILE "dspdvfax.bin"
+#define DSP_DIRECTORY_ENTRIES 64
+#define DSP_MEMORY_TYPE_EXTERNAL_DM         0
+#define DSP_MEMORY_TYPE_EXTERNAL_PM         1
+#define DSP_MEMORY_TYPE_INTERNAL_DM         2
+#define DSP_MEMORY_TYPE_INTERNAL_PM         3
+#define DSP_DOWNLOAD_FLAG_BOOTABLE          0x0001
+#define DSP_DOWNLOAD_FLAG_2181              0x0002
+#define DSP_DOWNLOAD_FLAG_TIMECRITICAL      0x0004
+#define DSP_DOWNLOAD_FLAG_COMPAND           0x0008
+#define DSP_MEMORY_BLOCK_COUNT              16
+#define DSP_SEGMENT_PM_FLAG                 0x0001
+#define DSP_SEGMENT_SHARED_FLAG             0x0002
+#define DSP_SEGMENT_EXTERNAL_DM             DSP_MEMORY_TYPE_EXTERNAL_DM
+#define DSP_SEGMENT_EXTERNAL_PM             DSP_MEMORY_TYPE_EXTERNAL_PM
+#define DSP_SEGMENT_INTERNAL_DM             DSP_MEMORY_TYPE_INTERNAL_DM
+#define DSP_SEGMENT_INTERNAL_PM             DSP_MEMORY_TYPE_INTERNAL_PM
+#define DSP_SEGMENT_FIRST_RELOCATABLE       4
+#define DSP_DATA_BLOCK_PM_FLAG              0x0001
+#define DSP_DATA_BLOCK_DWORD_FLAG           0x0002
+#define DSP_DATA_BLOCK_RESOLVE_FLAG         0x0004
+#define DSP_RELOC_NONE                      0x00
+#define DSP_RELOC_SEGMENT_MASK              0x3f
+#define DSP_RELOC_TYPE_MASK                 0xc0
+#define DSP_RELOC_TYPE_0                    0x00  /* relocation of address in DM word / high part of PM word */
+#define DSP_RELOC_TYPE_1                    0x40  /* relocation of address in low part of PM data word */
+#define DSP_RELOC_TYPE_2                    0x80  /* relocation of address in standard command */
+#define DSP_RELOC_TYPE_3                    0xc0  /* relocation of address in call/jump on flag in */
+#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_COMBIFILE_FORMAT_VERSION_BCD    0x0100
+#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_FILE_FORMAT_VERSION_BCD         0x0100
+typedef struct tag_dsp_combifile_header
+{
+  char                  format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  header_size;
+  word                  combifile_description_size;
+  word                  directory_entries;
+  word                  directory_size;
+  word                  download_count;
+  word                  usage_mask_size;
+} t_dsp_combifile_header;
+typedef struct tag_dsp_combifile_directory_entry
+{
+  word                  card_type_number;
+  word                  file_set_number;
+} t_dsp_combifile_directory_entry;
+typedef struct tag_dsp_file_header
+{
+  char                  format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  header_size;
+  word                  download_description_size;
+  word                  memory_block_table_size;
+  word                  memory_block_count;
+  word                  segment_table_size;
+  word                  segment_count;
+  word                  symbol_table_size;
+  word                  symbol_count;
+  word                  total_data_size_dm;
+  word                  data_block_count_dm;
+  word                  total_data_size_pm;
+  word                  data_block_count_pm;
+} t_dsp_file_header;
+typedef struct tag_dsp_memory_block_desc
+{
+  word                  alias_memory_block;
+  word                  memory_type;
+  word                  address;
+  word                  size;             /* DSP words */
+} t_dsp_memory_block_desc;
+typedef struct tag_dsp_segment_desc
+{
+  word                  memory_block;
+  word                  attributes;
+  word                  base;
+  word                  size;
+  word                  alignment;        /* ==0 -> no other legal start address than base */
+} t_dsp_segment_desc;
+typedef struct tag_dsp_symbol_desc
+{
+  word                  symbol_id;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_symbol_desc;
+typedef struct tag_dsp_data_block_header
+{
+  word                  attributes;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_data_block_header;
+typedef struct tag_dsp_download_desc
+{
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  excess_header_size;
+  word                  memory_block_count;
+  word                  segment_count;
+  word                  symbol_count;
+  word                  data_block_count_dm;
+  word                  data_block_count_pm;
+  byte   *            p_excess_header_data;
+  char   *            p_download_description;
+  t_dsp_memory_block_desc   *p_memory_block_table;
+  t_dsp_segment_desc   *p_segment_table;
+  t_dsp_symbol_desc   *p_symbol_table;
+  word   *            p_data_blocks_dm;
+  word   *            p_data_blocks_pm;
+} t_dsp_desc;
+typedef struct tag_dsp_portable_download_desc /* be sure to keep native alignment for MAESTRA's */
+{
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  excess_header_size;
+  word                  memory_block_count;
+  word                  segment_count;
+  word                  symbol_count;
+  word                  data_block_count_dm;
+  word                  data_block_count_pm;
+  dword                 p_excess_header_data;
+  dword                 p_download_description;
+  dword                 p_memory_block_table;
+  dword                 p_segment_table;
+  dword                 p_symbol_table;
+  dword                 p_data_blocks_dm;
+  dword                 p_data_blocks_pm;
+} t_dsp_portable_desc;
+#define DSP_DOWNLOAD_INDEX_KERNEL               0
+#define DSP30TX_DOWNLOAD_INDEX_KERNEL           1
+#define DSP30RX_DOWNLOAD_INDEX_KERNEL           2
+#define DSP_MAX_DOWNLOAD_COUNT                  64
+#define DSP_DOWNLOAD_MAX_SEGMENTS         16
+#define DSP_UDATA_REQUEST_RECONFIGURE     0
+/*
+parameters:
+  <word> reconfigure delay (in 8kHz samples)
+  <word> reconfigure code
+  <byte> reconfigure hdlc preamble flags
+*/
+#define DSP_RECONFIGURE_TX_FLAG           0x8000
+#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG  0x4000
+#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
+#define DSP_RECONFIGURE_HDLC_FLAG         0x1000
+#define DSP_RECONFIGURE_SYNC_FLAG         0x0800
+#define DSP_RECONFIGURE_PROTOCOL_MASK     0x00ff
+#define DSP_RECONFIGURE_IDLE              0
+#define DSP_RECONFIGURE_V25               1
+#define DSP_RECONFIGURE_V21_CH2           2
+#define DSP_RECONFIGURE_V27_2400          3
+#define DSP_RECONFIGURE_V27_4800          4
+#define DSP_RECONFIGURE_V29_7200          5
+#define DSP_RECONFIGURE_V29_9600          6
+#define DSP_RECONFIGURE_V33_12000         7
+#define DSP_RECONFIGURE_V33_14400         8
+#define DSP_RECONFIGURE_V17_7200          9
+#define DSP_RECONFIGURE_V17_9600          10
+#define DSP_RECONFIGURE_V17_12000         11
+#define DSP_RECONFIGURE_V17_14400         12
+/*
+data indications if transparent framer
+  <byte> data 0
+  <byte> data 1
+  ...
+data indications if HDLC framer
+  <byte> data 0
+  <byte> data 1
+  ...
+  <byte> CRC 0
+  <byte> CRC 1
+  <byte> preamble flags
+*/
+#define DSP_UDATA_INDICATION_SYNC         0
+/*
+returns:
+  <word> time of sync (sampled from counter at 8kHz)
+*/
+#define DSP_UDATA_INDICATION_DCD_OFF      1
+/*
+returns:
+  <word> time of DCD off (sampled from counter at 8kHz)
+*/
+#define DSP_UDATA_INDICATION_DCD_ON       2
+/*
+returns:
+  <word> time of DCD on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+#define DSP_UDATA_INDICATION_CTS_OFF      3
+/*
+returns:
+  <word> time of CTS off (sampled from counter at 8kHz)
+*/
+#define DSP_UDATA_INDICATION_CTS_ON       4
+/*
+returns:
+  <word> time of CTS on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+#define DSP_CONNECTED_NORM_UNSPECIFIED      0
+#define DSP_CONNECTED_NORM_V21              1
+#define DSP_CONNECTED_NORM_V23              2
+#define DSP_CONNECTED_NORM_V22              3
+#define DSP_CONNECTED_NORM_V22_BIS          4
+#define DSP_CONNECTED_NORM_V32_BIS          5
+#define DSP_CONNECTED_NORM_V34              6
+#define DSP_CONNECTED_NORM_V8               7
+#define DSP_CONNECTED_NORM_BELL_212A        8
+#define DSP_CONNECTED_NORM_BELL_103         9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
+#define DSP_CONNECTED_NORM_TFAST            12
+#define DSP_CONNECTED_NORM_V21_CH2          13
+#define DSP_CONNECTED_NORM_V27_TER          14
+#define DSP_CONNECTED_NORM_V29              15
+#define DSP_CONNECTED_NORM_V33              16
+#define DSP_CONNECTED_NORM_V17              17
+#define DSP_CONNECTED_OPTION_TRELLIS        0x0001
+/*---------------------------------------------------------------------------*/
+extern char *dsp_read_file (OsFileHandle          *fp,
+                            word                     card_type_number,
+                            word                  *p_dsp_download_count,
+                            t_dsp_desc            *p_dsp_download_table,
+                            t_dsp_portable_desc   *p_dsp_portable_download_table) ;
+/*---------------------------------------------------------------------------*/
+#endif /* DSP_DEFS_H_ */  
diff -Nru a/drivers/isdn/hardware/eicon/dsp_tst.h b/drivers/isdn/hardware/eicon/dsp_tst.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dsp_tst.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,47 @@
+/* $Id: dsp_tst.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#ifndef __DIVA_PRI_HOST_TEST_DSPS_H__
+#define __DIVA_PRI_HOST_TEST_DSPS_H__
+
+/*
+   DSP registers on maestra pri
+   */
+#define DSP1_PORT       (0x00)
+#define DSP2_PORT       (0x8)
+#define DSP3_PORT       (0x800)
+#define DSP4_PORT       (0x808)
+#define DSP5_PORT       (0x810)
+#define DSP6_PORT       (0x818)
+#define DSP7_PORT       (0x820)
+#define DSP8_PORT       (0x828)
+#define DSP9_PORT       (0x830)
+#define DSP10_PORT      (0x840)
+#define DSP11_PORT      (0x848)
+#define DSP12_PORT      (0x850)
+#define DSP13_PORT      (0x858)        
+#define DSP14_PORT      (0x860)
+#define DSP15_PORT      (0x868)
+#define DSP16_PORT      (0x870)
+#define DSP17_PORT      (0x1000)
+#define DSP18_PORT      (0x1008)
+#define DSP19_PORT      (0x1010)
+#define DSP20_PORT      (0x1018)
+#define DSP21_PORT      (0x1020)
+#define DSP22_PORT      (0x1028)
+#define DSP23_PORT      (0x1030)
+#define DSP24_PORT      (0x1040)
+#define DSP25_PORT      (0x1048)
+#define DSP26_PORT      (0x1050)
+#define DSP27_PORT      (0x1058)
+#define DSP28_PORT      (0x1060)
+#define DSP29_PORT      (0x1068)
+#define DSP30_PORT      (0x1070)
+#define DSP_ADR_OFFS    0x80
+
+/*------------------------------------------------------------------
+		Dsp related definitions
+  ------------------------------------------------------------------ */
+#define DSP_SIGNATURE_PROBE_WORD 0x5a5a
+#define dsp_make_address_ex(pm,address) ((word)((pm) ? (address) : (address) + 0x4000))
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/dspdids.h b/drivers/isdn/hardware/eicon/dspdids.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dspdids.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,75 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef DSPDIDS_H_
+#define DSPDIDS_H_
+/*---------------------------------------------------------------------------*/
+#define DSP_DID_INVALID   0
+#define DSP_DID_DIVA   1
+#define DSP_DID_DIVA_PRO  2
+#define DSP_DID_DIVA_PRO_20  3
+#define DSP_DID_DIVA_PRO_PCCARD  4
+#define DSP_DID_DIVA_SERVER_BRI_1M 5
+#define DSP_DID_DIVA_SERVER_BRI_2M 6
+#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7
+#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8
+#define DSP_DID_DIVA_SERVER_PRI_30M 9
+#define DSP_DID_TASK_HSCX  100
+#define DSP_DID_TASK_HSCX_PRI_2M_TX 101
+#define DSP_DID_TASK_HSCX_PRI_2M_RX 102
+#define DSP_DID_TASK_V110KRNL  200
+#define DSP_DID_OVERLAY_V1100  201
+#define DSP_DID_OVERLAY_V1101  202
+#define DSP_DID_OVERLAY_V1102  203
+#define DSP_DID_OVERLAY_V1103  204
+#define DSP_DID_OVERLAY_V1104  205
+#define DSP_DID_OVERLAY_V1105  206
+#define DSP_DID_OVERLAY_V1106  207
+#define DSP_DID_OVERLAY_V1107  208
+#define DSP_DID_OVERLAY_V1108  209
+#define DSP_DID_OVERLAY_V1109  210
+#define DSP_DID_TASK_V110_PRI_2M_TX 220
+#define DSP_DID_TASK_V110_PRI_2M_RX 221
+#define DSP_DID_TASK_MODEM  300
+#define DSP_DID_TASK_FAX05  400
+#define DSP_DID_TASK_VOICE  500
+#define DSP_DID_TASK_TIKRNL81  600
+#define DSP_DID_OVERLAY_DIAL  601
+#define DSP_DID_OVERLAY_V22  602
+#define DSP_DID_OVERLAY_V32  603
+#define DSP_DID_OVERLAY_FSK  604
+#define DSP_DID_OVERLAY_FAX  605
+#define DSP_DID_OVERLAY_VXX  606
+#define DSP_DID_OVERLAY_V8  607
+#define DSP_DID_OVERLAY_INFO  608
+#define DSP_DID_OVERLAY_V34  609
+#define DSP_DID_OVERLAY_DFX  610
+#define DSP_DID_PARTIAL_OVERLAY_DIAL 611
+#define DSP_DID_PARTIAL_OVERLAY_FSK 612
+#define DSP_DID_PARTIAL_OVERLAY_FAX 613
+#define DSP_DID_TASK_TIKRNL05  700
+/*---------------------------------------------------------------------------*/
+#endif
+/*---------------------------------------------------------------------------*/
diff -Nru a/drivers/isdn/hardware/eicon/dsrv4bri.h b/drivers/isdn/hardware/eicon/dsrv4bri.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dsrv4bri.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,40 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_XDI_DSRV_4_BRI_INC__
+#define __DIVA_XDI_DSRV_4_BRI_INC__
+/*
+ * Some special registers in the PLX 9054
+ */
+#define PLX9054_P2LDBELL    0x60
+#define PLX9054_L2PDBELL    0x64
+#define PLX9054_INTCSR      0x69
+#define PLX9054_INT_ENABLE  0x09
+#define PLX9054_SOFT_RESET 0x4000
+#define PLX9054_RELOAD_EEPROM 0x2000
+#define DIVA_4BRI_REVISION(__x__) (((__x__)->cardType == CARDTYPE_DIVASRV_Q_8M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_B_2M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_B_2F_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI))
+void diva_os_set_qBri_functions (PISDN_ADAPTER IoAdapter);
+void diva_os_set_qBri2_functions (PISDN_ADAPTER IoAdapter);
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/dsrv_bri.h b/drivers/isdn/hardware/eicon/dsrv_bri.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dsrv_bri.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,37 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_XDI_DSRV_BRI_INC__
+#define __DIVA_XDI_DSRV_BRI_INC__
+/*
+ Functions exported from os dependent part of
+ BRI card configuration and used in
+ OS independed part
+ */
+/*
+ Prepare OS dependent part of BRI functions
+ */
+void diva_os_prepare_maestra_functions (PISDN_ADAPTER IoAdapter);
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/dsrv_pri.h b/drivers/isdn/hardware/eicon/dsrv_pri.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/dsrv_pri.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,38 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_XDI_DSRV_PRI_INC__
+#define __DIVA_XDI_DSRV_PRI_INC__
+/*
+ Functions exported from os dependent part of
+ PRI card configuration and used in
+ OS independed part
+ */
+/*
+ Prepare OS dependent part of PRI/PRI Rev.2 functions
+ */
+void diva_os_prepare_pri_functions (PISDN_ADAPTER IoAdapter);
+void diva_os_prepare_pri2_functions (PISDN_ADAPTER IoAdapter);
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/entity.h b/drivers/isdn/hardware/eicon/entity.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/entity.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,28 @@
+/* $Id: entity.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#ifndef __DIVAS_USER_MODE_IDI_ENTITY__
+#define __DIVAS_USER_MODE_IDI_ENTITY__
+
+#define DIVA_UM_IDI_RC_PENDING      0x00000001
+#define DIVA_UM_IDI_REMOVE_PENDING  0x00000002
+#define DIVA_UM_IDI_TX_FLOW_CONTROL 0x00000004
+#define DIVA_UM_IDI_REMOVED         0x00000008
+#define DIVA_UM_IDI_ASSIGN_PENDING  0x00000010
+
+typedef struct _divas_um_idi_entity {
+  diva_entity_link_t        link; /* should be first */
+  diva_um_idi_adapter_t*    adapter; /* Back to adapter */
+  ENTITY                    e;
+  void*                     os_ref;
+  dword                     status;
+  void*                     os_context;
+  int                       rc_count;
+  diva_um_idi_data_queue_t  data; /* definad by user 1 ... MAX */
+  diva_um_idi_data_queue_t  rc;   /* two entries */
+  BUFFERS                   XData;
+  BUFFERS                   RData;
+  byte                      buffer[2048+512];
+} divas_um_idi_entity_t;
+
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/helpers.h b/drivers/isdn/hardware/eicon/helpers.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/helpers.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,51 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_XDI_CARD_CONFIG_HELPERS_INC__
+#define __DIVA_XDI_CARD_CONFIG_HELPERS_INC__
+dword diva_get_protocol_file_features  (byte* File,
+                      int offset,
+                      char *IdStringBuffer,
+                      dword IdBufferSize);
+void diva_configure_protocol (PISDN_ADAPTER IoAdapter);
+/*
+ Low level file access system abstraction
+ */
+/* -------------------------------------------------------------------------
+  Access to single file
+  Return pointer to the image of the requested file,
+  write image length to 'FileLength'
+  ------------------------------------------------------------------------- */
+void *xdiLoadFile (char *FileName, dword *FileLength, unsigned long MaxLoadSize) ;
+/* -------------------------------------------------------------------------
+  Dependent on the protocol settings does read return pointer
+  to the image of appropriate protocol file
+  ------------------------------------------------------------------------- */
+void *xdiLoadArchive (PISDN_ADAPTER IoAdapter, dword *FileLength, unsigned long MaxLoadSize) ;
+/* --------------------------------------------------------------------------
+  Free all system resources accessed by xdiLoadFile and xdiLoadArchive
+  -------------------------------------------------------------------------- */
+void xdiFreeFile (void* handle);
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/i4l_idi.c b/drivers/isdn/hardware/eicon/i4l_idi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/i4l_idi.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,3137 @@
+/* $Id: i4l_idi.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards.
+ * I4L - IDI Interface
+ *
+ * Copyright 1998-2000  by Armin Schindler (mac@melware.de)
+ * Copyright 1999-2002  Cytronics & Melware (info@melware.de)
+ *
+ * Thanks to	Deutsche Mailbox Saar-Lor-Lux GmbH
+ *		for sponsoring and testing fax
+ *		capabilities with Diva Server cards.
+ *		(dor@deutschemailbox.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include "i4lididrv.h"
+
+#undef EICON_FULL_SERVICE_OKTETT
+
+char *eicon_idi_revision = "$Revision: 1.1.2.2 $";
+
+eicon_manifbuf *manbuf;
+
+static int eicon_idi_manage_assign(eicon_card *card);
+static int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);
+
+static int
+idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
+{
+	int l = 0;
+	int tmp;
+
+	tmp = 0;
+  if (!signet) {
+	/* Signal Layer */
+	reqbuf->XBuffer.P[l++] = CAI;
+	reqbuf->XBuffer.P[l++] = 1;
+	reqbuf->XBuffer.P[l++] = 0;
+	reqbuf->XBuffer.P[l++] = KEY;
+	reqbuf->XBuffer.P[l++] = 3;
+	reqbuf->XBuffer.P[l++] = 'I';
+	reqbuf->XBuffer.P[l++] = '4';
+	reqbuf->XBuffer.P[l++] = 'L';
+	reqbuf->XBuffer.P[l++] = SHIFT|6;
+	reqbuf->XBuffer.P[l++] = SIN;
+	reqbuf->XBuffer.P[l++] = 2;
+	reqbuf->XBuffer.P[l++] = 0;
+	reqbuf->XBuffer.P[l++] = 0;
+	reqbuf->XBuffer.P[l++] = 0; /* end */
+	reqbuf->Req = ASSIGN;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = DSIG_ID;
+	reqbuf->XBuffer.length = l;
+	reqbuf->Reference = 0; /* Sig Entity */
+  }
+  else {
+	/* Network Layer */
+	reqbuf->XBuffer.P[l++] = CAI;
+	reqbuf->XBuffer.P[l++] = 1;
+	reqbuf->XBuffer.P[l++] = chan->e.D3Id;
+	reqbuf->XBuffer.P[l++] = LLC;
+	reqbuf->XBuffer.P[l++] = 2;
+	switch(chan->l2prot) {
+		case ISDN_PROTO_L2_V11096:
+		case ISDN_PROTO_L2_V11019:
+		case ISDN_PROTO_L2_V11038:
+		case ISDN_PROTO_L2_TRANS:
+			reqbuf->XBuffer.P[l++] = 2; /* transparent */
+			break;
+		case ISDN_PROTO_L2_X75I:
+		case ISDN_PROTO_L2_X75UI:
+		case ISDN_PROTO_L2_X75BUI:
+			reqbuf->XBuffer.P[l++] = 5; /* X.75 */ 
+			break;
+		case ISDN_PROTO_L2_MODEM:
+  			  if (chan->fsm_state == EICON_STATE_IWAIT)
+				reqbuf->XBuffer.P[l++] = 9; /* V.42 incoming */
+  			  else
+				reqbuf->XBuffer.P[l++] = 10; /* V.42 */
+			  break;
+		case ISDN_PROTO_L2_HDLC:
+		case ISDN_PROTO_L2_FAX:
+  			if (chan->fsm_state == EICON_STATE_IWAIT)
+				reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */
+			else
+				reqbuf->XBuffer.P[l++] = 2; /* transparent */
+			break;
+		default:
+			reqbuf->XBuffer.P[l++] = 1;
+	}
+	switch(chan->l3prot) {
+		case ISDN_PROTO_L3_FCLASS2:
+#ifdef CONFIG_ISDN_TTY_FAX
+			reqbuf->XBuffer.P[l++] = 6;
+			reqbuf->XBuffer.P[l++] = NLC;
+			tmp = idi_fill_in_T30(chan, &reqbuf->XBuffer.P[l+1]);
+			reqbuf->XBuffer.P[l++] = tmp; 
+			l += tmp;
+			break;
+#endif
+		case ISDN_PROTO_L3_TRANS:
+		default:
+			reqbuf->XBuffer.P[l++] = 4;
+	}
+        /* Additional DLC element */
+       switch(chan->l2prot) {
+               case ISDN_PROTO_L2_X75I:
+               case ISDN_PROTO_L2_X75UI:
+               case ISDN_PROTO_L2_X75BUI:
+               case ISDN_PROTO_L2_FAX:
+                    reqbuf->XBuffer.P[l++] = DLC;
+                    reqbuf->XBuffer.P[l++] = 2;
+                    reqbuf->XBuffer.P[l++] = (2138 % 256); /* max. info (lo byte) */
+                    reqbuf->XBuffer.P[l++] = (2138 / 256); /* max. info (hi byte) */
+                break;
+        }
+	reqbuf->XBuffer.P[l++] = 0; /* end */
+	reqbuf->Req = ASSIGN;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = NL_ID;
+	reqbuf->XBuffer.length = l;
+	reqbuf->Reference = 1; /* Net Entity */
+  }
+   return(0);
+}
+
+static int
+idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch)
+{
+	reqbuf->Req = rq;
+	reqbuf->ReqCh = Ch;
+	reqbuf->ReqId = 1;
+	reqbuf->XBuffer.length = 1;
+	reqbuf->XBuffer.P[0] = 0;
+	reqbuf->Reference = signet;
+   return(0);
+}
+
+static int
+idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan)
+{
+	reqbuf->Req = SUSPEND;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = 1;
+	reqbuf->XBuffer.P[0] = CAI;
+	reqbuf->XBuffer.P[1] = 1;
+	reqbuf->XBuffer.P[2] = chan->No;
+	reqbuf->XBuffer.P[3] = 0;
+	reqbuf->XBuffer.length = 4;
+	reqbuf->Reference = 0; /* Sig Entity */
+   return(0);
+}
+
+static int
+idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
+{
+	int l = 9;
+	reqbuf->Req = CALL_RES;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = 1;
+	reqbuf->XBuffer.P[0] = CAI;
+	reqbuf->XBuffer.P[1] = 6;
+	reqbuf->XBuffer.P[2] = 9;
+	reqbuf->XBuffer.P[3] = 0;
+	reqbuf->XBuffer.P[4] = 0;
+	reqbuf->XBuffer.P[5] = 0;
+	reqbuf->XBuffer.P[6] = 32;
+	reqbuf->XBuffer.P[7] = 0;
+	switch(chan->l2prot) {
+		case ISDN_PROTO_L2_X75I:
+		case ISDN_PROTO_L2_X75UI:
+		case ISDN_PROTO_L2_X75BUI:
+		case ISDN_PROTO_L2_HDLC:
+			reqbuf->XBuffer.P[1] = 1;
+			reqbuf->XBuffer.P[2] = 0x05;
+			l = 4;
+			break;
+		case ISDN_PROTO_L2_V11096:
+			reqbuf->XBuffer.P[2] = 0x0d;
+			reqbuf->XBuffer.P[3] = 5;
+			reqbuf->XBuffer.P[4] = 0;
+			break;
+		case ISDN_PROTO_L2_V11019:
+			reqbuf->XBuffer.P[2] = 0x0d;
+			reqbuf->XBuffer.P[3] = 6;
+			reqbuf->XBuffer.P[4] = 0;
+			break;
+		case ISDN_PROTO_L2_V11038:
+			reqbuf->XBuffer.P[2] = 0x0d;
+			reqbuf->XBuffer.P[3] = 7;
+			reqbuf->XBuffer.P[4] = 0;
+			break;
+		case ISDN_PROTO_L2_MODEM:
+			/* reqbuf->XBuffer.P[1] = 12; */
+			reqbuf->XBuffer.P[2] = 0x11;
+			reqbuf->XBuffer.P[3] = 9;
+			reqbuf->XBuffer.P[4] = 0;
+			reqbuf->XBuffer.P[5] = 0;
+			reqbuf->XBuffer.P[6] = 32;
+			reqbuf->XBuffer.P[7] = 0;
+			break;
+		case ISDN_PROTO_L2_FAX:
+			reqbuf->XBuffer.P[2] = 0x10;
+			reqbuf->XBuffer.P[3] = 0;
+			reqbuf->XBuffer.P[4] = 0;
+			reqbuf->XBuffer.P[5] = 0;
+			reqbuf->XBuffer.P[6] = 32;
+			reqbuf->XBuffer.P[7] = 0;
+			break;
+		case ISDN_PROTO_L2_TRANS:
+			switch(chan->l3prot) {
+				case ISDN_PROTO_L3_TRANSDSP:
+					reqbuf->XBuffer.P[2] = 22; /* DTMF, audio events on */
+			}
+			break;
+	}
+	reqbuf->XBuffer.P[l-1] = 0;
+	reqbuf->XBuffer.length = l;
+	reqbuf->Reference = 0; /* Sig Entity */
+	eicon_log(NULL, 8, "idi_req: Ch%d: Call_Res\n", chan->No);
+   return(0);
+}
+
+int
+idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
+{
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+	eicon_REQ *reqbuf;
+	eicon_chan_ptr *chan2;
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               	eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
+		if (skb) 
+			dev_kfree_skb(skb);
+		if (skb2) 
+			dev_kfree_skb(skb2);
+                return -ENOMEM; 
+	}
+
+	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+	chan2->ptr = chan;
+
+	reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+	eicon_log(card, 8, "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
+	if (layer) cmd |= 0x700;
+	switch(cmd) {
+		case ASSIGN:
+		case ASSIGN|0x700:
+			idi_assign_req(reqbuf, layer, chan);
+			break;
+		case REMOVE:
+		case REMOVE|0x700:
+			idi_put_req(reqbuf, REMOVE, layer, 0);
+			break;
+		case INDICATE_REQ:
+			idi_put_req(reqbuf, INDICATE_REQ, 0, 0);
+			break;
+		case HANGUP:
+			idi_put_req(reqbuf, HANGUP, 0, 0);
+			break;
+		case SUSPEND:
+			idi_put_suspend_req(reqbuf, chan);
+			break;
+		case RESUME:
+			idi_put_req(reqbuf, RESUME, 0 ,0);
+			break;
+		case REJECT:
+			idi_put_req(reqbuf, REJECT, 0 ,0);
+			break;
+		case CALL_ALERT:
+			idi_put_req(reqbuf, CALL_ALERT, 0, 0);
+			break;
+		case CALL_RES:
+			idi_call_res_req(reqbuf, chan);
+			break;
+		case CALL_HOLD:
+			idi_put_req(reqbuf, CALL_HOLD, 0, 0);
+			break;
+		case N_CONNECT|0x700:
+			idi_put_req(reqbuf, N_CONNECT, 1, 0);
+			break;
+		case N_CONNECT_ACK|0x700:
+			idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0);
+			break;
+		case N_DISC|0x700:
+			idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh);
+			break;
+		case N_DISC_ACK|0x700:
+			idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh);
+			break;
+		default:
+			eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
+			dev_kfree_skb(skb);
+			dev_kfree_skb(skb2);
+			return(-1);
+	}
+
+	skb_queue_tail(&chan->e.X, skb);
+	skb_queue_tail(&card->sndq, skb2); 
+	eicon_tx_request(card);
+	return(0);
+}
+
+int
+eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
+{
+	if ((!card) || (!chan))
+		return 1;
+
+	eicon_log(card, 16, "idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
+	if (!chan->e.D3Id) {
+		idi_do_req(card, chan, ASSIGN, 0); 
+	}
+	if (chan->fsm_state == EICON_STATE_NULL) {
+		if (!(chan->statectrl & HAVE_CONN_REQ)) {
+			idi_do_req(card, chan, INDICATE_REQ, 0);
+			chan->fsm_state = EICON_STATE_LISTEN;
+		}
+	}
+  return(0);
+}
+
+static unsigned char
+idi_si2bc(int si1, int si2, char *bc, char *hlc)
+{
+  hlc[0] = 0;
+  switch(si1) {
+	case 1:
+		bc[0] = 0x90;		/* 3,1 kHz audio */
+		bc[1] = 0x90;		/* 64 kbit/s */
+		bc[2] = 0xa3;		/* G.711 A-law */
+#ifdef EICON_FULL_SERVICE_OKTETT
+		if (si2 == 1) {
+			bc[0] = 0x80;	/* Speech */
+			hlc[0] = 0x02;	/* hlc len */
+			hlc[1] = 0x91;	/* first hic */
+			hlc[2] = 0x81;	/* Telephony */
+		}
+#endif
+		return(3);
+	case 2:
+		bc[0] = 0x90;		/* 3,1 kHz audio */
+		bc[1] = 0x90;		/* 64 kbit/s */
+		bc[2] = 0xa3;		/* G.711 A-law */
+#ifdef EICON_FULL_SERVICE_OKTETT
+		if (si2 == 2) {
+			hlc[0] = 0x02;	/* hlc len */
+			hlc[1] = 0x91;	/* first hic */
+			hlc[2] = 0x84;	/* Fax Gr.2/3 */
+		}
+#endif
+		return(3);
+	case 5:
+	case 7:
+	default:
+		bc[0] = 0x88;
+		bc[1] = 0x90;
+		return(2);
+  }
+ return (0);
+}
+
+int
+idi_hangup(eicon_card *card, eicon_chan *chan)
+{
+	if ((!card) || (!chan))
+		return 1;
+
+	if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
+	    (chan->fsm_state == EICON_STATE_WMCONN)) {
+  		if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1);
+	}
+	if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
+	if (chan->fsm_state != EICON_STATE_NULL) {
+		chan->statectrl |= WAITING_FOR_HANGUP;
+		idi_do_req(card, chan, HANGUP, 0);
+		chan->fsm_state = EICON_STATE_NULL;
+	}
+	eicon_log(card, 8, "idi_req: Ch%d: Hangup\n", chan->No);
+#ifdef CONFIG_ISDN_TTY_FAX
+	chan->fax = 0;
+#endif
+  return(0);
+}
+
+int
+capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm)
+{
+	if ((cm->para[0] != 3) || (cm->para[1] != 0))
+		return -1;
+	if (cm->para[2] < 3)
+		return -1;
+	if (cm->para[4] != 0)
+		return -1;
+	switch(cm->para[3]) {
+		case 4: /* Suspend */
+			eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No);
+			if (cm->para[5]) {
+				idi_do_req(card, chan, SUSPEND, 0);
+			} else {
+				idi_do_req(card, chan, CALL_HOLD, 0);
+			}
+			break;
+		case 5: /* Resume */
+			eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No);
+			idi_do_req(card, chan, RESUME, 0);
+			break;
+        }
+	return 0;
+}
+
+int
+idi_connect_res(eicon_card *card, eicon_chan *chan)
+{
+	if ((!card) || (!chan))
+		return 1;
+
+	chan->fsm_state = EICON_STATE_IWAIT;
+	
+	/* check if old NetID has been removed */
+	if (chan->e.B2Id) {
+		eicon_log(card, 1, "idi_conn_res: Ch%d: old net_id %x still exist, removing.\n",
+			chan->No, chan->e.B2Id);
+		idi_do_req(card, chan, REMOVE, 1);
+	}
+
+	idi_do_req(card, chan, ASSIGN, 1);
+	idi_do_req(card, chan, CALL_RES, 0);
+	return(0);
+}
+
+int
+idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
+                    char *eazmsn, int si1, int si2)
+{
+	int l = 0;
+	int i;
+	unsigned char tmp;
+	unsigned char *sub, *sp;
+	unsigned char bc[5];
+	unsigned char hlc[5];
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+	eicon_REQ *reqbuf;
+	eicon_chan_ptr *chan2;
+
+	if ((!card) || (!chan))
+		return 1;
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               	eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
+		if (skb) 
+			dev_kfree_skb(skb);
+		if (skb2) 
+			dev_kfree_skb(skb2);
+                return -ENOMEM; 
+	}
+
+	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+	chan2->ptr = chan;
+
+	reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+	reqbuf->Req = CALL_REQ;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = 1;
+
+	sub = NULL;
+	sp = phone;
+	while (*sp) {
+		if (*sp == '.') {
+			sub = sp + 1;
+			*sp = 0;
+		} else
+			sp++;
+	}
+	reqbuf->XBuffer.P[l++] = CPN;
+	reqbuf->XBuffer.P[l++] = strlen(phone) + 1;
+	reqbuf->XBuffer.P[l++] = 0x81;
+	for(i=0; i<strlen(phone);i++) 
+		reqbuf->XBuffer.P[l++] = phone[i] & 0x7f;
+	if (sub) {
+		reqbuf->XBuffer.P[l++] = DSA;
+		reqbuf->XBuffer.P[l++] = strlen(sub) + 2;
+		reqbuf->XBuffer.P[l++] = 0x80; /* NSAP coded */
+		reqbuf->XBuffer.P[l++] = 0x50; /* local IDI format */
+		while (*sub)
+			reqbuf->XBuffer.P[l++] = *sub++ & 0x7f;
+	}
+
+	sub = NULL;
+	sp = eazmsn;
+	while (*sp) {
+		if (*sp == '.') {
+			sub = sp + 1;
+			*sp = 0;
+		} else
+			sp++;
+	}
+	reqbuf->XBuffer.P[l++] = OAD;
+	reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2;
+	reqbuf->XBuffer.P[l++] = 0x01;
+	reqbuf->XBuffer.P[l++] = 0x80;
+	for(i=0; i<strlen(eazmsn);i++) 
+		reqbuf->XBuffer.P[l++] = eazmsn[i] & 0x7f;
+	if (sub) {
+		reqbuf->XBuffer.P[l++] = OSA;
+		reqbuf->XBuffer.P[l++] = strlen(sub) + 2;
+		reqbuf->XBuffer.P[l++] = 0x80; /* NSAP coded */
+		reqbuf->XBuffer.P[l++] = 0x50; /* local IDI format */
+		while (*sub)
+			reqbuf->XBuffer.P[l++] = *sub++ & 0x7f;
+	}
+
+	if (si2 > 2) {
+		reqbuf->XBuffer.P[l++] = SHIFT|6;
+		reqbuf->XBuffer.P[l++] = SIN;
+		reqbuf->XBuffer.P[l++] = 2;
+		reqbuf->XBuffer.P[l++] = si1;
+		reqbuf->XBuffer.P[l++] = si2;
+	}
+	else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
+		reqbuf->XBuffer.P[l++] = BC;
+		reqbuf->XBuffer.P[l++] = tmp;
+		for(i=0; i<tmp;i++) 
+			reqbuf->XBuffer.P[l++] = bc[i];
+		if ((tmp=hlc[0])) {
+			reqbuf->XBuffer.P[l++] = HLC;
+			reqbuf->XBuffer.P[l++] = tmp;
+			for(i=1; i<=tmp;i++) 
+				reqbuf->XBuffer.P[l++] = hlc[i];
+		}
+	}
+
+        reqbuf->XBuffer.P[l++] = CAI;
+        reqbuf->XBuffer.P[l++] = 6;
+        reqbuf->XBuffer.P[l++] = 0x09;
+	reqbuf->XBuffer.P[l++] = 0;
+	reqbuf->XBuffer.P[l++] = 0;
+	reqbuf->XBuffer.P[l++] = 0;
+	reqbuf->XBuffer.P[l++] = 32;
+	reqbuf->XBuffer.P[l++] = 0;
+        switch(chan->l2prot) {
+		case ISDN_PROTO_L2_X75I:
+		case ISDN_PROTO_L2_X75UI:
+		case ISDN_PROTO_L2_X75BUI:
+                case ISDN_PROTO_L2_HDLC:
+                        reqbuf->XBuffer.P[l-6] = 5;
+                        reqbuf->XBuffer.P[l-7] = 1;
+			l -= 5; 
+                        break;
+                case ISDN_PROTO_L2_V11096:
+                        reqbuf->XBuffer.P[l-7] = 3;
+                        reqbuf->XBuffer.P[l-6] = 0x0d;
+                        reqbuf->XBuffer.P[l-5] = 5;
+                        reqbuf->XBuffer.P[l-4] = 0;
+                        l -= 3;
+                        break;
+                case ISDN_PROTO_L2_V11019:
+                        reqbuf->XBuffer.P[l-7] = 3;
+                        reqbuf->XBuffer.P[l-6] = 0x0d;
+                        reqbuf->XBuffer.P[l-5] = 6;
+                        reqbuf->XBuffer.P[l-4] = 0;
+                        l -= 3;
+                        break;
+                case ISDN_PROTO_L2_V11038:
+                        reqbuf->XBuffer.P[l-7] = 3;
+                        reqbuf->XBuffer.P[l-6] = 0x0d;
+                        reqbuf->XBuffer.P[l-5] = 7;
+                        reqbuf->XBuffer.P[l-4] = 0;
+                        l -= 3;
+                        break;
+                case ISDN_PROTO_L2_MODEM:
+			/* reqbuf->XBuffer.P[l-7] = 12; */
+			reqbuf->XBuffer.P[l-6] = 0x11;
+			reqbuf->XBuffer.P[l-5] = 7;
+			reqbuf->XBuffer.P[l-4] = 0;
+			reqbuf->XBuffer.P[l-3] = 0;
+			reqbuf->XBuffer.P[l-2] = 32;
+			reqbuf->XBuffer.P[l-1] = 0;
+                        break;
+                case ISDN_PROTO_L2_FAX:
+			reqbuf->XBuffer.P[l-6] = 0x10;
+			reqbuf->XBuffer.P[l-5] = 0;
+			reqbuf->XBuffer.P[l-4] = 0;
+			reqbuf->XBuffer.P[l-3] = 0;
+			reqbuf->XBuffer.P[l-2] = 32;
+			reqbuf->XBuffer.P[l-1] = 0;
+                        break;
+		case ISDN_PROTO_L2_TRANS:
+			switch(chan->l3prot) {
+				case ISDN_PROTO_L3_TRANSDSP:
+					reqbuf->XBuffer.P[l-6] = 22; /* DTMF, audio events on */
+			}
+			break;
+        }
+	
+	reqbuf->XBuffer.P[l++] = 0; /* end */
+	reqbuf->XBuffer.length = l;
+	reqbuf->Reference = 0; /* Sig Entity */
+
+	if (chan->statectrl & WAITING_FOR_HANGUP) {
+		/*	If the line did not disconnect yet,
+			we have to delay this command		*/
+		eicon_log(card, 32, "idi_req: Ch%d: delaying conn_req\n", chan->No);
+		chan->statectrl |= HAVE_CONN_REQ;
+		chan->tskb1 = skb;
+		chan->tskb2 = skb2;
+	} else {
+		skb_queue_tail(&chan->e.X, skb);
+		skb_queue_tail(&card->sndq, skb2); 
+		eicon_tx_request(card);
+	}
+
+	eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
+   return(0);
+}
+
+
+static void
+idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsigned char *buffer, int len)
+{
+	int i,j;
+	int pos = 0;
+	int codeset = 0;
+	int wlen = 0;
+	int lock = 0;
+	__u8 w;
+	__u16 code;
+	isdn_ctrl cmd;
+
+	memset(message, 0, sizeof(idi_ind_message));
+
+	if ((!len) || (!buffer[pos])) return;
+
+  while(pos <= len) {
+	w = buffer[pos++];
+	if (!w) return;
+	if (w & 0x80) {
+		wlen = 0;
+	}
+	else {
+		wlen = buffer[pos++];
+	}
+
+	if (pos > len) return;
+
+	if (lock & 0x80) lock &= 0x7f;
+	else codeset = lock;
+
+	if((w&0xf0) == SHIFT) {
+		codeset = w;
+		if(!(codeset & 0x08)) lock = codeset & 7;
+		codeset &= 7;
+		lock |= 0x80;
+	}
+	else {
+		if (w==ESC && wlen >=2) {
+			code = buffer[pos++]|0x800;
+			wlen--;
+		}
+		else code = w;
+		code |= (codeset<<8);
+
+		if (pos + wlen > len) {
+			eicon_log(ccard, 1, "idi_err: Ch%d: IElen %d of %x exceeds Ind_Length (+%d)\n", chan->No, 
+					wlen, code, (pos + wlen) - len);
+			return;
+		}
+
+		switch(code) {
+			case OAD:
+				if (wlen > sizeof(message->oad)) {
+					pos += wlen;
+					break;
+				}
+				j = 1;
+				if (wlen) {
+					message->plan = buffer[pos++];
+					if (message->plan &0x80) 
+						message->screen = 0;
+					else {
+						message->screen = buffer[pos++];
+						j = 2;
+					}
+				}
+				for(i=0; i < wlen-j; i++) 
+					message->oad[i] = buffer[pos++];
+				eicon_log(ccard, 2, "idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, 
+					message->plan, message->screen, message->oad);
+				break;
+			case RDN:
+				if (wlen > sizeof(message->rdn)) {
+					pos += wlen;
+					break;
+				}
+				j = 1;
+				if (wlen) {
+					if (!(buffer[pos++] & 0x80)) {
+						pos++; 
+						j = 2;
+					}
+				}
+				for(i=0; i < wlen-j; i++) 
+					message->rdn[i] = buffer[pos++];
+				eicon_log(ccard, 2, "idi_inf: Ch%d: RDN= %s\n", chan->No, 
+						message->rdn);
+				break;
+			case CPN:
+				if (wlen > sizeof(message->cpn)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->cpn[i] = buffer[pos++];
+				eicon_log(ccard, 2, "idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
+					(__u8)message->cpn[0], message->cpn + 1);
+				break;
+			case DSA:
+				if (wlen > sizeof(message->dsa)) {
+					pos += wlen;
+					break;
+				}
+				pos += 2;
+				for(i=0; i < wlen-2; i++) 
+					message->dsa[i] = buffer[pos++];
+				eicon_log(ccard, 2, "idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
+				break;
+			case OSA:
+				if (wlen > sizeof(message->osa)) {
+					pos += wlen;
+					break;
+				}
+				pos += 2;
+				for(i=0; i < wlen-2; i++) 
+					message->osa[i] = buffer[pos++];
+				eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
+				break;
+			case CAD:
+				pos += wlen;
+				eicon_log(ccard, 2, "idi_inf: Ch%d: Connected Address in ind, len:%x\n", 
+					chan->No, wlen);
+				break;
+			case BC:
+				if (wlen > sizeof(message->bc)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->bc[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
+					message->bc[0],message->bc[1],message->bc[2]);
+				break;
+			case 0x800|BC:
+				if (wlen > sizeof(message->e_bc)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->e_bc[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
+				break;
+			case LLC:
+				if (wlen > sizeof(message->llc)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->llc[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0],
+					message->llc[1],message->llc[2],message->llc[3]);
+				break;
+			case HLC:
+				if (wlen > sizeof(message->hlc)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->hlc[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No,
+					message->hlc[0], message->hlc[1],
+					message->hlc[2], message->hlc[3], message->hlc[4]);
+				break;
+			case DSP:
+			case 0x600|DSP:
+				if (wlen > sizeof(message->display)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->display[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: Display: %s\n", chan->No,
+					message->display);
+				break;
+			case 0x600|KEY:
+				if (wlen > sizeof(message->keypad)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->keypad[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: Keypad: %s\n", chan->No,
+					message->keypad);
+				break;
+			case NI:
+			case 0x600|NI:
+				if (wlen) {
+					switch(buffer[pos] & 127) {
+						case 0:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: User suspended.\n", chan->No);
+							break;
+						case 1:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: User resumed.\n", chan->No);
+							break;
+						case 2:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Bearer service change.\n", chan->No);
+							break;
+						default:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Notification %x.\n", 
+									chan->No, buffer[pos] & 127);
+					}
+					pos += wlen;
+				}
+				break;
+			case PI:
+			case 0x600|PI:
+				if (wlen > 1) {
+					switch(buffer[pos+1] & 127) {
+						case 1:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
+							break;
+						case 2:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
+							break;
+						case 3:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
+							break;
+						case 4:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
+							break;
+						case 5:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
+							break;
+						case 8:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: In-band information available.\n", chan->No);
+							break;
+						default:
+							eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Progress %x.\n", 
+									chan->No, buffer[pos+1] & 127);
+					}
+				}
+				pos += wlen;
+				break;
+			case CAU:
+				if (wlen > sizeof(message->cau)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->cau[i] = buffer[pos++];
+				memcpy(&chan->cause, &message->cau, 2);
+				eicon_log(ccard, 4, "idi_inf: Ch%d: CAU=%d %d\n", chan->No,
+					message->cau[0],message->cau[1]);
+				break;
+			case 0x800|CAU:
+				if (wlen > sizeof(message->e_cau)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->e_cau[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
+					message->e_cau[0],message->e_cau[1]);
+				break;
+			case 0x800|CHI:
+				if (wlen > sizeof(message->e_chi)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->e_chi[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
+					message->e_cau[0]);
+				break;
+			case 0x800|0x7a:
+				pos ++;
+				message->e_mt=buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
+				break;
+			case DT:
+				if (wlen > sizeof(message->dt)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->dt[i] = buffer[pos++];
+				eicon_log(ccard, 4, "idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
+					message->dt[2], message->dt[1], message->dt[0],
+					message->dt[3], message->dt[4], message->dt[5]);
+				break;
+			case 0x600|SIN:
+				if (wlen > sizeof(message->sin)) {
+					pos += wlen;
+					break;
+				}
+				for(i=0; i < wlen; i++) 
+					message->sin[i] = buffer[pos++];
+				eicon_log(ccard, 2, "idi_inf: Ch%d: SIN=%d %d\n", chan->No,
+					message->sin[0],message->sin[1]);
+				break;
+			case 0x600|CPS:
+				eicon_log(ccard, 2, "idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
+				pos += wlen;
+				break;
+			case 0x600|CIF:
+				for (i = 0; i < wlen; i++)
+					if (buffer[pos + i] != '0') break;
+				memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i);
+				cmd.parm.num[wlen - i] = 0;
+				eicon_log(ccard, 2, "idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
+				pos += wlen;
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_CINF;
+				cmd.arg = chan->No;
+				ccard->interface.statcallb(&cmd);
+				break;
+			case 0x600|DATE:
+				eicon_log(ccard, 2, "idi_inf: Ch%d: Date in ind\n", chan->No);
+				pos += wlen;
+				break;
+			case 0xa1: 
+				eicon_log(ccard, 2, "idi_inf: Ch%d: Sending Complete in ind.\n", chan->No);
+				pos += wlen;
+				break;
+			case 0xe08: 
+			case 0xe7a: 
+			case 0xe04: 
+			case 0xe00: 
+				/* *** TODO *** */
+			case CHA:
+				/* Charge advice */
+			case FTY:
+			case 0x600|FTY:
+			case CHI:
+			case 0x800:
+				/* Not yet interested in this */
+				pos += wlen;
+				break;
+			case 0x880:
+				/* Managment Information Element */
+				if (!manbuf) {
+					eicon_log(ccard, 1, "idi_err: manbuf not allocated\n");
+				}
+				else {
+					memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen);
+					manbuf->length[manbuf->count] = wlen;
+					manbuf->count++;
+					manbuf->pos += wlen;
+				}
+				pos += wlen;
+				break;
+			default:
+				pos += wlen;
+				eicon_log(ccard, 6, "idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", 
+					chan->No, code, wlen);
+		}
+	}
+  }
+}
+
+static void
+idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2)
+{
+	si1[0] = 0;
+	si2[0] = 0;
+
+	switch (bc[0] & 0x7f) {
+		case 0x00: /* Speech */
+			si1[0] = 1;
+#ifdef EICON_FULL_SERVICE_OKTETT
+			si1[0] = sin[0];
+			si2[0] = sin[1];
+#endif
+			break;
+		case 0x10: /* 3.1 Khz audio */
+			si1[0] = 1;
+#ifdef EICON_FULL_SERVICE_OKTETT
+			si1[0] = sin[0];
+			si2[0] = sin[1];
+#endif
+			break;
+		case 0x08: /* Unrestricted digital information */
+			si1[0] = 7;
+			si2[0] = sin[1];
+			break;
+		case 0x09: /* Restricted digital information */
+			si1[0] = 2;
+			break;
+		case 0x11:
+			/* Unrestr. digital information  with
+			 * tones/announcements ( or 7 kHz audio
+			 */
+			si1[0] = 3;
+			break;
+		case 0x18: /* Video */
+			si1[0] = 4;
+			break;
+	}
+	switch (bc[1] & 0x7f) {
+		case 0x40: /* packed mode */
+			si1[0] = 8;
+			break;
+		case 0x10: /* 64 kbit */
+		case 0x11: /* 2*64 kbit */
+		case 0x13: /* 384 kbit */
+		case 0x15: /* 1536 kbit */
+		case 0x17: /* 1920 kbit */
+			/* moderate = bc[1] & 0x7f; */
+			break;
+	}
+}
+
+/********************* FAX stuff ***************************/
+
+#ifdef CONFIG_ISDN_TTY_FAX
+
+static int
+idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer)
+{
+	eicon_t30_s	*t30 = (eicon_t30_s *) buffer;
+
+	if (!chan->fax) {
+		eicon_log(NULL, 1,"idi_T30: fill_in with NULL fax struct, ERROR\n");
+		return 0;
+	}
+	memset(t30, 0, sizeof(eicon_t30_s));
+	t30->station_id_len = EICON_FAXID_LEN;
+	memcpy(&t30->station_id[0], &chan->fax->id[0], EICON_FAXID_LEN);
+	t30->resolution = chan->fax->resolution;
+	t30->rate = chan->fax->rate + 1;	/* eicon rate starts with 1 */
+	t30->format = T30_FORMAT_SFF;
+	t30->pages_low = 0;
+	t30->pages_high = 0;
+	t30->atf = 1;				/* optimised for AT+F command set */
+	t30->code = 0;
+	t30->feature_bits_low = 0;
+	t30->feature_bits_high = 0;
+	t30->control_bits_low = 0;
+	t30->control_bits_high = 0;
+
+	if (chan->fax->nbc) {
+		/* set compression by DCC value */
+  	  switch(chan->fax->compression) {
+		case (0):	/* 1-D modified */
+			break;
+		case (1):	/* 2-D modified Read */
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+			break;
+		case (2):	/* 2-D uncompressed */
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+			t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+			break;
+		case (3):	/* 2-D modified Read */
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+			t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+			t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+			break;
+	  }
+	} else {
+		/* set compression to best */
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
+		t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
+		t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
+		t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
+		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+		t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+	}
+	switch(chan->fax->ecm) {
+		case (0):	/* disable ECM */
+			break;
+		case (1):
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+			t30->control_bits_low |= T30_CONTROL_BIT_ECM_64_BYTES;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM_64_BYTES;
+			break;
+		case (2):
+			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
+			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
+			break;
+	}
+
+	if (DebugVar & 128) {
+		char st[40];
+		eicon_log(NULL, 128, "sT30:code = %x\n", t30->code);
+		eicon_log(NULL, 128, "sT30:rate = %x\n", t30->rate);
+		eicon_log(NULL, 128, "sT30:res  = %x\n", t30->resolution);
+		eicon_log(NULL, 128, "sT30:format = %x\n", t30->format);
+		eicon_log(NULL, 128, "sT30:pages_low = %x\n", t30->pages_low);
+		eicon_log(NULL, 128, "sT30:pages_high = %x\n", t30->pages_high);
+		eicon_log(NULL, 128, "sT30:atf  = %x\n", t30->atf);
+		eicon_log(NULL, 128, "sT30:control_bits_low = %x\n", t30->control_bits_low);
+		eicon_log(NULL, 128, "sT30:control_bits_high = %x\n", t30->control_bits_high);
+		eicon_log(NULL, 128, "sT30:feature_bits_low = %x\n", t30->feature_bits_low);
+		eicon_log(NULL, 128, "sT30:feature_bits_high = %x\n", t30->feature_bits_high);
+		//eicon_log(NULL, 128, "sT30:universal_5 = %x\n", t30->universal_5);
+		//eicon_log(NULL, 128, "sT30:universal_6 = %x\n", t30->universal_6);
+		//eicon_log(NULL, 128, "sT30:universal_7 = %x\n", t30->universal_7);
+		eicon_log(NULL, 128, "sT30:station_id_len = %x\n", t30->station_id_len);
+		eicon_log(NULL, 128, "sT30:head_line_len = %x\n", t30->head_line_len);
+		strncpy(st, t30->station_id, t30->station_id_len);
+		st[t30->station_id_len] = 0;
+		eicon_log(NULL, 128, "sT30:station_id = <%s>\n", st);
+	}
+	return(sizeof(eicon_t30_s));
+}
+
+/* send fax struct */
+static int
+idi_send_edata(eicon_card *card, eicon_chan *chan)
+{
+	struct sk_buff *skb;
+	struct sk_buff *skb2;
+	eicon_REQ *reqbuf;
+	eicon_chan_ptr *chan2;
+
+	if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
+		eicon_log(card, 1, "idi_snd: Ch%d: send edata on state %d !\n", chan->No, chan->fsm_state);
+		return -ENODEV;
+	}
+	eicon_log(card, 128, "idi_snd: Ch%d: edata (fax)\n", chan->No);
+
+	skb = alloc_skb(sizeof(eicon_REQ) + sizeof(eicon_t30_s), GFP_ATOMIC);
+	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+	if ((!skb) || (!skb2)) {
+		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_edata()\n", chan->No);
+		if (skb) 
+			dev_kfree_skb(skb);
+		if (skb2) 
+			dev_kfree_skb(skb2);
+		return -ENOMEM;
+	}
+
+	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+	chan2->ptr = chan;
+
+	reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
+
+	reqbuf->Req = N_EDATA;
+	reqbuf->ReqCh = chan->e.IndCh;
+	reqbuf->ReqId = 1;
+
+	reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P);
+	reqbuf->Reference = 1; /* Net Entity */
+
+	skb_queue_tail(&chan->e.X, skb);
+	skb_queue_tail(&card->sndq, skb2);
+	eicon_tx_request(card);
+	return (0);
+}
+
+static void
+idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
+{
+	eicon_t30_s *p = (eicon_t30_s *)buffer;
+	int i;
+
+	if (DebugVar & 128) {
+		char st[40];
+		eicon_log(ccard, 128, "rT30:len %d , size %d\n", len, sizeof(eicon_t30_s));
+		eicon_log(ccard, 128, "rT30:code = %x\n", p->code);
+		eicon_log(ccard, 128, "rT30:rate = %x\n", p->rate);
+		eicon_log(ccard, 128, "rT30:res  = %x\n", p->resolution);
+		eicon_log(ccard, 128, "rT30:format = %x\n", p->format);
+		eicon_log(ccard, 128, "rT30:pages_low = %x\n", p->pages_low);
+		eicon_log(ccard, 128, "rT30:pages_high = %x\n", p->pages_high);
+		eicon_log(ccard, 128, "rT30:atf  = %x\n", p->atf);
+		eicon_log(ccard, 128, "rT30:control_bits_low = %x\n", p->control_bits_low);
+		eicon_log(ccard, 128, "rT30:control_bits_high = %x\n", p->control_bits_high);
+		eicon_log(ccard, 128, "rT30:feature_bits_low = %x\n", p->feature_bits_low);
+		eicon_log(ccard, 128, "rT30:feature_bits_high = %x\n", p->feature_bits_high);
+		//eicon_log(ccard, 128, "rT30:universal_5 = %x\n", p->universal_5);
+		//eicon_log(ccard, 128, "rT30:universal_6 = %x\n", p->universal_6);
+		//eicon_log(ccard, 128, "rT30:universal_7 = %x\n", p->universal_7);
+		eicon_log(ccard, 128, "rT30:station_id_len = %x\n", p->station_id_len);
+		eicon_log(ccard, 128, "rT30:head_line_len = %x\n", p->head_line_len);
+		strncpy(st, p->station_id, p->station_id_len);
+		st[p->station_id_len] = 0;
+		eicon_log(ccard, 128, "rT30:station_id = <%s>\n", st);
+	}
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_edata: parse to NULL fax struct, ERROR\n");
+		return;
+	}
+	chan->fax->code = p->code;
+	i = (p->station_id_len < FAXIDLEN) ? p->station_id_len : (FAXIDLEN - 1);
+	memcpy(chan->fax->r_id, p->station_id, i);
+	chan->fax->r_id[i] = 0;
+	chan->fax->r_resolution = p->resolution;
+	chan->fax->r_rate = p->rate - 1;
+	chan->fax->r_binary = 0; /* no binary support */
+	chan->fax->r_width = 0;
+	chan->fax->r_length = 2;
+	chan->fax->r_scantime = 0;
+	chan->fax->r_compression = 0;
+	chan->fax->r_ecm = 0;
+	if (p->feature_bits_low & T30_FEATURE_BIT_2D_CODING) {
+		chan->fax->r_compression = 1;
+		if (p->feature_bits_low & T30_FEATURE_BIT_UNCOMPR_ENABLED) {
+			chan->fax->r_compression = 2;
+		}
+	}
+	if (p->feature_bits_low & T30_FEATURE_BIT_T6_CODING) {
+		chan->fax->r_compression = 3;
+	}
+
+	if (p->feature_bits_low & T30_FEATURE_BIT_ECM) {
+		chan->fax->r_ecm = 2;
+		if (p->feature_bits_low & T30_FEATURE_BIT_ECM_64_BYTES)
+			chan->fax->r_ecm = 1;
+	}
+}
+
+static void
+idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
+{
+	static __u16 wd2sff[] = {
+		1728, 2048, 2432, 1216, 864
+	};
+	static __u16 ln2sff[2][3] = {
+		{ 1143, 1401, 0 } , { 2287, 2802, 0 }
+	};
+	struct sk_buff *skb;
+	eicon_sff_dochead *doc;
+	eicon_sff_pagehead *page;
+	u_char *docp;
+
+	if (!chan->fax) {
+		eicon_log(card, 1, "idi_fax: send head with NULL fax struct, ERROR\n");
+		return;
+	}
+	if (header == 2) { /* DocHeader + PageHeader */
+		skb = alloc_skb(sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+	} else {
+		skb = alloc_skb(sizeof(eicon_sff_pagehead), GFP_ATOMIC);
+	}
+	if (!skb) {
+		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_header()\n", chan->No);
+		return;
+	}
+
+	if (header == 2) { /* DocHeader + PageHeader */
+		docp = skb_put(skb, sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead));
+		doc = (eicon_sff_dochead *) docp;
+		page = (eicon_sff_pagehead *) (docp + sizeof(eicon_sff_dochead));
+		memset(docp, 0,sizeof(eicon_sff_dochead)  + sizeof(eicon_sff_pagehead));
+		doc->id = 0x66666653;
+		doc->version = 0x01;
+		doc->off1pagehead = sizeof(eicon_sff_dochead);
+	} else {
+		page = (eicon_sff_pagehead *)skb_put(skb, sizeof(eicon_sff_pagehead));
+		memset(page, 0, sizeof(eicon_sff_pagehead));
+	}
+
+	switch(header) {
+		case 1:	/* PageHeaderEnd */
+			page->pageheadid = 254;
+			page->pageheadlen = 0; 
+			break;
+		case 0: /* PageHeader */
+		case 2: /* DocHeader + PageHeader */
+			page->pageheadid = 254;
+			page->pageheadlen = sizeof(eicon_sff_pagehead) - 2;
+			page->resvert = chan->fax->resolution;
+			page->reshoriz = 0; /* always 203 dpi */
+			page->coding = 0; /* always 1D */
+			page->linelength = wd2sff[chan->fax->width];
+			page->pagelength = ln2sff[chan->fax->resolution][chan->fax->length]; 
+			eicon_log(card, 128, "sSFF-Head: linelength = %d\n", page->linelength);
+			eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
+			break;
+	}
+	idi_send_data(card, chan, 0, skb, 0, 0);
+}
+
+void
+idi_fax_cmd(eicon_card *card, eicon_chan *chan) 
+{
+	isdn_ctrl cmd;
+
+	if ((!card) || (!chan))
+		return;
+
+	if (!chan->fax) {
+		eicon_log(card, 1, "idi_fax: cmd with NULL fax struct, ERROR\n");
+		return;
+	}
+	switch (chan->fax->code) {
+		case ISDN_TTY_FAX_DT:
+			if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+				idi_send_edata(card, chan);
+				break;
+			}
+			if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+				idi_send_edata(card, chan);
+				break;
+			}
+			break;
+
+		case ISDN_TTY_FAX_DR:
+			if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+				idi_send_edata(card, chan);
+
+				cmd.driver = card->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_CFR;
+				card->interface.statcallb(&cmd);
+
+				cmd.driver = card->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_RID;
+				card->interface.statcallb(&cmd);
+
+				/* telling 1-D compression */
+				chan->fax->r_compression = 0;
+				cmd.driver = card->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_DCS;
+				card->interface.statcallb(&cmd);
+
+				chan->fax2.NextObject = FAX_OBJECT_DOCU;
+				chan->fax2.PrevObject = FAX_OBJECT_DOCU;
+
+				break;
+			}
+			if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+				idi_send_edata(card, chan);
+				break;
+			}
+			break;
+
+		case ISDN_TTY_FAX_ET:
+				switch(chan->fax->fet) {
+					case 0:
+					case 1:
+						idi_fax_send_header(card, chan, 0);
+						break;
+					case 2:
+						idi_fax_send_header(card, chan, 1);
+						break;
+				}
+			break;
+	}
+}
+
+static void
+idi_edata_rcveop(eicon_card *card, eicon_chan *chan)
+{
+	isdn_ctrl cmd;
+
+	if (!chan->fax) {
+		eicon_log(card, 1, "idi_edata: rcveop with NULL fax struct, ERROR\n");
+		return;
+	}
+	cmd.driver = card->myid;
+	cmd.command = ISDN_STAT_FAXIND;
+	cmd.arg = chan->No;
+	chan->fax->r_code = ISDN_TTY_FAX_ET;
+	card->interface.statcallb(&cmd);
+}
+
+static void
+idi_reset_fax_stat(eicon_chan *chan)
+{
+	chan->fax2.LineLen = 0;
+	chan->fax2.LineData = 0;
+	chan->fax2.LineDataLen = 0;
+	chan->fax2.NullByteExist = 0;
+	chan->fax2.Dle = 0;
+	chan->fax2.PageCount = 0;
+	chan->fax2.Eop = 0;
+}
+
+static void
+idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
+{
+	isdn_ctrl cmd;
+
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_edata: action with NULL fax struct, ERROR\n");
+		return;
+	}
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) {
+		idi_parse_edata(ccard, chan, buffer, len);
+
+		if (chan->fax->phase == ISDN_FAX_PHASE_A) {
+			idi_reset_fax_stat(chan);
+
+			chan->fsm_state = EICON_STATE_ACTIVE;
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_BCONN;
+			cmd.arg = chan->No;
+			strcpy(cmd.parm.num, "");
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_FCON;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_RID;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_DIS;
+			ccard->interface.statcallb(&cmd);
+
+			if (chan->fax->r_compression != 0) {
+			/* telling fake compression in second DIS message */
+				chan->fax->r_compression = 0;
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_DIS;
+				ccard->interface.statcallb(&cmd);
+			}
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_SENT; /* OK message */
+			ccard->interface.statcallb(&cmd);
+		} else
+		if (chan->fax->phase == ISDN_FAX_PHASE_D) {
+
+			if ((chan->fax->code == EDATA_T30_MCF) &&
+			    (chan->fax->fet != 2)) {
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_FAXIND;
+				cmd.arg = chan->No;
+				chan->fax->r_code = ISDN_TTY_FAX_PTS;
+				ccard->interface.statcallb(&cmd);
+			}
+
+			switch(chan->fax->fet) {
+				case 0:	/* new page */
+					/* stay in phase D , wait on cmd +FDT */
+					break;
+				case 1:	/* new document */
+					/* link-level switch to phase B */
+					break;
+				case 2:	/* session end */
+				default:
+					/* send_edata produces error on some */
+					/* fax-machines here, so we don't */
+					/* idi_send_edata(ccard, chan); */
+					break;
+			}
+		}
+	}
+
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+		idi_parse_edata(ccard, chan, buffer, len);
+
+		if ((chan->fax->code == EDATA_T30_DCS) &&
+		    (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+			idi_reset_fax_stat(chan);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_BCONN;
+			cmd.arg = chan->No;
+			strcpy(cmd.parm.num, "");
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_FCON_I;
+			ccard->interface.statcallb(&cmd);
+		} else
+		if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+		    (chan->fax->phase == ISDN_FAX_PHASE_A)) {
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_RID;
+			ccard->interface.statcallb(&cmd);
+
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+			ccard->interface.statcallb(&cmd);
+		} else
+		if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
+		    (chan->fax->phase == ISDN_FAX_PHASE_B)) {
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_FAXIND;
+			cmd.arg = chan->No;
+			chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
+			ccard->interface.statcallb(&cmd);
+		} else
+		if (chan->fax->phase == ISDN_FAX_PHASE_C) {
+			switch(chan->fax->code) {
+				case EDATA_T30_TRAIN_OK:
+					idi_send_edata(ccard, chan);
+					break;
+				case EDATA_T30_MPS:
+					chan->fax->fet = 0;
+					idi_edata_rcveop(ccard, chan);
+					break;
+				case EDATA_T30_EOM:
+					chan->fax->fet = 1;
+					idi_edata_rcveop(ccard, chan);
+					break;
+				case EDATA_T30_EOP:
+					chan->fax->fet = 2;
+					idi_edata_rcveop(ccard, chan);
+					break;
+			}
+		}
+	}
+}
+
+static void
+fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len)
+{
+	struct sk_buff *skb;
+	
+        skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC);
+	if (!skb) {
+		eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_put_rcv()\n", chan->No);
+		return;
+	}
+	skb_reserve(skb, MAX_HEADER_LEN);
+	memcpy(skb_put(skb, len), Data, len);
+	ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
+}
+
+static void
+idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
+{
+	eicon_OBJBUFFER InBuf;
+	eicon_OBJBUFFER LineBuf;
+	unsigned int Length = 0;
+	unsigned int aLength = 0;
+	unsigned int ObjectSize = 0;
+	unsigned int ObjHeadLen = 0;
+	unsigned int ObjDataLen = 0;
+	__u8 Recordtype;
+	__u8 PageHeaderLen;	
+	__u8 Event;
+	eicon_sff_pagehead *ob_page;
+
+	__u16 Cl2Eol = 0x8000;
+
+#	define EVENT_NONE	0
+#	define EVENT_NEEDDATA	1
+
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_fax: rcvdata with NULL fax struct, ERROR\n");
+		return;
+	}
+
+
+	
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+		InBuf.Data = skb->data;
+		InBuf.Size = skb->len;
+		InBuf.Len  = 0;
+		InBuf.Next = InBuf.Data;
+		LineBuf.Data = chan->fax2.abLine;
+		LineBuf.Size = sizeof(chan->fax2.abLine);
+		LineBuf.Len  = chan->fax2.LineLen;
+		LineBuf.Next = LineBuf.Data + LineBuf.Len;
+
+		Event = EVENT_NONE;
+		while (Event == EVENT_NONE) {
+			switch(chan->fax2.NextObject) {
+				case FAX_OBJECT_DOCU:
+						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+						if (Length < sizeof(eicon_sff_dochead)) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						ObjectSize = sizeof(eicon_sff_dochead);
+						Length = ObjectSize;
+						if (LineBuf.Len < Length) {
+							Length -= LineBuf.Len;
+							LineBuf.Len = 0;
+							LineBuf.Next = LineBuf.Data;
+							InBuf.Len += Length;
+							InBuf.Next += Length;
+						} else {
+							LineBuf.Len -= Length;
+							LineBuf.Next = LineBuf.Data + LineBuf.Len;
+							memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+						}
+						chan->fax2.PrevObject = FAX_OBJECT_DOCU;
+						chan->fax2.NextObject = FAX_OBJECT_PAGE;
+					break;
+
+				case FAX_OBJECT_PAGE:
+						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+						if (Length < 2) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						if (LineBuf.Len == 0) {
+							*LineBuf.Next++ = *InBuf.Next++;
+							LineBuf.Len++;
+							InBuf.Len++;
+						}
+						if (LineBuf.Len == 1) {
+							*LineBuf.Next++ = *InBuf.Next++;
+							LineBuf.Len++;
+							InBuf.Len++;
+						}
+						PageHeaderLen = *(LineBuf.Data + 1);
+						ObjectSize = (PageHeaderLen == 0) ? 2 : sizeof(eicon_sff_pagehead);
+						if (Length < ObjectSize) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						Length = ObjectSize;
+						/* extract page dimensions */
+						if (LineBuf.Len < Length) {
+							aLength = Length - LineBuf.Len;
+							memcpy(LineBuf.Next, InBuf.Next, aLength);
+							LineBuf.Next += aLength;
+							InBuf.Next += aLength;
+							LineBuf.Len += aLength;
+							InBuf.Len += aLength;
+						}
+						if (Length > 2) {
+							ob_page = (eicon_sff_pagehead *)LineBuf.Data;
+							switch(ob_page->linelength) {
+								case 2048:
+									chan->fax->r_width = 1;
+									break;
+								case 2432:
+									chan->fax->r_width = 2;
+									break;
+								case 1216:
+									chan->fax->r_width = 3;
+									break;
+								case 864:
+									chan->fax->r_width = 4;
+									break;
+								case 1728:
+								default:
+									chan->fax->r_width = 0;
+							}
+							switch(ob_page->pagelength) {
+								case 1143:
+								case 2287:
+									chan->fax->r_length = 0;
+									break;
+								case 1401:
+								case 2802:
+									chan->fax->r_length = 1;
+									break;
+								default:
+									chan->fax->r_length = 2;
+							}
+							eicon_log(ccard, 128, "rSFF-Head: linelength = %d\n", ob_page->linelength);
+							eicon_log(ccard, 128, "rSFF-Head: pagelength = %d\n", ob_page->pagelength);
+						}
+						LineBuf.Len -= Length;
+						LineBuf.Next = LineBuf.Data + LineBuf.Len;
+						memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+
+						chan->fax2.PrevObject = FAX_OBJECT_PAGE;
+						chan->fax2.NextObject = FAX_OBJECT_LINE;
+					break;
+
+				case FAX_OBJECT_LINE:
+						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
+						if (Length < 1) {
+							Event = EVENT_NEEDDATA;
+							break;
+						}
+						if (LineBuf.Len == 0) {
+							*LineBuf.Next++ = *InBuf.Next++;
+							LineBuf.Len++;
+							InBuf.Len++;
+						}
+						Recordtype = *LineBuf.Data;
+						if (Recordtype == 0) {
+							/* recordtype pixel row (2 byte length) */
+							ObjHeadLen = 3;
+							if (Length < ObjHeadLen) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+							while (LineBuf.Len < ObjHeadLen) {
+								*LineBuf.Next++ = *InBuf.Next++;
+								LineBuf.Len++;
+								InBuf.Len++;
+							}
+							ObjDataLen = *((__u16*) (LineBuf.Data + 1));
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							if (Length < ObjectSize) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+						} else
+						if ((Recordtype >= 1) && (Recordtype <= 216)) {
+							/* recordtype pixel row (1 byte length) */
+							ObjHeadLen = 1;
+							ObjDataLen = Recordtype;
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							if (Length < ObjectSize) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+						} else
+						if ((Recordtype >= 217) && (Recordtype <= 253)) {
+							/* recordtype empty lines */
+							ObjHeadLen = 1;
+							ObjDataLen = 0;
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							LineBuf.Len--;
+							LineBuf.Next = LineBuf.Data + LineBuf.Len;
+							memmove(LineBuf.Data, LineBuf.Data + 1, LineBuf.Len);
+							break;
+						} else
+						if (Recordtype == 254) {
+							/* recordtype page header */
+							chan->fax2.PrevObject = FAX_OBJECT_LINE;
+							chan->fax2.NextObject = FAX_OBJECT_PAGE;
+							break;
+						} else {
+							/* recordtype user information */
+							ObjHeadLen = 2;
+							if (Length < ObjHeadLen) {
+								Event = EVENT_NEEDDATA;
+								break;
+							}
+							while (LineBuf.Len < ObjHeadLen) {
+								*LineBuf.Next++ = *InBuf.Next++;
+								LineBuf.Len++;
+								InBuf.Len++;
+							}
+							ObjDataLen = *(LineBuf.Data + 1);
+							ObjectSize = ObjHeadLen + ObjDataLen;
+							if (ObjDataLen == 0) {
+								/* illegal line coding */
+								LineBuf.Len -= ObjHeadLen;
+								LineBuf.Next = LineBuf.Data + LineBuf.Len;
+								memmove(LineBuf.Data, LineBuf.Data + ObjHeadLen, LineBuf.Len);
+								break;
+							} else {
+								/* user information */
+								if (Length < ObjectSize) {
+									Event = EVENT_NEEDDATA;
+									break;
+								}
+								Length = ObjectSize;
+								if (LineBuf.Len < Length) {
+									Length -= LineBuf.Len;
+									LineBuf.Len = 0;
+									LineBuf.Next = LineBuf.Data;
+									InBuf.Len += Length;
+									InBuf.Next += Length;
+								} else {
+									LineBuf.Len -= Length;
+									LineBuf.Next = LineBuf.Data + LineBuf.Len;
+									memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
+								}
+							}
+							break;	
+						}
+						Length = ObjectSize;
+						if (LineBuf.Len > ObjHeadLen) {
+							fax_put_rcv(ccard, chan, LineBuf.Data + ObjHeadLen,
+									(LineBuf.Len - ObjHeadLen));
+						}
+						Length -= LineBuf.Len;
+						LineBuf.Len = 0;
+						LineBuf.Next = LineBuf.Data;
+						if (Length > 0) {
+							fax_put_rcv(ccard, chan, InBuf.Next, Length);
+							InBuf.Len += Length;
+							InBuf.Next += Length;
+						}
+						fax_put_rcv(ccard, chan, (__u8 *)&Cl2Eol, sizeof(Cl2Eol));
+					break;
+			} /* end of switch (chan->fax2.NextObject) */
+		} /* end of while (Event==EVENT_NONE) */
+		if (InBuf.Len < InBuf.Size) {
+			Length = InBuf.Size - InBuf.Len;
+			if ((LineBuf.Len + Length) > LineBuf.Size) {
+				eicon_log(ccard, 1, "idi_fax: Ch%d: %d bytes dropping, small buffer\n", chan->No,
+					Length);
+				} else {
+					memcpy(LineBuf.Next, InBuf.Next, Length);
+					LineBuf.Len += Length;
+				}
+		}
+		chan->fax2.LineLen = LineBuf.Len;
+	} else { /* CONN_OUT */
+		/* On CONN_OUT we do not need incoming data, drop it */
+		/* maybe later for polling */
+	}
+
+#	undef EVENT_NONE
+#	undef EVENT_NEEDDATA
+
+	return;
+}
+
+static int
+idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(OutBuf->Len, GFP_ATOMIC);
+	if (!skb) {
+		eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_outbuf()\n", chan->No);
+		return(-1);
+	}
+	memcpy(skb_put(skb, OutBuf->Len), OutBuf->Data, OutBuf->Len);
+
+	OutBuf->Len = 0;
+	OutBuf->Next = OutBuf->Data;
+
+	return(idi_send_data(ccard, chan, 0, skb, 1, 0));
+}
+
+int
+idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
+{
+	isdn_ctrl cmd;
+	eicon_OBJBUFFER InBuf;
+	__u8 InData;
+	__u8 InMask;
+	eicon_OBJBUFFER OutBuf;
+	eicon_OBJBUFFER LineBuf;
+	__u32 LineData;
+	unsigned int LineDataLen;
+	__u8 Byte;
+	__u8 Event;
+	int ret = 1;
+
+#	define EVENT_NONE	0
+#	define EVENT_EOD	1
+#	define EVENT_EOL 	2
+#	define EVENT_EOP 	3
+
+	if ((!ccard) || (!chan))
+		return -1;
+
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_fax: senddata with NULL fax struct, ERROR\n");
+		return -1;
+	}
+
+	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+		/* Simply ignore any data written in data mode when receiving a fax.    */
+		/* This is not completely correct because only XON's should come here.  */
+        	dev_kfree_skb(skb);
+		return 1;
+	}
+
+	if (chan->fax->phase != ISDN_FAX_PHASE_C) {
+        	dev_kfree_skb(skb);
+		return 1;
+	}
+
+        if (chan->queued + skb->len > 1200)
+                return 0;
+	if (chan->pqueued > 1)
+		return 0;
+
+	InBuf.Data = skb->data;
+	InBuf.Size = skb->len;
+	InBuf.Len  = 0;
+	InBuf.Next = InBuf.Data;
+	InData = 0;
+	InMask = 0;
+
+	LineBuf.Data = chan->fax2.abLine;
+	LineBuf.Size = sizeof(chan->fax2.abLine);
+	LineBuf.Len  = chan->fax2.LineLen;
+	LineBuf.Next = LineBuf.Data + LineBuf.Len;
+	LineData = chan->fax2.LineData;
+	LineDataLen = chan->fax2.LineDataLen;
+
+	OutBuf.Data = chan->fax2.abFrame;
+	OutBuf.Size = sizeof(chan->fax2.abFrame);
+	OutBuf.Len = 0;
+	OutBuf.Next = OutBuf.Data;
+
+	Event = EVENT_NONE;
+
+	chan->fax2.Eop = 0;
+
+	for (;;) {
+	  for (;;) {
+		if (InMask == 0) {
+			if (InBuf.Len >= InBuf.Size) {
+				Event = EVENT_EOD;
+				break;
+			}
+			if ((chan->fax2.Dle != _DLE_) && *InBuf.Next == _DLE_) {
+				chan->fax2.Dle = _DLE_;
+				InBuf.Next++;
+				InBuf.Len++;
+				if (InBuf.Len >= InBuf.Size) {
+					Event = EVENT_EOD;
+					break;
+				}
+			}
+			if (chan->fax2.Dle == _DLE_) {
+				chan->fax2.Dle = 0;
+				if (*InBuf.Next == _ETX_) {
+					Event = EVENT_EOP;
+					break;
+				} else
+				if (*InBuf.Next == _DLE_) {
+					/* do nothing */
+				} else {
+					eicon_log(ccard, 1,
+						"idi_err: Ch%d: unknown DLE escape %02x found\n",
+							chan->No, *InBuf.Next);
+					InBuf.Next++;
+					InBuf.Len++;
+					if (InBuf.Len >= InBuf.Size) {
+						Event = EVENT_EOD;
+						break;
+					}
+				}
+			}
+			InBuf.Len++;
+			InData = *InBuf.Next++;
+			InMask = (chan->fax->bor) ? 0x80 : 0x01;
+		}
+		while (InMask) {
+			LineData >>= 1;
+			LineDataLen++;
+			if (InData & InMask)
+				LineData |= 0x80000000;
+			if (chan->fax->bor)
+				InMask >>= 1;
+			else
+				InMask <<= 1;
+
+			if ((LineDataLen >= T4_EOL_BITSIZE) &&
+			   ((LineData & T4_EOL_MASK_DWORD) == T4_EOL_DWORD)) {
+				Event = EVENT_EOL;
+				if (LineDataLen > T4_EOL_BITSIZE) {
+					Byte = (__u8)
+						((LineData & ~T4_EOL_MASK_DWORD) >>
+						(32 - LineDataLen));
+					if (Byte == 0) {
+						if (! chan->fax2.NullByteExist) {
+							chan->fax2.NullBytesPos = LineBuf.Len;
+							chan->fax2.NullByteExist = 1;
+						}
+					} else {
+						chan->fax2.NullByteExist = 0;
+					}
+					if (LineBuf.Len < LineBuf.Size) {
+						*LineBuf.Next++  = Byte;
+						LineBuf.Len++;
+					}
+				}
+				LineDataLen = 0;
+				break;
+			}
+			if (LineDataLen >= T4_EOL_BITSIZE + 8) {
+				Byte = (__u8)
+					((LineData & ~T4_EOL_MASK_DWORD) >>
+					(32 - T4_EOL_BITSIZE - 8));
+				LineData &= T4_EOL_MASK_DWORD;
+				LineDataLen = T4_EOL_BITSIZE;
+				if (Byte == 0) {
+					if (! chan->fax2.NullByteExist) {
+						chan->fax2.NullBytesPos = LineBuf.Len;
+						chan->fax2.NullByteExist = 1;
+					}
+				} else {
+					chan->fax2.NullByteExist = 0;
+				}
+				if (LineBuf.Len < LineBuf.Size) {
+					*LineBuf.Next++  = Byte; 
+					LineBuf.Len++;
+				}
+			}
+		}
+		if (Event != EVENT_NONE)
+			break;
+	  }
+
+		if ((Event != EVENT_EOL) && (Event != EVENT_EOP))
+			break;
+
+		if ((Event == EVENT_EOP) && (LineDataLen > 0)) {
+			LineData >>= 32 - LineDataLen;
+			LineDataLen = 0;
+			while (LineData != 0) {
+				Byte = (__u8) LineData;
+				LineData >>= 8;
+				if (Byte == 0) {
+					if (! chan->fax2.NullByteExist) {
+						chan->fax2.NullBytesPos = LineBuf.Len;
+						chan->fax2.NullByteExist = 1;
+					}
+				} else {
+					chan->fax2.NullByteExist = 0;
+				}
+				if (LineBuf.Len < LineBuf.Size) {
+					*LineBuf.Next++  = Byte;
+					LineBuf.Len++;
+				}
+				
+			}
+		}
+		if (chan->fax2.NullByteExist) {
+			if (chan->fax2.NullBytesPos == 0) {
+				LineBuf.Len = 0;
+			} else {
+				LineBuf.Len = chan->fax2.NullBytesPos + 1;
+			}
+		}
+		if (LineBuf.Len > 0) {
+			if (OutBuf.Len + LineBuf.Len + SFF_LEN_FLD_SIZE > OutBuf.Size) {
+				ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+			}
+			if (LineBuf.Len <= 216) {
+				*OutBuf.Next++ = (__u8) LineBuf.Len;
+				OutBuf.Len++;
+			} else {
+				*OutBuf.Next++ = 0;
+				*((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len;
+				OutBuf.Len += 3;
+			}
+			memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len);
+			OutBuf.Next += LineBuf.Len;
+			OutBuf.Len  += LineBuf.Len;
+		}
+		LineBuf.Len = 0;
+		LineBuf.Next = LineBuf.Data;
+		chan->fax2.NullByteExist = 0;
+		if (Event == EVENT_EOP)
+			break;
+
+		Event = EVENT_NONE;
+	}
+
+	if (Event == EVENT_EOP) {
+		chan->fax2.Eop = 1;
+		chan->fax2.PageCount++;
+		cmd.driver = ccard->myid;
+		cmd.command = ISDN_STAT_FAXIND;
+		cmd.arg = chan->No;
+		chan->fax->r_code = ISDN_TTY_FAX_EOP;
+		ccard->interface.statcallb(&cmd);
+	}
+	if (OutBuf.Len > 0) {
+		ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
+	}
+
+	chan->fax2.LineLen = LineBuf.Len;
+	chan->fax2.LineData = LineData;
+	chan->fax2.LineDataLen = LineDataLen;
+
+#	undef EVENT_NONE
+#	undef EVENT_EOD
+#	undef EVENT_EOL
+#	undef EVENT_EOP
+
+	if (ret >= 0)
+	        dev_kfree_skb(skb);
+	if (ret == 0)
+		ret = 1;
+	return(ret);
+}
+
+static void
+idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
+{
+	isdn_ctrl cmd;
+
+	if (!chan->fax) {
+		eicon_log(ccard, 1, "idi_fax: hangup with NULL fax struct, ERROR\n");
+		return;
+	}
+	if ((chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) &&
+	    (chan->fax->code == 0)) {
+		cmd.driver = ccard->myid;
+		cmd.command = ISDN_STAT_FAXIND;
+		cmd.arg = chan->No;
+		chan->fax->r_code = ISDN_TTY_FAX_PTS;
+		ccard->interface.statcallb(&cmd);
+	}
+	if ((chan->fax->code > 1) && (chan->fax->code < 120))
+		chan->fax->code += 120;
+	eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code);
+	chan->fax->r_code = ISDN_TTY_FAX_HNG;
+	cmd.driver = ccard->myid;
+	cmd.command = ISDN_STAT_FAXIND;
+	cmd.arg = chan->No;
+	ccard->interface.statcallb(&cmd);
+}
+
+#endif	/******** FAX ********/
+
+static int
+idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int len)
+{
+	struct sk_buff *skb;
+	struct sk_buff *skb2;
+	eicon_REQ *reqbuf;
+	eicon_chan_ptr *chan2;
+
+	if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
+		eicon_log(card, 1, "idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
+		return -ENODEV;
+	}
+	eicon_log(card, 8, "idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
+			UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
+
+	skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC);
+	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+	if ((!skb) || (!skb2)) {
+		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
+		if (skb) 
+			dev_kfree_skb(skb);
+		if (skb2) 
+			dev_kfree_skb(skb2);
+		return -ENOMEM;
+	}
+
+	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+	chan2->ptr = chan;
+
+	reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
+
+	reqbuf->Req = N_UDATA;
+	reqbuf->ReqCh = chan->e.IndCh;
+	reqbuf->ReqId = 1;
+
+	reqbuf->XBuffer.length = len + 1;
+	reqbuf->XBuffer.P[0] = UReq;
+	memcpy(&reqbuf->XBuffer.P[1], buffer, len);
+	reqbuf->Reference = 1; /* Net Entity */
+
+	skb_queue_tail(&chan->e.X, skb);
+	skb_queue_tail(&card->sndq, skb2);
+	eicon_tx_request(card);
+	return (0);
+}
+
+void
+idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value)
+{
+	u_char buf[6];
+	struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf;
+
+	if ((!ccard) || (!chan))
+		return;
+
+	memset(buf, 0, 6);
+	switch(cmd) {
+		case ISDN_AUDIO_SETDD:
+			if (value[0]) {
+				dtmf_buf->tone = (__u16) (value[1] * 5);
+				dtmf_buf->gap = (__u16) (value[1] * 5);
+				idi_send_udata(ccard, chan,
+					DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER,
+					buf, 4);
+			} else {
+				idi_send_udata(ccard, chan,
+					DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER,
+					buf, 0);
+			}
+			break;
+	}
+}
+
+static void
+idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
+{
+	isdn_ctrl cmd;
+	eicon_dsp_ind *p = (eicon_dsp_ind *) (&buffer[1]);
+        static char *connmsg[] =
+        {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34",
+         "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90",
+         "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17", "V.32", "K56Flex",
+         "X2", "V.18", "V.18LH", "V.18HL", "V.21LH", "V.21HL",
+         "Bell 103LH", "Bell 103HL", "V.23", "V.23", "EDT 110",
+         "Baudot45", "Baudot47", "Baudot50", "DTMF" };
+	static u_char dtmf_code[] = {
+	'1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
+	};
+
+	if ((!ccard) || (!chan))
+		return;
+
+	switch (buffer[0]) {
+		case DSP_UDATA_INDICATION_SYNC:
+			eicon_log(ccard, 16, "idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
+			break;
+		case DSP_UDATA_INDICATION_DCD_OFF:
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
+			break;
+		case DSP_UDATA_INDICATION_DCD_ON:
+			if ((chan->l2prot == ISDN_PROTO_L2_MODEM) &&
+			   ((chan->fsm_state == EICON_STATE_IBWAIT) ||
+			    (chan->fsm_state == EICON_STATE_WMCONN))) {
+				chan->fsm_state = EICON_STATE_ACTIVE;
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_BCONN;
+				cmd.arg = chan->No;
+                                if (p->norm > 34) {
+                                  sprintf(cmd.parm.num, "%d/(%d)", p->speed, p->norm);
+                                } else {
+                                  sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
+                                }
+				ccard->interface.statcallb(&cmd);
+			}
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+				p->norm, p->options, p->speed, p->delay); 
+			break;
+		case DSP_UDATA_INDICATION_CTS_OFF:
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
+			break;
+		case DSP_UDATA_INDICATION_CTS_ON:
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
+			eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+				p->norm, p->options, p->speed, p->delay); 
+			break;
+		case DSP_UDATA_INDICATION_DISCONNECT:
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
+			break;
+		case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED:
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
+				dtmf_code[buffer[1]]);
+			cmd.driver = ccard->myid;
+			cmd.command = ISDN_STAT_AUDIO;
+			cmd.parm.num[0] = ISDN_AUDIO_DTMF;
+			cmd.parm.num[1] = dtmf_code[buffer[1]];
+			cmd.arg = chan->No;
+			ccard->interface.statcallb(&cmd);
+			break;
+		default:
+			eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
+	}
+}
+
+static void
+eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len)
+{
+	int i,j,n;
+	int buflen = len * 3 + 30;
+	char *p;
+	struct trace_s {
+		unsigned long time;
+		unsigned short size;
+		unsigned short code;
+		unsigned char data[1];
+	} *q;
+
+	if (!(p = kmalloc(buflen, GFP_ATOMIC))) {
+		eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n");
+		return;
+	}
+	memset(p, 0, buflen);
+	q = (struct trace_s *)buffer;
+
+	if (DebugVar & 512) {
+		if ((q->code == 3) || (q->code == 4)) {
+			n = (short) *(q->data);
+			if (n) {
+				j = sprintf(p, "DTRC:");
+				for (i = 0; i < n; i++) {
+					j += sprintf(p + j, "%02x ", q->data[i+2]);
+				}
+				j += sprintf(p + j, "\n");
+			}
+		}
+	} else {
+		j = sprintf(p, "XLOG: %lx %04x %04x ",
+			q->time, q->size, q->code);
+
+		for (i = 0; i < q->size; i++) {
+			j += sprintf(p + j, "%02x ", q->data[i]);
+		}
+		j += sprintf(p + j, "\n");
+	}
+	if (strlen(p))
+		eicon_putstatus(ccard, p);
+	kfree(p);
+}
+
+void
+idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
+{
+	int tmp;
+	char tnum[64];
+	int dlev;
+	int free_buff;
+  eicon_IND *ind = (eicon_IND *)skb->data;
+	eicon_chan *chan;
+	idi_ind_message message;
+	isdn_ctrl cmd;
+
+	if (!ccard) {
+		eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ind\n");
+  		dev_kfree_skb(skb);
+		return;
+	}
+
+	if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+		eicon_log(ccard, 1, "idi_err: Ch??: null chan in handle_ind\n");
+  		dev_kfree_skb(skb);
+		return;
+	}
+	
+	if ((ind->Ind != 8) && (ind->Ind != 0xc))
+		dlev = 144;
+	else
+		dlev = 128;
+
+       	eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%x Id=%x Ch=%x MInd=%x MLen=%x Len=%x\n", chan->No,
+	        ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
+
+	free_buff = 1;
+	/* Signal Layer */
+	if (chan->e.D3Id == ind->IndId) {
+		idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
+		switch(ind->Ind) {
+			case HANGUP:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Hangup\n", chan->No);
+		    skb_queue_purge(&chan->e.X);
+				chan->queued = 0;
+				chan->pqueued = 0;
+				chan->waitq = 0;
+				chan->waitpq = 0;
+				if (message.e_cau[0] & 0x7f) {
+					cmd.driver = ccard->myid;
+					cmd.arg = chan->No;
+					sprintf(cmd.parm.num,"E%02x%02x", 
+						chan->cause[0]&0x7f, message.e_cau[0]&0x7f); 
+					cmd.command = ISDN_STAT_CAUSE;
+					ccard->interface.statcallb(&cmd);
+				}
+				chan->cause[0] = 0; 
+				if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
+				    ((chan->l2prot == ISDN_PROTO_L2_FAX) &&
+				    (chan->fsm_state == EICON_STATE_OBWAIT))) {
+					chan->fsm_state = EICON_STATE_NULL;
+				} else {
+					if (chan->e.B2Id)
+						idi_do_req(ccard, chan, REMOVE, 1);
+					chan->statectrl &= ~WAITING_FOR_HANGUP;
+					chan->statectrl &= ~IN_HOLD;
+					if (chan->statectrl & HAVE_CONN_REQ) {
+						eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No);
+						chan->statectrl &= ~HAVE_CONN_REQ;
+						if ((chan->tskb1) && (chan->tskb2)) {
+							skb_queue_tail(&chan->e.X, chan->tskb1);
+							skb_queue_tail(&ccard->sndq, chan->tskb2); 
+						}
+						chan->tskb1 = NULL;
+						chan->tskb2 = NULL;
+					} else {
+						chan->fsm_state = EICON_STATE_NULL;
+						cmd.driver = ccard->myid;
+						cmd.arg = chan->No;
+						cmd.command = ISDN_STAT_DHUP;
+						ccard->interface.statcallb(&cmd);
+						eicon_idi_listen_req(ccard, chan);
+#ifdef CONFIG_ISDN_TTY_FAX
+						chan->fax = 0;
+#endif
+					}
+				}
+				break;
+			case INDICATE_IND:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+				if (chan->fsm_state != EICON_STATE_LISTEN) {
+					eicon_log(ccard, 1, "idi_err: Ch%d: Incoming call on wrong state (%d).\n",
+						chan->No, chan->fsm_state);
+					idi_do_req(ccard, chan, HANGUP, 0);
+					break;
+				}
+				chan->fsm_state = EICON_STATE_ICALL;
+				idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2);
+				strcpy(chan->cpn, message.cpn + 1);
+				strcpy(chan->oad, message.oad);
+				strcpy(chan->dsa, message.dsa);
+				strcpy(chan->osa, message.osa);
+				chan->plan = message.plan;
+				chan->screen = message.screen;
+				try_stat_icall_again: 
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_ICALL;
+				cmd.arg = chan->No;
+				cmd.parm.setup.si1 = chan->si1;
+				cmd.parm.setup.si2 = chan->si2;
+				strcpy(tnum, chan->cpn);
+				if (strlen(chan->dsa)) {
+					strcat(tnum, ".");
+					strcat(tnum, chan->dsa);
+				}
+				tnum[ISDN_MSNLEN - 1] = 0;
+				strcpy(cmd.parm.setup.eazmsn, tnum);
+				strcpy(tnum, chan->oad);
+				if (strlen(chan->osa)) {
+					strcat(tnum, ".");
+					strcat(tnum, chan->osa);
+				}
+				tnum[ISDN_MSNLEN - 1] = 0;
+				strcpy(cmd.parm.setup.phone, tnum);
+				cmd.parm.setup.plan = chan->plan;
+				cmd.parm.setup.screen = chan->screen;
+				tmp = ccard->interface.statcallb(&cmd);
+				switch(tmp) {
+					case 0: /* no user responding */
+						idi_do_req(ccard, chan, HANGUP, 0);
+						chan->fsm_state = EICON_STATE_NULL;
+						break;
+					case 1: /* alert */
+						eicon_log(ccard, 8, "idi_req: Ch%d: Call Alert\n", chan->No);
+						if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) {
+							chan->fsm_state = EICON_STATE_ICALL;
+							idi_do_req(ccard, chan, CALL_ALERT, 0);
+						}
+						break;
+					case 2: /* reject */
+						eicon_log(ccard, 8, "idi_req: Ch%d: Call Reject\n", chan->No);
+						idi_do_req(ccard, chan, REJECT, 0);
+						break;
+					case 3: /* incomplete number */
+						eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No);
+						chan->fsm_state = EICON_STATE_ICALLW;
+						break;
+				}
+				break;
+			case INFO_IND:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Info_Ind\n", chan->No);
+				if ((chan->fsm_state == EICON_STATE_ICALLW) &&
+				    (message.cpn[0])) {
+					strcat(chan->cpn, message.cpn + 1);
+					goto try_stat_icall_again;
+				}
+				break;
+			case CALL_IND:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Ind\n", chan->No);
+				if ((chan->fsm_state == EICON_STATE_ICALL) ||
+                                     (chan->fsm_state == EICON_STATE_WMCONN) ||
+                                     (chan->fsm_state == EICON_STATE_IWAIT)) {
+					chan->fsm_state = EICON_STATE_IBWAIT;
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_DCONN;
+					cmd.arg = chan->No;
+					ccard->interface.statcallb(&cmd);
+					switch(chan->l2prot) {
+						case ISDN_PROTO_L2_FAX:
+#ifdef CONFIG_ISDN_TTY_FAX
+							if (chan->fax)
+								chan->fax->phase = ISDN_FAX_PHASE_A;
+#endif
+							break;
+						case ISDN_PROTO_L2_MODEM:
+							/* do nothing, wait for connect */
+							break;
+						case ISDN_PROTO_L2_V11096:
+						case ISDN_PROTO_L2_V11019:
+						case ISDN_PROTO_L2_V11038:
+						case ISDN_PROTO_L2_TRANS:
+							idi_do_req(ccard, chan, N_CONNECT, 1);
+							break;
+						default:
+							/* On most incoming calls we use automatic connect */
+							/* idi_do_req(ccard, chan, N_CONNECT, 1); */
+							break;
+					}
+				} else {
+					if (chan->fsm_state != EICON_STATE_ACTIVE)
+						idi_hangup(ccard, chan);
+				}
+				break;
+			case CALL_CON:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
+				if (chan->fsm_state == EICON_STATE_OCALL) {
+					/* check if old NetID has been removed */
+					if (chan->e.B2Id) {
+						eicon_log(ccard, 1, "idi_ind: Ch%d: old net_id %x still exist, removing.\n",
+							chan->No, chan->e.B2Id);
+						idi_do_req(ccard, chan, REMOVE, 1);
+					}
+#ifdef CONFIG_ISDN_TTY_FAX
+					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+						if (chan->fax) {
+							chan->fax->phase = ISDN_FAX_PHASE_A;
+						} else {
+							eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n");
+							idi_hangup(ccard, chan);
+							break;
+						}
+					}
+#endif
+					chan->fsm_state = EICON_STATE_OBWAIT;
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_DCONN;
+					cmd.arg = chan->No;
+					ccard->interface.statcallb(&cmd);
+
+					idi_do_req(ccard, chan, ASSIGN, 1); 
+					idi_do_req(ccard, chan, N_CONNECT, 1);
+				} else
+					idi_hangup(ccard, chan);
+				break;
+			case AOC_IND:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
+				break;
+			case CALL_HOLD_ACK:
+				chan->statectrl |= IN_HOLD;
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No);
+				break;
+			case SUSPEND_REJ:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No);
+				break;
+			case SUSPEND:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No);
+				break;
+			case RESUME:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No);
+				break;
+			default:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
+		}
+	}
+	/* Network Layer */
+	else if (chan->e.B2Id == ind->IndId) {
+
+		if (chan->No == ccard->nchannels) {
+			/* Management Indication */
+			if (ind->Ind == 0x04) { /* Trace_Ind */
+				eicon_parse_trace(ccard, ind->RBuffer.P, ind->RBuffer.length);
+			} else {
+				idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
+				chan->fsm_state = 1;
+			}
+		} 
+		else
+		switch(ind->Ind) {
+			case N_CONNECT_ACK:
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
+				if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
+					chan->fsm_state = EICON_STATE_WMCONN;
+					break;
+				}
+				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+#ifdef CONFIG_ISDN_TTY_FAX
+					chan->fsm_state = EICON_STATE_ACTIVE;
+					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+					if (chan->fax) {
+						if (chan->fax->phase == ISDN_FAX_PHASE_B) {
+							idi_fax_send_header(ccard, chan, 2);
+							cmd.driver = ccard->myid;
+							cmd.command = ISDN_STAT_FAXIND;
+							cmd.arg = chan->No;
+							chan->fax->r_code = ISDN_TTY_FAX_DCS;
+							ccard->interface.statcallb(&cmd);
+						}
+					}
+					else {
+						eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n");
+					}
+#endif
+					break;
+				}
+				chan->fsm_state = EICON_STATE_ACTIVE;
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_BCONN;
+				cmd.arg = chan->No;
+				strcpy(cmd.parm.num, "64000");
+				ccard->interface.statcallb(&cmd);
+				break; 
+			case N_CONNECT:
+				eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
+				chan->e.IndCh = ind->IndCh;
+				if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1);
+				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+					break;
+				}
+				if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
+					chan->fsm_state = EICON_STATE_WMCONN;
+					break;
+				}
+				chan->fsm_state = EICON_STATE_ACTIVE;
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_BCONN;
+				cmd.arg = chan->No;
+				strcpy(cmd.parm.num, "64000");
+				ccard->interface.statcallb(&cmd);
+				break; 
+			case N_DISC:
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No);
+				if (chan->e.B2Id) {
+		      skb_queue_purge(&chan->e.X);
+					idi_do_req(ccard, chan, N_DISC_ACK, 1);
+					idi_do_req(ccard, chan, REMOVE, 1);
+				}
+#ifdef CONFIG_ISDN_TTY_FAX
+				if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){
+					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+					idi_fax_hangup(ccard, chan);
+				}
+#endif
+				chan->e.IndCh = 0;
+				chan->queued = 0;
+				chan->pqueued = 0;
+				chan->waitq = 0;
+				chan->waitpq = 0;
+				if (!(chan->statectrl & IN_HOLD)) {
+					idi_do_req(ccard, chan, HANGUP, 0);
+				}
+				if (chan->fsm_state == EICON_STATE_ACTIVE) {
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_BHUP;
+					cmd.arg = chan->No;
+					ccard->interface.statcallb(&cmd);
+					chan->fsm_state = EICON_STATE_NULL;
+					if (!(chan->statectrl & IN_HOLD)) {
+						chan->statectrl |= WAITING_FOR_HANGUP;
+					}
+				}
+#ifdef CONFIG_ISDN_TTY_FAX
+				chan->fax = 0;
+#endif
+				break; 
+			case N_DISC_ACK:
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No);
+#ifdef CONFIG_ISDN_TTY_FAX
+				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+					idi_fax_hangup(ccard, chan);
+				}
+#endif
+				break; 
+			case N_DATA_ACK:
+				eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No);
+				break;
+			case N_DATA:
+				skb_pull(skb, sizeof(eicon_IND) - 1);
+				eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
+				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+#ifdef CONFIG_ISDN_TTY_FAX
+					idi_faxdata_rcv(ccard, chan, skb);
+#endif
+				} else {
+					ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
+					free_buff = 0; 
+				}
+				break; 
+			case N_UDATA:
+				idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+				break; 
+#ifdef CONFIG_ISDN_TTY_FAX
+			case N_EDATA:
+				idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+				break; 
+#endif
+			default:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
+		}
+	}
+	else {
+		eicon_log(ccard, 1, "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
+	}
+   if (free_buff)
+	dev_kfree_skb(skb);
+}
+
+static int
+idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
+{
+  isdn_ctrl cmd;
+  int tqueued = 0;
+  int twaitpq = 0;
+
+	if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
+		/* I dont know why this happens, should not ! */
+		/* just ignoring this RC */
+		eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, 
+			ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
+		return 1;
+	}
+
+	/* Management Interface */	
+	if (chan->No == ccard->nchannels) {
+		/* Managementinterface: changing state */
+		if (chan->e.Req != 0x02)
+			chan->fsm_state = 1;
+	}
+
+	/* Remove an Id */
+	if (chan->e.Req == REMOVE) {
+		if (ack->Reference != chan->e.ref) {
+			/* This should not happen anymore */
+			eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
+				ack->Reference, chan->e.ref);
+		}
+		ccard->IdTable[ack->RcId] = NULL;
+		if (!chan->e.ReqCh) 
+			chan->e.D3Id = 0;
+		else
+			chan->e.B2Id = 0;
+		eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+			ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
+		return 1;
+	}
+
+	/* Signal layer */
+	if (!chan->e.ReqCh) {
+		eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+			ack->RcId, ack->RcCh, ack->Reference);
+	} else {
+	/* Network layer */
+		switch(chan->e.Req & 0x0f) {
+			case N_CONNECT:
+				chan->e.IndCh = ack->RcCh;
+				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+					ack->RcId, ack->RcCh, ack->Reference);
+				break;
+			case N_MDATA:
+			case N_DATA:
+				tqueued = chan->queued;
+				twaitpq = chan->waitpq;
+				if ((chan->e.Req & 0x0f) == N_DATA) {
+					chan->waitpq = 0;
+					if(chan->pqueued)
+						chan->pqueued--;
+#ifdef CONFIG_ISDN_TTY_FAX
+					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+						if (((chan->queued - chan->waitq) < 1) &&
+						    (chan->fax2.Eop)) {
+							chan->fax2.Eop = 0;
+							if (chan->fax) {
+								cmd.driver = ccard->myid;
+								cmd.command = ISDN_STAT_FAXIND;
+								cmd.arg = chan->No;
+								chan->fax->r_code = ISDN_TTY_FAX_SENT;
+								ccard->interface.statcallb(&cmd);
+							}
+							else {
+								eicon_log(ccard, 1, "idi_ack: Sent with NULL fax struct, ERROR\n");
+							}
+						}
+					}
+#endif
+				}
+				chan->queued -= chan->waitq;
+				if (chan->queued < 0) chan->queued = 0;
+				if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) {
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_BSENT;
+					cmd.arg = chan->No;
+					cmd.parm.length = twaitpq;
+					ccard->interface.statcallb(&cmd);
+				}
+				break;
+			default:
+				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+					ack->RcId, ack->RcCh, ack->Reference);
+		}
+	}
+	return 1;
+}
+
+void
+idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
+{
+	int j;
+        eicon_RC *ack = (eicon_RC *)skb->data;
+	eicon_chan *chan;
+	isdn_ctrl cmd;
+	int dCh = -1;
+
+	if (!ccard) {
+		eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ack\n");
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	if ((chan = ccard->IdTable[ack->RcId]) != NULL)
+		dCh = chan->No;
+
+	switch (ack->Rc) {
+		case OK_FC:
+		case N_FLOW_CONTROL:
+		case ASSIGN_RC:
+			eicon_log(ccard, 1, "idi_ack: Ch%d: unhandled RC 0x%x\n",
+				dCh, ack->Rc);
+			break;
+		case READY_INT:
+		case TIMER_INT:
+			/* we do nothing here */
+			break;
+
+		case OK:
+			if (!chan) {
+				eicon_log(ccard, 1, "idi_ack: Ch%d: OK on chan without Id\n", dCh);
+				break;
+			}
+			if (!idi_handle_ack_ok(ccard, chan, ack))
+				chan = NULL;
+			break;
+
+		case ASSIGN_OK:
+			if (chan) {
+				eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
+					chan->No, chan->e.D3Id, chan->e.B2Id);
+			}
+			for(j = 0; j < ccard->nchannels + 1; j++) {
+				if ((ccard->bch[j].e.ref == ack->Reference) &&
+					(ccard->bch[j].e.Req == ASSIGN)) {
+					if (!ccard->bch[j].e.ReqCh) 
+						ccard->bch[j].e.D3Id  = ack->RcId;
+					else
+						ccard->bch[j].e.B2Id  = ack->RcId;
+					ccard->IdTable[ack->RcId] = &ccard->bch[j];
+					chan = &ccard->bch[j];
+					break;
+				}
+			}
+			eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
+				ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
+			if (j > ccard->nchannels) {
+				eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", 
+					ack->Reference, ack->RcId);
+			}
+			break;
+
+		case OUT_OF_RESOURCES:
+		case UNKNOWN_COMMAND:
+		case WRONG_COMMAND:
+		case WRONG_ID:
+		case 0x08:  /* ADAPTER_DEAD */ 
+		case WRONG_CH:
+		case UNKNOWN_IE:
+		case WRONG_IE:
+		default:
+			if (!chan) {
+				eicon_log(ccard, 1, "idi_ack: Ch%d: Not OK !! on chan without Id\n", dCh);
+				break;
+			} else
+			switch (chan->e.Req) {
+				case 12:	/* Alert */
+					eicon_log(ccard, 2, "idi_err: Ch%d: Alert Not OK : Rc=%d Id=%x Ch=%d\n",
+						dCh, ack->Rc, ack->RcId, ack->RcCh);
+					break;
+				default:
+					if (dCh != ccard->nchannels)
+						eicon_log(ccard, 1, "idi_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+							dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
+			}
+			if (dCh == ccard->nchannels) { /* Management */
+				chan->fsm_state = 2;
+				eicon_log(ccard, 8, "idi_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
+					dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
+			} else if (dCh >= 0) {
+					/* any other channel */
+					/* card reports error: we hangup */
+				idi_hangup(ccard, chan);
+				cmd.driver = ccard->myid;
+				cmd.command = ISDN_STAT_DHUP;
+				cmd.arg = chan->No;
+				ccard->interface.statcallb(&cmd);
+			}
+	}
+	if (chan) {
+		chan->e.ref = 0;
+		chan->e.busy = 0;
+	}
+	dev_kfree_skb(skb);
+}
+
+int
+idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk)
+{
+        struct sk_buff *xmit_skb;
+        struct sk_buff *skb2;
+        eicon_REQ *reqbuf;
+        eicon_chan_ptr *chan2;
+        int len, plen = 0, offset = 0;
+
+	if ((!card) || (!chan)) {
+		eicon_log(card, 1, "idi_err: Ch??: null card/chan in send_data\n");
+		return -1;
+	}
+
+        if (chan->fsm_state != EICON_STATE_ACTIVE) {
+		eicon_log(card, 1, "idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
+                return -ENODEV;
+	}
+
+        len = skb->len;
+	if (len > EICON_MAX_QUEUE)	/* too much for the shared memory */
+		return -1;
+        if (!len)
+                return 0;
+
+	if ((chk) && (chan->pqueued > 1))
+		return 0;
+
+	eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n",
+		chan->No, len, chan->pqueued);
+	while(offset < len) {
+
+		plen = ((len - offset) > 270) ? 270 : len - offset;
+
+	        xmit_skb = alloc_skb(plen + sizeof(eicon_REQ), GFP_ATOMIC);
+        	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+	        if ((!xmit_skb) || (!skb2)) {
+        	        eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
+			if (xmit_skb) 
+				dev_kfree_skb(skb);
+			if (skb2) 
+				dev_kfree_skb(skb2);
+                	return -ENOMEM;
+	        }
+
+	        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+        	chan2->ptr = chan;
+
+	        reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
+		if ((len - offset) > 270) {
+		        reqbuf->Req = N_MDATA;
+		} else {
+		        reqbuf->Req = N_DATA;
+			/* if (ack) reqbuf->Req |= N_D_BIT; */
+		}	
+        	reqbuf->ReqCh = chan->e.IndCh;
+	        reqbuf->ReqId = 1;
+		memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen);
+		reqbuf->XBuffer.length = plen;
+		reqbuf->Reference = 1; /* Net Entity */
+
+		skb_queue_tail(&chan->e.X, xmit_skb);
+		skb_queue_tail(&card->sndq, skb2); 
+
+		offset += plen;
+	}
+	if (que) {
+		chan->queued += len;
+		chan->pqueued++;
+	}
+	eicon_tx_request(card);
+        dev_kfree_skb(skb);
+        return len;
+}
+
+
+static int
+eicon_idi_manage_assign(eicon_card *card)
+{
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+        eicon_REQ  *reqbuf;
+        eicon_chan     *chan;
+        eicon_chan_ptr *chan2;
+
+        chan = &(card->bch[card->nchannels]);
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+		eicon_log(card, 1, "idi_err: alloc_skb failed in manage_assign()\n");
+		if (skb) 
+			dev_kfree_skb(skb);
+		if (skb2) 
+			dev_kfree_skb(skb2);
+                return -ENOMEM;
+        }
+
+        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+        chan2->ptr = chan;
+
+        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+
+        reqbuf->XBuffer.P[0] = 0;
+        reqbuf->Req = ASSIGN;
+        reqbuf->ReqCh = 0;
+        reqbuf->ReqId = MAN_ID;
+        reqbuf->XBuffer.length = 1;
+        reqbuf->Reference = 2; /* Man Entity */
+
+        skb_queue_tail(&chan->e.X, skb);
+        skb_queue_tail(&card->sndq, skb2);
+        eicon_tx_request(card);
+        return(0);
+}
+
+int
+eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
+{
+	int l = 0;
+	int ret = 0;
+	int timeout;
+	int i;
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+        eicon_REQ  *reqbuf;
+        eicon_chan     *chan;
+        eicon_chan_ptr *chan2;
+
+        chan = &(card->bch[card->nchannels]);
+
+	if (!(chan->e.D3Id)) {
+		chan->e.D3Id = 1;
+		skb_queue_purge(&chan->e.X);
+		chan->e.busy = 0;
+ 
+		if ((ret = eicon_idi_manage_assign(card))) {
+			chan->e.D3Id = 0;
+			return(ret); 
+		}
+
+	        timeout = jiffies + 50;
+        	while (timeout > jiffies) {
+	                if (chan->e.B2Id) break;
+        	        SLEEP(10);
+	        }
+	        if (!chan->e.B2Id) {
+			chan->e.D3Id = 0;
+			return -EIO;
+		}
+	}
+
+	chan->fsm_state = 0;
+
+	if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
+               	eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n");
+		return -ENOMEM;
+	}
+	if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) {
+		kfree(manbuf);
+		return -EFAULT;
+	}
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               	eicon_log(card, 1, "idi_err_manif: alloc_skb failed in manage()\n");
+		if (skb) 
+			dev_kfree_skb(skb);
+		if (skb2) 
+			dev_kfree_skb(skb2);
+		kfree(manbuf);
+                return -ENOMEM;
+        }
+
+        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+        chan2->ptr = chan;
+
+        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+
+        reqbuf->XBuffer.P[l++] = ESC;
+        reqbuf->XBuffer.P[l++] = 6;
+        reqbuf->XBuffer.P[l++] = 0x80;
+	for (i = 0; i < manbuf->length[0]; i++)
+	        reqbuf->XBuffer.P[l++] = manbuf->data[i];
+        reqbuf->XBuffer.P[1] = manbuf->length[0] + 1;
+
+        reqbuf->XBuffer.P[l++] = 0;
+        reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ;
+        reqbuf->ReqCh = 0;
+        reqbuf->ReqId = 1;
+        reqbuf->XBuffer.length = l;
+        reqbuf->Reference = 2; /* Man Entity */
+
+        skb_queue_tail(&chan->e.X, skb);
+        skb_queue_tail(&card->sndq, skb2);
+
+	manbuf->count = 0;
+	manbuf->pos = 0;
+
+        eicon_tx_request(card);
+
+        timeout = jiffies + 50;
+        while (timeout > jiffies) {
+                if (chan->fsm_state) break;
+                SLEEP(10);
+        }
+        if ((!chan->fsm_state) || (chan->fsm_state == 2)) {
+		kfree(manbuf);
+		return -EIO;
+	}
+	if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) {
+		kfree(manbuf);
+		return -EFAULT;
+	}
+
+	kfree(manbuf);
+  return(0);
+}
diff -Nru a/drivers/isdn/hardware/eicon/i4l_idi.h b/drivers/isdn/hardware/eicon/i4l_idi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/i4l_idi.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,381 @@
+/* $Id: i4l_idi.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards.
+ * I4L - IDI Interface
+ *
+ * Copyright 1998-2000  by Armin Schindler (mac@melware.de)
+ * Copyright 1999-2002  Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef E_IDI_H
+#define E_IDI_H
+
+#include <linux/config.h>
+
+#undef N_DATA
+#undef ID_MASK
+
+#include "pc.h"
+
+#define AOC_IND  26		/* Advice of Charge                         */
+#define PI  0x1e                /* Progress Indicator               */
+#define NI  0x27                /* Notification Indicator           */
+
+/* defines for statectrl */
+#define WAITING_FOR_HANGUP	0x01
+#define HAVE_CONN_REQ		0x02
+#define IN_HOLD			0x04
+
+typedef struct {
+	char cpn[32];
+	char oad[32];
+	char dsa[32];
+	char osa[32];
+	__u8 plan;
+	__u8 screen;
+	__u8 sin[4];
+	__u8 chi[4];
+	__u8 e_chi[4];
+	__u8 bc[12];
+	__u8 e_bc[12];
+ 	__u8 llc[18];
+	__u8 hlc[5];
+	__u8 cau[4];
+	__u8 e_cau[2];
+	__u8 e_mt;
+	__u8 dt[6];
+	char display[83];
+	char keypad[35];
+	char rdn[32];
+} idi_ind_message;
+
+typedef struct { 
+  __u16 next            __attribute__ ((packed));
+  __u8  Req             __attribute__ ((packed));
+  __u8  ReqId           __attribute__ ((packed));
+  __u8  ReqCh           __attribute__ ((packed));
+  __u8  Reserved1       __attribute__ ((packed));
+  __u16 Reference       __attribute__ ((packed));
+  __u8  Reserved[8]     __attribute__ ((packed));
+  eicon_PBUFFER XBuffer; 
+} eicon_REQ;
+
+typedef struct {
+  __u16 next            __attribute__ ((packed));
+  __u8  Rc              __attribute__ ((packed));
+  __u8  RcId            __attribute__ ((packed));
+  __u8  RcCh            __attribute__ ((packed));
+  __u8  Reserved1       __attribute__ ((packed));
+  __u16 Reference       __attribute__ ((packed));
+  __u8  Reserved2[8]    __attribute__ ((packed));
+} eicon_RC;
+
+typedef struct {
+  __u16 next            __attribute__ ((packed));
+  __u8  Ind             __attribute__ ((packed));
+  __u8  IndId           __attribute__ ((packed));
+  __u8  IndCh           __attribute__ ((packed));
+  __u8  MInd            __attribute__ ((packed));
+  __u16 MLength         __attribute__ ((packed));
+  __u16 Reference       __attribute__ ((packed));
+  __u8  RNR             __attribute__ ((packed));
+  __u8  Reserved        __attribute__ ((packed));
+  __u32 Ack             __attribute__ ((packed));
+  eicon_PBUFFER RBuffer;
+} eicon_IND;
+
+typedef struct {
+	__u8		*Data;
+	unsigned int	Size;
+	unsigned int	Len;
+	__u8		*Next;
+} eicon_OBJBUFFER;
+
+extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer);
+extern int idi_hangup(eicon_card *card, eicon_chan *chan);
+extern int idi_connect_res(eicon_card *card, eicon_chan *chan);
+extern int eicon_idi_listen_req(eicon_card *card, eicon_chan *chan);
+extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
+	                    char *eazmsn, int si1, int si2);
+
+extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
+extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
+extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
+extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk);
+extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
+extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm);
+#ifdef CONFIG_ISDN_TTY_FAX
+extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
+extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
+#endif
+
+#include "dsp_defs.h"
+
+#define DSP_UDATA_REQUEST_SWITCH_FRAMER         1
+/*
+parameters:
+  <byte> transmit framer type
+  <byte> receive framer type
+*/
+
+#define DSP_REQUEST_SWITCH_FRAMER_HDLC          0
+#define DSP_REQUEST_SWITCH_FRAMER_TRANSPARENT   1
+#define DSP_REQUEST_SWITCH_FRAMER_ASYNC         2
+
+
+#define DSP_UDATA_REQUEST_CLEARDOWN             2
+/*
+parameters:
+  - none -
+*/
+
+
+#define DSP_UDATA_REQUEST_TX_CONFIRMATION_ON    3
+/*
+parameters:
+  - none -
+*/
+
+
+#define DSP_UDATA_REQUEST_TX_CONFIRMATION_OFF   4
+/*
+parameters:
+  - none -
+*/
+
+typedef struct eicon_dsp_ind {
+	__u16	time		__attribute__ ((packed));
+	__u8	norm		__attribute__ ((packed));
+	__u16	options		__attribute__ ((packed));
+	__u32	speed		__attribute__ ((packed));
+	__u16	delay		__attribute__ ((packed));
+	__u32	txspeed		__attribute__ ((packed));
+	__u32	rxspeed		__attribute__ ((packed));
+} eicon_dsp_ind;
+
+#define DSP_CONNECTED_OPTION_V42_TRANS           0x0002
+#define DSP_CONNECTED_OPTION_V42_LAPM            0x0004
+#define DSP_CONNECTED_OPTION_SHORT_TRAIN         0x0008
+#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
+
+#define DSP_UDATA_INDICATION_DISCONNECT         5
+/*
+returns:
+  <byte> cause
+*/
+
+#define DSP_DISCONNECT_CAUSE_NONE               0x00
+#define DSP_DISCONNECT_CAUSE_BUSY_TONE          0x01
+#define DSP_DISCONNECT_CAUSE_CONGESTION_TONE    0x02
+#define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY    0x03
+#define DSP_DISCONNECT_CAUSE_CLEARDOWN          0x04
+#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT   0x05
+
+#define DSP_UDATA_INDICATION_TX_CONFIRMATION    6
+/*
+returns:
+  <word> confirmation number
+*/
+
+
+#define DSP_UDATA_REQUEST_SEND_DTMF_DIGITS      16
+/*
+parameters:
+  <word> tone duration (ms)
+  <word> gap duration (ms)
+  <byte> digit 0 tone code
+  ...
+  <byte> digit n tone code
+*/
+
+#define DSP_SEND_DTMF_DIGITS_HEADER_LENGTH      5
+
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_697_HZ    0x00
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_770_HZ    0x01
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_852_HZ    0x02
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_941_HZ    0x03
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_MASK      0x03
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ  0x00
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ  0x04
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ  0x08
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ  0x0c
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_MASK     0x0c
+
+#define DSP_DTMF_DIGIT_TONE_CODE_0              0x07
+#define DSP_DTMF_DIGIT_TONE_CODE_1              0x00
+#define DSP_DTMF_DIGIT_TONE_CODE_2              0x04
+#define DSP_DTMF_DIGIT_TONE_CODE_3              0x08
+#define DSP_DTMF_DIGIT_TONE_CODE_4              0x01
+#define DSP_DTMF_DIGIT_TONE_CODE_5              0x05
+#define DSP_DTMF_DIGIT_TONE_CODE_6              0x09
+#define DSP_DTMF_DIGIT_TONE_CODE_7              0x02
+#define DSP_DTMF_DIGIT_TONE_CODE_8              0x06
+#define DSP_DTMF_DIGIT_TONE_CODE_9              0x0a
+#define DSP_DTMF_DIGIT_TONE_CODE_STAR           0x03
+#define DSP_DTMF_DIGIT_TONE_CODE_HASHMARK       0x0b
+#define DSP_DTMF_DIGIT_TONE_CODE_A              0x0c
+#define DSP_DTMF_DIGIT_TONE_CODE_B              0x0d
+#define DSP_DTMF_DIGIT_TONE_CODE_C              0x0e
+#define DSP_DTMF_DIGIT_TONE_CODE_D              0x0f
+
+
+#define DSP_UDATA_INDICATION_DTMF_DIGITS_SENT   16
+/*
+returns:
+  - none -
+  One indication will be sent for every request.
+*/
+
+
+#define DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER  17
+/*
+parameters:
+  <word> tone duration (ms)
+  <word> gap duration (ms)
+*/
+typedef struct enable_dtmf_s {
+	__u16 tone;
+	__u16 gap;
+} enable_dtmf_s;
+
+#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18
+/*
+parameters:
+  - none -
+*/
+
+#define DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED 17
+/*
+returns:
+  <byte> digit 0 tone code
+  ...
+  <byte> digit n tone code
+*/
+
+#define DSP_DTMF_DIGITS_RECEIVED_HEADER_LENGTH  1
+
+
+#define DSP_UDATA_INDICATION_MODEM_CALLING_TONE 18
+/*
+returns:
+  - none -
+*/
+
+#define DSP_UDATA_INDICATION_FAX_CALLING_TONE   19
+/*
+returns:
+  - none -
+*/
+
+#define DSP_UDATA_INDICATION_ANSWER_TONE        20
+/*
+returns:
+  - none -
+*/
+
+/* ============= FAX ================ */
+
+#define EICON_FAXID_LEN 20
+
+typedef struct eicon_t30_s {
+  __u8          code;
+  __u8          rate;
+  __u8          resolution;
+  __u8          format;
+  __u8          pages_low;
+  __u8          pages_high;
+  __u8          atf;
+  __u8          control_bits_low;
+  __u8          control_bits_high;
+  __u8          feature_bits_low;
+  __u8          feature_bits_high;
+  __u8          universal_5;
+  __u8          universal_6;
+  __u8          universal_7;
+  __u8          station_id_len;
+  __u8          head_line_len;
+  __u8          station_id[EICON_FAXID_LEN];
+/* __u8          head_line[]; */
+} eicon_t30_s;
+
+        /* EDATA transmit messages */
+#define EDATA_T30_DIS       0x01
+#define EDATA_T30_FTT       0x02
+#define EDATA_T30_MCF       0x03
+
+        /* EDATA receive messages */
+#define EDATA_T30_DCS       0x81
+#define EDATA_T30_TRAIN_OK  0x82
+#define EDATA_T30_EOP       0x83
+#define EDATA_T30_MPS       0x84
+#define EDATA_T30_EOM       0x85
+#define EDATA_T30_DTC       0x86
+
+#define T30_FORMAT_SFF            0
+#define T30_FORMAT_ASCII          1
+#define T30_FORMAT_COUNT          2
+
+#define T30_CONTROL_BIT_DISABLE_FINE      0x0001
+#define T30_CONTROL_BIT_ENABLE_ECM        0x0002
+#define T30_CONTROL_BIT_ECM_64_BYTES      0x0004
+#define T30_CONTROL_BIT_ENABLE_2D_CODING  0x0008
+#define T30_CONTROL_BIT_ENABLE_T6_CODING  0x0010
+#define T30_CONTROL_BIT_ENABLE_UNCOMPR    0x0020
+#define T30_CONTROL_BIT_ACCEPT_POLLING    0x0040
+#define T30_CONTROL_BIT_REQUEST_POLLING   0x0080
+#define T30_CONTROL_BIT_MORE_DOCUMENTS    0x0100
+
+#define T30_CONTROL_BIT_ALL_FEATURES\
+  (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |\
+   T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR)
+
+#define T30_FEATURE_BIT_FINE              0x0001
+#define T30_FEATURE_BIT_ECM               0x0002
+#define T30_FEATURE_BIT_ECM_64_BYTES      0x0004
+#define T30_FEATURE_BIT_2D_CODING         0x0008
+#define T30_FEATURE_BIT_T6_CODING         0x0010
+#define T30_FEATURE_BIT_UNCOMPR_ENABLED   0x0020
+#define T30_FEATURE_BIT_POLLING           0x0040
+
+#define FAX_OBJECT_DOCU		1
+#define FAX_OBJECT_PAGE		2
+#define FAX_OBJECT_LINE		3
+
+#define T4_EOL			0x800
+#define T4_EOL_BITSIZE		12
+#define T4_EOL_DWORD		(T4_EOL << (32 - T4_EOL_BITSIZE))
+#define T4_EOL_MASK_DWORD	((__u32) -1 << (32 - T4_EOL_BITSIZE))
+
+#define SFF_LEN_FLD_SIZE	3
+
+#define _DLE_	0x10
+#define _ETX_	0x03
+
+typedef struct eicon_sff_dochead {
+	__u32	id		__attribute__ ((packed));
+	__u8	version		__attribute__ ((packed));
+	__u8	reserved1	__attribute__ ((packed));
+	__u16	userinfo	__attribute__ ((packed));
+	__u16	pagecount	__attribute__ ((packed));
+	__u16	off1pagehead	__attribute__ ((packed));
+	__u32	offnpagehead	__attribute__ ((packed));
+	__u32	offdocend	__attribute__ ((packed));
+} eicon_sff_dochead;
+
+typedef struct eicon_sff_pagehead {
+	__u8	pageheadid	__attribute__ ((packed));
+	__u8	pageheadlen	__attribute__ ((packed));
+	__u8	resvert		__attribute__ ((packed));
+	__u8	reshoriz	__attribute__ ((packed));
+	__u8	coding		__attribute__ ((packed));
+	__u8	reserved2	__attribute__ ((packed));
+	__u16	linelength	__attribute__ ((packed));
+	__u16	pagelength	__attribute__ ((packed));
+	__u32	offprevpage	__attribute__ ((packed));
+	__u32	offnextpage	__attribute__ ((packed));
+} eicon_sff_pagehead;
+
+#endif	/* E_IDI_H */
diff -Nru a/drivers/isdn/hardware/eicon/i4lididrv.c b/drivers/isdn/hardware/eicon/i4lididrv.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/i4lididrv.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1468 @@
+/* $Id: i4lididrv.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards.
+ * I4L - IDI Interface
+ * 
+ * Copyright 1998-2000 by Armin Schindler (mac@melware.de) 
+ * Copyright 1999-2002 Cytronics & Melware (info@melware.de)
+ * 
+ * Thanks to	Deutsche Mailbox Saar-Lor-Lux GmbH
+ *		for sponsoring and testing fax
+ *		capabilities with Diva Server cards.
+ *		(dor@deutschemailbox.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+
+#include "i4lididrv.h"
+#include <linux/smp_lock.h>
+#include "divasync.h"
+
+#include "../avmb1/capicmd.h"  /* this should be moved in a common place */
+
+EXPORT_NO_SYMBOLS;
+
+#define INCLUDE_INLINE_FUNCS
+
+static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
+                                                     start of card-list   */
+
+static char *DRIVERNAME = "Eicon Diva - native I4L Interface driver (http://www.melware.net)";
+static char *DRIVERLNAME = "diva2i4l";
+static char *DRIVERRELEASE = "2.0";
+static char *eicon_revision = "$Revision: 1.1.2.2 $";
+extern char *eicon_idi_revision;
+
+#ifdef MODULE
+#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
+#endif
+
+#define EICON_CTRL_VERSION 2
+
+ulong DebugVar;
+
+static spinlock_t status_lock;
+static spinlock_t ll_lock;
+
+#define MAX_DESCRIPTORS  32
+extern void DIVA_DIDD_Read(DESCRIPTOR *, int);
+
+static dword notify_handle;
+static DESCRIPTOR DAdapter;
+static DESCRIPTOR MAdapter;
+
+/* Parameter to be set by insmod */
+static char *id  = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+static int debug = 1;
+
+MODULE_DESCRIPTION(             "ISDN4Linux Interface for Eicon active card driver");
+MODULE_AUTHOR(                  "Armin Schindler");
+MODULE_SUPPORTED_DEVICE(        "ISDN subsystem and Eicon active card driver");
+MODULE_PARM_DESC(id,   		"ID-String for ISDN4Linux");
+MODULE_PARM(id,           	"s");
+MODULE_PARM_DESC(debug,		"Initial debug value");
+MODULE_PARM(debug,           	"i");
+MODULE_LICENSE("GPL");
+
+void no_printf (unsigned char * x ,...)
+{
+  /* dummy debug function */
+}
+DIVA_DI_PRINTF dprintf = no_printf;
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+#include "debuglib.c"
+
+static char *
+eicon_getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else rev = "1.0";
+	return rev;
+
+}
+
+static void
+stop_dbg(void)
+{
+		DbgDeregister();
+		memset(&MAdapter, 0, sizeof(MAdapter));
+		dprintf = no_printf;
+}
+
+static eicon_chan *
+find_channel(eicon_card *card, int channel)
+{
+	if ((channel >= 0) && (channel < card->nchannels))
+        	return &(card->bch[channel]);
+	eicon_log(card, 1, "%s: Invalid channel %d\n", DRIVERLNAME, channel);
+	return NULL;
+}
+
+static void
+eicon_rx_request(struct eicon_card *card)
+{
+	struct sk_buff *skb, *skb2, *skb_new;
+	eicon_IND *ind, *ind2, *ind_new;
+	eicon_chan *chan;
+
+	if (!card) {
+		eicon_log(card, 1, "%s: NULL card in rcv_dispatch !\n", DRIVERLNAME);
+		return;
+	}
+
+	while((skb = skb_dequeue(&card->rcvq))) {
+		ind = (eicon_IND *)skb->data;
+
+		if ((chan = card->IdTable[ind->IndId]) == NULL) {
+			if (DebugVar & 1) {
+				switch(ind->Ind) {
+					case N_DISC_ACK:
+						/* doesn't matter if this happens */
+						break;
+					default:
+						eicon_log(card, 1, "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
+						eicon_log(card, 1, "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
+						ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
+				}
+			}
+			dev_kfree_skb(skb);
+			continue;
+		}
+
+		if (chan->e.complete) { /* check for rec-buffer chaining */
+			if (ind->MLength == ind->RBuffer.length) {
+				chan->e.complete = 1;
+				idi_handle_ind(card, skb);
+				continue;
+			}
+			else {
+				chan->e.complete = 0;
+				ind->Ind = ind->MInd;
+				skb_queue_tail(&chan->e.R, skb);
+				continue;
+			}
+		}
+		else {
+			if (!(skb2 = skb_dequeue(&chan->e.R))) {
+				chan->e.complete = 1;
+				eicon_log(card, 1, "%s: buffer incomplete, but 0 in queue\n", DRIVERLNAME);
+				dev_kfree_skb(skb);
+				continue;
+			}
+			ind2 = (eicon_IND *)skb2->data;
+			skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
+				GFP_ATOMIC);
+			if (!skb_new) {
+			eicon_log(card, 1, "%s: skb_alloc failed in rcv_dispatch()\n", DRIVERLNAME);
+				dev_kfree_skb(skb);
+				dev_kfree_skb(skb2);
+				continue;
+			}
+			ind_new = (eicon_IND *)skb_put(skb_new,
+				((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length));
+			ind_new->Ind = ind2->Ind;
+			ind_new->IndId = ind2->IndId;
+			ind_new->IndCh = ind2->IndCh;
+			ind_new->MInd = ind2->MInd;
+			ind_new->MLength = ind2->MLength;
+			ind_new->RBuffer.length = ind2->RBuffer.length + ind->RBuffer.length;
+			memcpy(&ind_new->RBuffer.P, &ind2->RBuffer.P, ind2->RBuffer.length);
+			memcpy((&ind_new->RBuffer.P)+ind2->RBuffer.length, &ind->RBuffer.P, ind->RBuffer.length);
+			dev_kfree_skb(skb);
+			dev_kfree_skb(skb2);
+			if (ind->MLength == ind->RBuffer.length) {
+				chan->e.complete = 2;
+				idi_handle_ind(card, skb_new);
+				continue;
+			}
+			else {
+				chan->e.complete = 0;
+				skb_queue_tail(&chan->e.R, skb_new);
+				continue;
+			}
+		}
+	}
+}
+
+static void
+eicon_ack_request(struct eicon_card *card)
+{
+	struct sk_buff *skb;
+
+	if (!card) {
+		eicon_log(card, 1, "%s: NULL card in ack_dispatch!\n", DRIVERLNAME);
+		return;
+	}
+	while((skb = skb_dequeue(&card->rackq))) {
+		idi_handle_ack(card, skb);
+	}
+}
+
+/*
+ *  IDI-Callback function
+ */
+static void
+eicon_idi_callback(ENTITY *de)
+{
+	eicon_card *ccard = (eicon_card *)de->R;
+	struct sk_buff *skb;
+	eicon_RC *ack;
+	eicon_IND *ind;
+	int len = 0;
+
+	if (de->complete == 255) {
+		/* Return Code */
+		skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
+		if (!skb) {
+			eicon_log(ccard, 1, "%s: skb_alloc failed in _idi_callback()\n", DRIVERLNAME);
+		} else {
+			ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+			ack->Rc = de->Rc;
+			if (de->Rc == ASSIGN_OK) {
+				ack->RcId = de->Id;
+				de->user[1] = de->Id;
+			} else {
+				ack->RcId = de->user[1];
+			}
+			ack->RcCh = de->RcCh;
+			ack->Reference = de->user[0];
+			skb_queue_tail(&ccard->rackq, skb);
+			eicon_ack_request(ccard);
+			eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n",
+				de->user[0], de->Rc, ack->RcId, de->RLength, de->complete);
+			DBG_TRC(("idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x",
+				de->user[0], de->Rc, ack->RcId, de->RLength, de->complete))
+	                de->Rc = 0;
+		}
+	} else {
+		/* Indication */
+		if (de->complete) {
+			len = de->RLength;
+		} else {
+			len = 270;
+			if (de->RLength <= 270)
+				eicon_log(ccard, 1, "idi_cbk: ind not complete but <= 270\n");
+		}
+		skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
+		if (!skb) {
+			eicon_log(ccard, 1, "%s: skb_alloc failed in _idi_callback()\n", DRIVERLNAME);
+		} else {
+			ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+			ind->Ind = de->Ind;
+			ind->IndId = de->user[1];
+			ind->IndCh = de->IndCh;
+			ind->MInd  = de->Ind;
+			ind->RBuffer.length = len;
+			ind->MLength = de->RLength;
+			memcpy(&ind->RBuffer.P, &de->RBuffer->P, len);
+			skb_queue_tail(&ccard->rcvq, skb);
+			eicon_rx_request(ccard);
+			eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n",
+				de->user[0], de->Ind, ind->IndId, de->RLength, de->complete);
+			DBG_TRC(("idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x",
+				de->user[0], de->Ind, ind->IndId, de->RLength, de->complete))
+	                de->Ind = 0;
+		}
+	}
+	de->RNum = 0;
+	de->RNR = 0;
+    eicon_tx_request(ccard);
+}
+
+/*
+**  Kernel thread to prevent in_interrupt
+*/
+static DECLARE_TASK_QUEUE(tq_divad);
+static struct semaphore diva_thread_sem;
+static struct semaphore diva_thread_end;
+static int divad_pid = -1;
+static int divad_thread(void * data);
+static void diva_tx(void *data);
+static atomic_t thread_running;
+
+static void __init
+diva_init_thread(void)
+{
+  int pid = 0;
+
+  pid = kernel_thread(divad_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+  if (pid >= 0) {
+       divad_pid = pid;
+  }
+}
+
+static int
+divad_thread(void * data)
+{
+  atomic_inc(&thread_running);
+  if (atomic_read(&thread_running) > 1) {
+      printk(KERN_WARNING"%s: thread already running\n", DRIVERLNAME);
+      return(0);
+  }
+
+  printk(KERN_INFO "%s: thread started with pid %d\n", DRIVERLNAME, current->pid);
+  exit_mm(current);
+  exit_files(current);
+  exit_fs(current);
+
+  /* Set to RealTime */
+  current->policy = SCHED_FIFO;
+  current->rt_priority = 33;
+
+  strcpy(current->comm, "kdiva2i4ld");
+
+  for(;;) {
+    down_interruptible(&diva_thread_sem);
+    if(!(atomic_read(&thread_running)))
+      break;
+    if(signal_pending(current)) {
+         /* we may want to do something on signals here */
+         spin_lock_irq(&current->sigmask_lock);
+         flush_signals(current);
+         spin_unlock_irq(&current->sigmask_lock);
+    } else {
+         run_task_queue(&tq_divad);
+    }
+  }
+  up(&diva_thread_end);
+  divad_pid = -1;
+  return 0;
+}
+
+static void
+stop_diva_thread(void)
+{
+    if (divad_pid >= 0) {
+         atomic_set(&thread_running, 0);
+         up(&diva_thread_sem);
+         down_interruptible(&diva_thread_end);
+    }
+}
+
+void
+eicon_tx_request(struct eicon_card *card)
+{
+  card->tq.routine = diva_tx;
+  card->tq.data = (void *)card;
+  queue_task(&card->tq, &tq_divad);
+  up(&diva_thread_sem);
+}
+
+static void
+diva_tx(void *data)
+{
+        struct eicon_card *card = (eicon_card *) data;
+	struct sk_buff *skb;
+	struct sk_buff *skb2;
+	eicon_chan *chan;
+	eicon_chan_ptr *chan2;
+	eicon_REQ *reqbuf = 0;
+	int ReqCount = 0;
+	int tmpid = 0;
+	int quloop = 1;
+	int dlev = 0;
+	ENTITY *ep = 0;
+
+        if (!card) {
+                eicon_log(card, 1, "%s: NULL card in transmit !\n", DRIVERLNAME);
+                return;
+        }
+
+	ReqCount = 0;
+	if (!(skb2 = skb_dequeue(&card->sndq)))
+		quloop = 0;
+	while(quloop) {
+		chan2 = (eicon_chan_ptr *)skb2->data;
+		chan = chan2->ptr;
+		if (!chan->e.busy) {
+		 if((skb = skb_dequeue(&chan->e.X))) {
+
+		  reqbuf = (eicon_REQ *)skb->data;
+		  if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
+			eicon_log(card, 16, "%s: transmit: error Id=0 on %d (Net)\n", DRIVERLNAME, chan->No);
+		  } else {
+			dlev = 160;
+			if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
+
+				if (!reqbuf->Reference) { /* Signal Layer */
+					ep = &chan->de;
+					tmpid = chan->e.D3Id;
+					chan->e.ReqCh = 0;
+				}
+				else {                  /* Net Layer */
+					ep = &chan->be;
+					tmpid = chan->e.B2Id;
+					chan->e.ReqCh = 1;
+					if (((reqbuf->Req & 0x0f) == 0x08) ||
+					    ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
+						chan->waitq = reqbuf->XBuffer.length;
+						chan->waitpq += reqbuf->XBuffer.length;
+						dlev = 128;
+					}
+				}
+
+			} else {        /* It is an ASSIGN */
+				if (!reqbuf->Reference)
+					ep = &chan->de;
+				else
+					ep = &chan->be;
+				ep->Id = reqbuf->ReqId;
+				tmpid = reqbuf->ReqId;
+
+				if (!reqbuf->Reference)
+					chan->e.ReqCh = 0;
+				else
+					chan->e.ReqCh = 1;
+			}
+
+			chan->e.ref = chan->No;
+			chan->e.Req = reqbuf->Req;
+			ReqCount++;
+			if (ep) {
+				ep->callback = eicon_idi_callback;
+				ep->R = (BUFFERS *)card;
+				ep->user[0] = (word)chan->No;
+				ep->user[1] = (word)tmpid;
+				ep->XNum = 1;
+				ep->RNum = 0;
+				ep->RNR = 0;
+				ep->Rc = 0;
+				ep->Ind = 0;
+				ep->X->PLength = reqbuf->XBuffer.length;
+				memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
+				ep->ReqCh = reqbuf->ReqCh;
+				ep->Req = reqbuf->Req;
+			}
+			chan->e.busy = 1;
+			eicon_log(card, dlev, "idi: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
+				reqbuf->Req, tmpid,
+				reqbuf->ReqCh, reqbuf->XBuffer.length,
+				chan->e.ref);
+			if (ep) {
+				card->d.request(ep);
+				if (ep->Rc)
+					eicon_idi_callback(ep);
+			}
+		  }
+		  dev_kfree_skb(skb);
+		 }
+		 dev_kfree_skb(skb2);
+		}
+		else {
+			skb_queue_tail(&card->sackq, skb2);
+			eicon_log(card, 128, "%s: transmit: busy chan %d\n", DRIVERLNAME, chan->No);
+		}
+		if (!(skb2 = skb_dequeue(&card->sndq)))
+			quloop = 0;
+	}
+	while((skb = skb_dequeue(&card->sackq))) {
+		skb_queue_tail(&card->sndq, skb);
+	}
+}
+
+static int
+eicon_command(eicon_card * card, isdn_ctrl * c)
+{
+        ulong a;
+        eicon_chan *chan;
+	isdn_ctrl cmd;
+	int ret = 0;
+
+	eicon_log(card, 16, "%s_cmd 0x%x with arg 0x%lx (0x%lx)\n", DRIVERLNAME,
+		c->command, c->arg, (ulong) *c->parm.num);
+
+        switch (c->command) {
+		case ISDN_CMD_IOCTL:
+			memcpy(&a, c->parm.num, sizeof(ulong));
+			switch (c->arg) {
+				case EICON_IOCTL_GETVER:
+					return(EICON_CTRL_VERSION);
+				case EICON_IOCTL_MANIF:
+					if (!card->flags & EICON_FLAGS_RUNNING)
+						return -ENODEV;
+					if (!card->d.features & DI_MANAGE)
+						return -ENODEV;
+					ret = eicon_idi_manage(
+						card, 
+						(eicon_manifbuf *)a);
+					return ret;
+
+				case EICON_IOCTL_GETXLOG:
+					return -ENODEV;
+				case EICON_IOCTL_DEBUGVAR:
+					DebugVar = a;
+					eicon_log(card, 1, "%s: Debug Value set to %ld\n", DRIVERLNAME, DebugVar);
+					return 0;
+#ifdef MODULE
+				case EICON_IOCTL_FREEIT:
+					while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT;
+					MOD_INC_USE_COUNT;
+					return 0;
+#endif
+				case EICON_IOCTL_LOADPCI:
+					eicon_log(card, 1, "%s: Wrong version of load-utility,\n", DRIVERLNAME);
+					eicon_log(card, 1, "%s: re-compile eiconctrl !\n", DRIVERLNAME);
+					eicon_log(card, 1, "%s: Maybe update of utility is necessary !\n", DRIVERLNAME);
+					return -EINVAL;
+				default:	
+					return -EINVAL;
+			}
+			break;
+		case ISDN_CMD_DIAL:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
+				eicon_log(card, 1, "%s: Dial on channel %d with state %d\n", DRIVERLNAME,
+					chan->No, chan->fsm_state);
+				return -EBUSY;
+			}
+			chan->fsm_state = EICON_STATE_OCALL;
+			
+			ret = idi_connect_req(card, chan, c->parm.setup.phone,
+						     c->parm.setup.eazmsn,
+						     c->parm.setup.si1,
+						     c->parm.setup.si2);
+			if (ret) {
+				cmd.driver = card->myid;
+				cmd.command = ISDN_STAT_DHUP;
+				cmd.arg &= 0x1f;
+				card->interface.statcallb(&cmd);
+			}
+			return ret;
+		case ISDN_CMD_ACCEPTD:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			if (chan->fsm_state == EICON_STATE_ICALL) { 
+				idi_connect_res(card, chan);
+			}
+			return 0;
+		case ISDN_CMD_ACCEPTB:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			return 0;
+		case ISDN_CMD_HANGUP:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			idi_hangup(card, chan);
+			return 0;
+		case ISDN_CMD_SETEAZ:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			chan->eazmask = 0x3ff;
+			eicon_idi_listen_req(card, chan);
+			return 0;
+		case ISDN_CMD_CLREAZ:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			chan->eazmask = 0;
+			eicon_idi_listen_req(card, chan);
+			return 0;
+		case ISDN_CMD_SETL2:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			chan->l2prot = (c->arg >> 8);
+                        memcpy(chan->a_para, c->parm.aux.para, sizeof(chan->a_para));
+			return 0;
+		case ISDN_CMD_GETL2:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			return chan->l2prot;
+		case ISDN_CMD_SETL3:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			chan->l3prot = (c->arg >> 8);
+#ifdef CONFIG_ISDN_TTY_FAX
+			if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) {
+				chan->fax = c->parm.fax;
+				eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax);
+			}
+#endif
+			return 0;
+		case ISDN_CMD_GETL3:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			return chan->l3prot;
+		case ISDN_CMD_GETEAZ:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			eicon_log(card, 1, "%s: CMD_GETEAZ not implemented\n", DRIVERLNAME);
+			return 0;
+		case ISDN_CMD_SETSIL:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			eicon_log(card, 1, "%s: CMD_SETSIL not implemented\n",DRIVERLNAME);
+			return 0;
+		case ISDN_CMD_GETSIL:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			eicon_log(card, 1, "%s: CMD_GETSIL not implemented\n", DRIVERLNAME);
+			return 0;
+		case ISDN_CMD_LOCK:
+			MOD_INC_USE_COUNT;
+			return 0;
+		case ISDN_CMD_UNLOCK:
+			MOD_DEC_USE_COUNT;
+			return 0;
+#ifdef CONFIG_ISDN_TTY_FAX
+		case ISDN_CMD_FAXCMD:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			if (!chan->fax)
+				break;
+			idi_fax_cmd(card, chan);
+			return 0;
+#endif
+		case ISDN_CMD_AUDIO:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num);
+			return 0;
+		case CAPI_PUT_MESSAGE:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			if (c->parm.cmsg.Length < 8)
+				break;
+			switch(c->parm.cmsg.Command) {
+				case CAPI_FACILITY:
+					if (c->parm.cmsg.Subcommand == CAPI_REQ)
+						return(capipmsg(card, chan, &c->parm.cmsg));
+					break;
+				case CAPI_MANUFACTURER:
+				default:
+					break;
+			}
+			return 0;
+        }
+	
+        return -EINVAL;
+}
+
+static int
+find_free_number(void)
+{
+  int num = 0;
+  char cid[40];
+  eicon_card *p;
+  ulong flags;
+
+  spin_lock_irqsave(&ll_lock, flags);
+  while(num < 100) {
+    sprintf(cid, "%s%d", id, num);
+    num++;
+    p = cards;
+    while (p) {
+      if (!strcmp(p->regname, cid))
+        break;
+      p = p->next;
+    }
+		if (p)
+		{
+	    spin_unlock_irqrestore(&ll_lock, flags);
+  	  return(num - 1);
+		}
+  }
+  spin_unlock_irqrestore(&ll_lock, flags);
+  return(999);
+}
+
+/*
+ * Find card with given driverId
+ */
+static inline eicon_card *
+eicon_findcard(int driverid)
+{
+  eicon_card *p;
+  ulong flags;
+
+  spin_lock_irqsave(&ll_lock, flags);
+  p = cards;
+  while (p) {
+    if (p->myid == driverid) {
+      spin_unlock_irqrestore(&ll_lock, flags);
+      return p;
+    }
+    p = p->next;
+  }
+  spin_unlock_irqrestore(&ll_lock, flags);
+  return (eicon_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl * c)
+{
+        eicon_card *card = eicon_findcard(c->driver);
+
+        if (card)
+                return (eicon_command(card, c));
+        printk(KERN_ERR
+             "%s: if_command %d called with invalid driverId %d!\n", DRIVERLNAME,
+               c->command, c->driver);
+        return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+{
+	/* Not used */
+        return (len);
+}
+
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+  int count = 0;
+  int cnt = 0;
+  u_char *p = buf;
+  struct sk_buff *skb;
+  ulong flags;
+
+        eicon_card *card = eicon_findcard(id);
+	
+        if (card) {
+                if (!card->flags & EICON_FLAGS_RUNNING)
+                        return -ENODEV;
+	
+		spin_lock_irqsave(&status_lock, flags);
+		while((skb = skb_dequeue(&card->statq))) {
+
+			if ((skb->len + count) > len)
+				cnt = len - count;
+			else
+				cnt = skb->len;
+
+			if (user)
+				copy_to_user(p, skb->data, cnt);
+			else
+				memcpy(p, skb->data, cnt);
+
+			count += cnt;
+			p += cnt;
+
+			if (cnt == skb->len) {
+				dev_kfree_skb(skb);
+				if (card->statq_entries > 0)
+					card->statq_entries--;
+			} else {
+				skb_pull(skb, cnt);
+				skb_queue_head(&card->statq, skb);
+				spin_unlock_irqrestore(&status_lock, flags);
+				return count;
+			}
+		}
+		card->statq_entries = 0;
+		spin_unlock_irqrestore(&status_lock, flags);
+		return count;
+        }
+        printk(KERN_ERR
+               "%s: if_readstatus called with invalid driverId!\n", DRIVERLNAME);
+        return 0;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+        eicon_card *card = eicon_findcard(id);
+	eicon_chan *chan;
+	int ret = 0;
+	int len;
+
+	len = skb->len;
+
+        if (card) {
+                if (!card->flags & EICON_FLAGS_RUNNING)
+                        return -ENODEV;
+        	if (!(chan = find_channel(card, channel)))
+			return -ENODEV;
+
+		if (chan->fsm_state == EICON_STATE_ACTIVE) {
+#ifdef CONFIG_ISDN_TTY_FAX
+			if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+				if ((ret = idi_faxdata_send(card, chan, skb)) > 0)
+					ret = len;
+			}
+			else
+#endif
+				ret = idi_send_data(card, chan, ack, skb, 1, 1);
+			return (ret);
+		} else {
+			return -ENODEV;
+		}
+        }
+        printk(KERN_ERR
+               "%s: if_sendbuf called with invalid driverId!\n", DRIVERLNAME);
+        return -ENODEV;
+}
+
+/* jiftime() copied from HiSax */
+static inline int jiftime(char *s, long mark)
+{
+        s += 8;
+
+        *s-- = '\0';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = '.';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 6 + '0';
+        mark /= 6;
+        *s-- = ':';
+        *s-- = mark % 10 + '0';
+        mark /= 10;
+        *s-- = mark % 10 + '0';
+        return(8);
+}
+
+void
+eicon_putstatus(eicon_card * card, char * buf)
+{
+  int count;
+  isdn_ctrl cmd;
+  u_char *p;
+  struct sk_buff *skb;
+  ulong flags;
+
+	if (!card) {
+		if (!(card = cards))
+			return;
+	}
+
+	spin_lock_irqsave(&status_lock, flags);
+	count = strlen(buf);
+	skb = alloc_skb(count, GFP_ATOMIC);
+	if (!skb) {
+		spin_unlock_irqrestore(&status_lock, flags);
+		printk(KERN_ERR "%s: could not alloc skb in putstatus\n", DRIVERLNAME);
+		return;
+	}
+	p = skb_put(skb, count);
+	memcpy(p, buf, count);
+
+	skb_queue_tail(&card->statq, skb);
+
+	if (card->statq_entries >= MAX_STATUS_BUFFER) {
+		if ((skb = skb_dequeue(&card->statq))) {
+			count -= skb->len;
+			dev_kfree_skb(skb);
+		} else
+			count = 0;
+	} else
+		card->statq_entries++;
+
+	spin_unlock_irqrestore(&status_lock, flags);
+        if (count) {
+                cmd.command = ISDN_STAT_STAVAIL;
+                cmd.driver = card->myid;
+                cmd.arg = count;
+		card->interface.statcallb(&cmd);
+        }
+}
+
+/*
+ * Debug and Log 
+ */
+void
+eicon_log(eicon_card * card, int level, const char *fmt, ...)
+{
+	va_list args;
+	char Line[160];
+	u_char *p;
+
+
+	if ((DebugVar & level) || (DebugVar & 256)) {
+		va_start(args, fmt);
+
+		if (DebugVar & level) {
+			if (DebugVar & 256) {
+				/* log-buffer */
+				p = Line;
+				p += jiftime(p, jiffies);
+				*p++ = 32;
+				p += vsprintf(p, fmt, args);
+				*p = 0;	
+				eicon_putstatus(card, Line);
+			} else {
+				/* printk, syslogd */
+				vsprintf(Line, fmt, args);
+				printk(KERN_DEBUG "%s", Line);
+			}
+		}
+
+		va_end(args);
+	}
+}
+
+
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list.
+ */
+static void
+eicon_alloccard(DESCRIPTOR *d)
+{
+  int j;
+  char cid[40];
+  eicon_card *card;
+  ulong flags;
+
+	sprintf(cid, "%s%d", id, find_free_number());
+	if (!(card = (eicon_card *) kmalloc(sizeof(eicon_card), GFP_KERNEL))) {
+		eicon_log(card, 1,
+		       "%s: (%s) Could not allocate card-struct.\n", DRIVERLNAME, cid);
+		return;
+	}
+	memset((char *) card, 0, sizeof(eicon_card));
+	skb_queue_head_init(&card->sndq);
+	skb_queue_head_init(&card->rcvq);
+	skb_queue_head_init(&card->rackq);
+	skb_queue_head_init(&card->sackq);
+	skb_queue_head_init(&card->statq);
+	card->statq_entries = 0;
+	card->interface.maxbufsize = 4000;
+	card->interface.command = if_command;
+	card->interface.writebuf_skb = if_sendbuf;
+	card->interface.writecmd = if_writecmd;
+	card->interface.readstat = if_readstatus;
+	card->interface.features =
+		ISDN_FEATURE_L2_X75I |
+		ISDN_FEATURE_L2_HDLC |
+		ISDN_FEATURE_L2_TRANS |
+		ISDN_FEATURE_L3_TRANS |
+		ISDN_FEATURE_L3_TRANSDSP |
+		ISDN_FEATURE_P_UNKNOWN;
+	card->interface.hl_hdrlen = 20;
+	card->ptype = ISDN_PTYPE_UNKNOWN;
+	strcpy(card->interface.id, cid);
+	card->myid = -1;
+	card->type = d->type;
+
+	if (d->features & (DI_FAX3 | DI_EXTD_FAX))
+		card->interface.features |= (ISDN_FEATURE_L2_FAX | ISDN_FEATURE_L3_FCLASS2);
+	if (d->features & DI_MODEM)
+		card->interface.features |= ISDN_FEATURE_L2_MODEM;
+	if (d->features & DI_V110)
+		card->interface.features |= (ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038);
+
+	card->flags = 0;
+	card->nchannels = d->channels;
+	card->interface.channels = d->channels;
+	if (!(card->bch = (eicon_chan *) vmalloc(sizeof(eicon_chan) * (card->nchannels + 1)))) {
+		eicon_log(card, 1,
+		       "%s: (%s) Could not allocate bch-struct.\n", DRIVERLNAME, cid);
+		kfree(card);
+		return;
+	}
+	for (j=0; j< (card->nchannels + 1); j++) {
+		memset((char *)&card->bch[j], 0, sizeof(eicon_chan));
+		card->bch[j].statectrl = 0;
+		card->bch[j].l2prot = ISDN_PROTO_L2_X75I;
+		card->bch[j].l3prot = ISDN_PROTO_L3_TRANS;
+		card->bch[j].e.D3Id = 0;
+		card->bch[j].e.B2Id = 0;
+		card->bch[j].e.Req = 0;
+		card->bch[j].No = j;
+		card->bch[j].tskb1 = NULL;
+		card->bch[j].tskb2 = NULL;
+		skb_queue_head_init(&card->bch[j].e.X);
+		skb_queue_head_init(&card->bch[j].e.R);
+	}
+
+	if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2
+						 , GFP_KERNEL))) {
+		eicon_log(card, 1,
+		       "%s: (%s) Could not allocate DBUFFER-struct.\n", DRIVERLNAME, cid);
+		kfree(card);
+		vfree(card->bch);
+		return;
+	}
+	if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+		eicon_log(card, 1,
+		       "%s: (%s) Could not allocate BUFFERS-struct.\n", DRIVERLNAME, cid);
+		kfree(card);
+		vfree(card->bch);
+		kfree(card->dbuf);
+		return;
+	}
+	if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+		eicon_log(card, 1,
+		       "%s: (%s) Could not allocate BUFFERSP-struct.\n", DRIVERLNAME, cid);
+		kfree(card);
+		vfree(card->bch);
+		kfree(card->dbuf);
+		kfree(card->sbuf);
+		return;
+	}
+	for (j=0; j< (card->nchannels + 1); j++) {
+		memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER));
+		card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j];
+		memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+		card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)];
+
+		memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS));
+		card->bch[j].de.X = (BUFFERS *)&card->sbuf[j];
+		memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+		card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)];
+
+		memset((char *)&card->sbufp[j], 0, 270);
+		card->bch[j].de.X->P = (char *)&card->sbufp[j * 270];
+		memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270);
+		card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270];
+	}
+	memcpy(&card->d, d, sizeof(*d)); /* DESCRIPTOR entries */
+
+	/* initializing some variables */
+	card->lock = SPIN_LOCK_UNLOCKED;
+	card->ReadyInt = 0;
+
+	for(j = 0; j < 256; j++)
+		card->IdTable[j] = NULL;
+
+	for(j = 0; j < (card->d.channels + 1); j++) {
+		card->bch[j].e.busy = 0;
+		card->bch[j].e.D3Id = 0;
+		card->bch[j].e.B2Id = 0;
+		card->bch[j].e.ref = 0;
+		card->bch[j].e.Req = 0;
+		card->bch[j].e.complete = 1;
+		card->bch[j].fsm_state = EICON_STATE_NULL;
+	}
+	printk(KERN_INFO "%s: registered card '%s' with %d channels\n",
+		DRIVERLNAME, cid, d->channels);
+
+  spin_lock_irqsave(&ll_lock, flags);
+	card->next = cards;
+	cards = card;
+  spin_unlock_irqrestore(&ll_lock, flags);
+}
+
+/*
+ * register card at linklevel
+ */
+static int
+eicon_registercard(eicon_card * card)
+{
+	isdn_ctrl cmd;
+
+        if (!register_isdn(&card->interface)) {
+                printk(KERN_WARNING
+                       "%s: Unable to register %s\n", DRIVERLNAME,
+                       card->interface.id);
+                return -1;
+        }
+        card->myid = card->interface.channels;
+        sprintf(card->regname, "%s", card->interface.id);
+
+	/* after register we start it */
+	card->flags |= EICON_FLAGS_LOADED;
+	card->flags |= EICON_FLAGS_RUNNING;
+	cmd.command = ISDN_STAT_RUN;
+	cmd.driver = card->myid;
+	cmd.arg = 0;
+	card->interface.statcallb(&cmd);
+
+        return 0;
+}
+
+static void 
+unregister_card(eicon_card * card, int rme)
+{
+  int count;
+  int channel;
+  isdn_ctrl cmd;
+  eicon_chan *chan;
+
+  if(rme) {
+      /* before unload we need to remove the signal entity */
+      for(channel = 0; channel < card->nchannels; channel++)
+        {
+		chan = &(card->bch[channel]);
+                if (chan->e.D3Id) {
+                        idi_do_req(card, chan, REMOVE, 0);
+			count = 100;
+			while(count--) {
+				if (!chan->e.D3Id)
+					break;
+				SLEEP(2);
+			}
+			if (!count)
+				printk(KERN_WARNING"%s: ch:%d unlink to diva module not successful !\n",
+					DRIVERLNAME, chan->No);
+		}
+        }
+  }
+
+  cmd.command = ISDN_STAT_UNLOAD;
+  cmd.driver = card->myid;
+  card->interface.statcallb(&cmd);
+  DBG_TRC(("channel entities freed"));
+}
+
+static void
+eicon_freecard(eicon_card *card) {
+	int i;
+
+	for(i = 0; i < (card->nchannels + 1); i++) {
+		skb_queue_purge(&card->bch[i].e.X);
+		skb_queue_purge(&card->bch[i].e.R);
+	}
+	skb_queue_purge(&card->sndq);
+	skb_queue_purge(&card->rcvq);
+	skb_queue_purge(&card->rackq);
+	skb_queue_purge(&card->sackq);
+	skb_queue_purge(&card->statq);
+
+	kfree(card->sbufp);
+	kfree(card->sbuf);
+	kfree(card->dbuf);
+	vfree(card->bch);
+	kfree(card);
+        DBG_TRC(("card structures freed"));
+}
+
+static int
+eicon_addcard(DESCRIPTOR *d)
+{
+  eicon_card *p;
+  eicon_card *q = NULL;
+  int registered;
+  int added = 0;
+  int failed = 0;
+  ulong flags;
+
+	eicon_alloccard(d);
+        p = cards;
+        while (p) {
+		registered = 0;
+		if (!p->interface.statcallb) {
+			/* Not yet registered.
+			 * Try to register and activate it.
+			 */
+			added++;
+			if (!eicon_registercard(p))
+				registered = 1;
+		} else {
+			/* Card already registered */
+			registered = 1;
+		}
+
+                if (registered) {
+			/* Init OK, next card ... */
+                        spin_lock_irqsave(&ll_lock, flags);
+                        q = p;
+                        p = p->next;
+                        spin_unlock_irqrestore(&ll_lock, flags);
+                } else {
+                        /* registering failed, remove card from list, free memory */
+                        printk(KERN_ERR
+                               "%s: Initialization of %s failed\n", DRIVERLNAME,
+                               p->interface.id);
+                        spin_lock_irqsave(&ll_lock, flags);
+                        if (q) {
+                                q->next = p->next;
+                                eicon_freecard(p);
+                                p = q->next;
+                        } else {
+                                cards = p->next;
+                                eicon_freecard(p);
+                                p = cards;
+                        }
+                        spin_unlock_irqrestore(&ll_lock, flags);
+			failed++;
+                }
+	}
+        return (added - failed);
+}
+
+static void *
+didd_callback(void *context, DESCRIPTOR* adapter, int removal)
+{
+  eicon_card *cp = NULL, *lastcp = NULL;
+  ulong flags;
+
+  if (adapter->type == IDI_DADAPTER)
+  {
+    printk(KERN_ERR "%s: Change in DAdapter ? Oops ?.\n", DRIVERLNAME);
+    DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
+    return(NULL);
+  }
+  else if (adapter->type == IDI_DIMAINT)
+  {
+    if (removal)
+    {
+				stop_dbg();
+    }
+    else
+    {
+      memcpy(&MAdapter, adapter, sizeof(MAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      DbgRegister("I4L", DRIVERRELEASE, DBG_DEFAULT);
+    }
+  }
+  else if ((adapter->type > 0) &&
+           (adapter->type < 16))
+  {  /* IDI Adapter */
+    if (removal)
+    {
+      spin_lock_irqsave(&ll_lock, flags);
+      lastcp = cp = cards;
+      while (cp) {
+        if (cp->d.request == adapter->request)
+        {
+          spin_unlock_irqrestore(&ll_lock, flags);
+          DBG_LOG(("remove adapter from list"));
+          unregister_card(cp, 0);
+          spin_lock_irqsave(&ll_lock, flags);
+          if (cp == lastcp)
+            cards = cp->next;
+          else
+            lastcp->next = cp->next;
+          eicon_freecard(cp);
+          break;
+        }
+        lastcp = cp;
+        cp = cp->next;
+      }
+      spin_unlock_irqrestore(&ll_lock, flags);
+    }
+    else
+    {
+      if (adapter->channels) {
+        DBG_LOG(("add adapter to list"));
+        eicon_addcard(adapter);
+      }
+    }
+  }
+  return(NULL);
+}
+
+static int __init
+connect_didd(void)
+{
+  int x = 0;
+  int dadapter = 0;
+  IDI_SYNC_REQ req;
+  DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+  DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+  for (x = 0; x < MAX_DESCRIPTORS; x++)
+  {
+    if (DIDD_Table[x].type == IDI_DADAPTER)
+    {  /* DADAPTER found */
+      dadapter = 1;
+      memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      req.didd_notify.e.Req = 0;
+      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+      req.didd_notify.info.callback = didd_callback;
+      req.didd_notify.info.context = 0;
+      DAdapter.request((ENTITY *)&req);
+      if (req.didd_notify.e.Rc != 0xff)
+			{
+					stop_dbg();
+					return(0);
+			}
+      notify_handle = req.didd_notify.info.handle;
+    }
+    else if (DIDD_Table[x].type == IDI_DIMAINT)
+    {  /* MAINT found */
+      memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      DbgRegister("I4L", DRIVERRELEASE, DBG_DEFAULT);
+    }
+    else if ((DIDD_Table[x].type > 0) &&
+             (DIDD_Table[x].type < 16))
+    {  /* IDI Adapter found */
+      if (DIDD_Table[x].channels) {
+        eicon_addcard(&DIDD_Table[x]);
+      }
+    }
+  }
+
+	if (!dadapter) {
+			stop_dbg();
+	}
+
+  return(dadapter);
+}
+
+static void __exit
+disconnect_didd(void)
+{
+  IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+  req.didd_notify.e.Req = 0;
+  req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+  req.didd_notify.info.handle = notify_handle;
+  DAdapter.request((ENTITY *)&req);
+}
+
+/*
+** proc entry
+*/
+extern struct proc_dir_entry *proc_net_isdn_eicon;
+static struct proc_dir_entry *i4lidi_proc_entry = NULL;
+
+static int
+i4lidi_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+  int len = 0;
+  char tmprev[32];
+
+  len += sprintf(page+len, "%s\n", DRIVERNAME);
+  len += sprintf(page+len, "name     : %s\n", DRIVERLNAME);
+  len += sprintf(page+len, "release  : %s\n", DRIVERRELEASE);
+  strcpy(tmprev, eicon_revision);
+  len += sprintf(page+len, "revision : %s/", eicon_getrev(tmprev));
+  strcpy(tmprev, eicon_idi_revision);
+  len += sprintf(page+len, "%s\n", eicon_getrev(tmprev));
+
+  if (off + count >= len)
+    *eof = 1;
+  if (len < off)
+    return 0;
+  *start = page + off;
+  return((count < len-off) ? count : len-off);
+}
+
+static void __init
+create_proc(void)
+{
+  if(!(i4lidi_proc_entry = create_proc_entry(DRIVERLNAME,
+                          S_IFREG | S_IRUGO | S_IWUSR, proc_net_isdn_eicon)))
+  {
+    printk(KERN_WARNING "%s: failed to create proc entry.\n", DRIVERLNAME);
+    return;
+  }
+  i4lidi_proc_entry->read_proc = i4lidi_proc_read;
+  i4lidi_proc_entry->owner = THIS_MODULE;
+}
+
+static void __exit
+remove_proc(void)
+{
+  if(i4lidi_proc_entry)
+      remove_proc_entry(DRIVERLNAME,  proc_net_isdn_eicon);
+}
+
+/*
+** load / unload
+*/
+static int __init
+i4l_idi_init(void)
+{
+  int ret = 0;
+  char tmprev[50];
+
+  status_lock = SPIN_LOCK_UNLOCKED;
+  ll_lock = SPIN_LOCK_UNLOCKED;
+
+  MOD_INC_USE_COUNT;
+
+  if (strlen(id) < 1)
+    strcpy(id, "diva");
+
+  DebugVar = debug;
+
+  init_MUTEX_LOCKED(&diva_thread_sem);
+  init_MUTEX_LOCKED(&diva_thread_end);
+
+  printk(KERN_INFO "%s\n", DRIVERNAME);
+  printk(KERN_INFO "%s: Rel:%s  Rev:",DRIVERLNAME , DRIVERRELEASE);
+  strcpy(tmprev, eicon_revision);
+  printk("%s/", eicon_getrev(tmprev));
+  strcpy(tmprev, eicon_idi_revision);
+  printk("%s\n", eicon_getrev(tmprev));
+
+  diva_init_thread();
+
+  if(!connect_didd()) {
+    printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME);
+    stop_diva_thread();
+    ret = -EIO;
+    goto out;
+  }    
+  create_proc();
+
+out:
+  MOD_DEC_USE_COUNT;
+  return(ret);
+}
+
+static void __exit
+i4l_idi_exit(void)
+{
+  eicon_card *card, *last, *cc;
+  ulong flags;
+
+  spin_lock_irqsave(&ll_lock, flags);
+  cc = cards;
+  card = cc;
+  cards = NULL;
+  spin_unlock_irqrestore(&ll_lock, flags);
+
+  remove_proc();
+
+  while (card) {
+    unregister_card(card, 1); 
+    card = card->next;
+  }
+
+  stop_diva_thread();
+  disconnect_didd();
+
+  card = cc;
+  while (card) {
+    last = card;
+    card = card->next;
+    eicon_freecard(last);
+  }
+  printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(i4l_idi_init);
+module_exit(i4l_idi_exit);
diff -Nru a/drivers/isdn/hardware/eicon/i4lididrv.h b/drivers/isdn/hardware/eicon/i4lididrv.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/i4lididrv.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,272 @@
+/* $Id: i4lididrv.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards.
+ * I4L - IDI Interface
+ *
+ * Copyright 1998-2000  by Armin Schindler (mac@melware.de) 
+ * Copyright 1999-2002  Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+
+#ifndef i4lididrv_h
+#define i4lididrv_h
+
+#include <linux/isdn.h>
+#include <linux/isdnif.h>
+
+#include "platform.h"
+#include "di_defs.h"
+
+#define EICON_IOCTL_GETTYPE   6
+#define EICON_IOCTL_LOADPCI   7 
+#define EICON_IOCTL_GETVER    9 
+#define EICON_IOCTL_GETXLOG  10 
+
+#define EICON_IOCTL_MANIF    90 
+
+#define EICON_IOCTL_FREEIT   97
+#define EICON_IOCTL_TEST     98
+#define EICON_IOCTL_DEBUGVAR 99
+
+/* Constants for describing Card-Type */
+#define EICON_CTYPE_S            0
+#define EICON_CTYPE_SX           1
+#define EICON_CTYPE_SCOM         2
+#define EICON_CTYPE_QUADRO       3
+#define EICON_CTYPE_S2M          4
+#define EICON_CTYPE_MAESTRA      5
+#define EICON_CTYPE_MAESTRAQ     6
+#define EICON_CTYPE_MAESTRAQ_U   7
+#define EICON_CTYPE_MAESTRAP     8
+#define EICON_CTYPE_ISABRI       0x10
+#define EICON_CTYPE_ISAPRI       0x20
+#define EICON_CTYPE_MASK         0x0f
+#define EICON_CTYPE_QUADRO_NR(n) (n<<4)
+
+#define MAX_HEADER_LEN 10
+
+#define MAX_STATUS_BUFFER	150
+
+/* Data for Management interface */
+typedef struct {
+	int count;
+	int pos;
+	int length[50];
+	unsigned char data[700]; 
+} eicon_manifbuf;
+
+#define TRACE_OK                 (1)
+
+#ifdef __KERNEL__
+
+/* Macro for delay via schedule() */
+#define SLEEP(j) {                     \
+  set_current_state(TASK_INTERRUPTIBLE); \
+  schedule_timeout(j);                 \
+}
+
+/* Kernel includes */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+
+typedef struct {
+  __u16 length __attribute__ ((packed)); /* length of data/parameter field */
+  __u8  P[1];                          /* data/parameter field */
+} eicon_PBUFFER;
+
+typedef struct {
+  __u16 NextReq  __attribute__ ((packed));  /* pointer to next Req Buffer */
+  __u16 NextRc   __attribute__ ((packed));  /* pointer to next Rc Buffer  */
+  __u16 NextInd  __attribute__ ((packed));  /* pointer to next Ind Buffer */
+  __u8 ReqInput  __attribute__ ((packed));  /* number of Req Buffers sent */
+  __u8 ReqOutput  __attribute__ ((packed)); /* number of Req Buffers returned */
+  __u8 ReqReserved  __attribute__ ((packed));/*number of Req Buffers reserved */
+  __u8 Int  __attribute__ ((packed));       /* ISDN-P interrupt           */
+  __u8 XLock  __attribute__ ((packed));     /* Lock field for arbitration */
+  __u8 RcOutput  __attribute__ ((packed));  /* number of Rc buffers received */
+  __u8 IndOutput  __attribute__ ((packed)); /* number of Ind buffers received */
+  __u8 IMask  __attribute__ ((packed));     /* Interrupt Mask Flag        */
+  __u8 Reserved1[2]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 ReadyInt  __attribute__ ((packed));  /* request field for ready int */
+  __u8 Reserved2[12]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 InterfaceType  __attribute__ ((packed)); /* interface type 1=16K    */
+  __u16 Signature  __attribute__ ((packed));    /* ISDN-P initialized ind  */
+  __u8 B[1];                            /* buffer space for Req,Ind and Rc */
+} eicon_pr_ram;
+
+typedef struct {
+  __u8                  Req;            /* pending request          */
+  __u8                  Rc;             /* return code received     */
+  __u8                  Ind;            /* indication received      */
+  __u8                  ReqCh;          /* channel of current Req   */
+  __u8                  RcCh;           /* channel of current Rc    */
+  __u8                  IndCh;          /* channel of current Ind   */
+  __u8                  D3Id;           /* ID used by this entity   */
+  __u8                  B2Id;           /* ID used by this entity   */
+  __u8                  GlobalId;       /* reserved field           */
+  __u8                  XNum;           /* number of X-buffers      */
+  __u8                  RNum;           /* number of R-buffers      */
+  struct sk_buff_head   X;              /* X-buffer queue           */
+  struct sk_buff_head   R;              /* R-buffer queue           */
+  __u8                  RNR;            /* receive not ready flag   */
+  __u8                  complete;       /* receive complete status  */
+  __u8                  busy;           /* busy flag                */
+  __u16                 ref;            /* saved reference          */
+} entity;
+
+#define FAX_MAX_SCANLINE 2500 
+
+typedef struct {
+	__u8		PrevObject;
+	__u8		NextObject;
+	__u8		abLine[FAX_MAX_SCANLINE];
+	__u8		abFrame[FAX_MAX_SCANLINE];
+	unsigned int	LineLen;
+	unsigned int	LineDataLen;
+	__u32		LineData;
+	unsigned int	NullBytesPos;
+	__u8		NullByteExist;
+	int		PageCount;
+	__u8		Dle;
+	__u8		Eop;
+} eicon_ch_fax_buf;
+
+typedef struct {
+	int	       No;		 /* Channel Number	        */
+	unsigned short fsm_state;        /* Current D-Channel state     */
+	unsigned short statectrl;	 /* State controling bits	*/
+	unsigned short eazmask;          /* EAZ-Mask for this Channel   */
+	int		queued;          /* User-Data Bytes in TX queue */
+	int		pqueued;         /* User-Data Packets in TX queue */
+	int		waitq;           /* User-Data Bytes in wait queue */
+	int		waitpq;          /* User-Data Bytes in packet queue */
+	struct sk_buff *tskb1;           /* temp skb 1			*/
+	struct sk_buff *tskb2;           /* temp skb 2			*/
+	unsigned char  l2prot;           /* Layer 2 protocol            */
+	unsigned char  l3prot;           /* Layer 3 protocol            */
+#ifdef CONFIG_ISDN_TTY_FAX
+	T30_s		*fax;		 /* pointer to fax data in LL	*/
+	eicon_ch_fax_buf fax2;		 /* fax related struct		*/
+#endif
+	entity		e;		 /* Native Entity		*/
+	ENTITY		de;		 /* Divas D Entity 		*/
+	ENTITY		be;		 /* Divas B Entity 		*/
+	char		cpn[32];	 /* remember cpn		*/
+	char		oad[32];	 /* remember oad		*/
+	char		dsa[32];	 /* remember dsa		*/
+	char		osa[32];	 /* remember osa		*/
+	unsigned char   cause[2];	 /* Last Cause			*/
+	unsigned char	si1;
+	unsigned char	si2;
+	unsigned char	plan;
+	unsigned char	screen;
+        unsigned char   a_para[8];       /* Additional parameter        */
+} eicon_chan;
+
+typedef struct {
+	eicon_chan *ptr;
+} eicon_chan_ptr;
+
+
+#define EICON_FLAGS_RUNNING  1 /* Cards driver activated */
+#define EICON_FLAGS_LOADED   8 /* Firmware loaded        */
+
+/* D-Channel states */
+#define EICON_STATE_NULL     0
+#define EICON_STATE_ICALL    1
+#define EICON_STATE_OCALL    2
+#define EICON_STATE_IWAIT    3
+#define EICON_STATE_OWAIT    4
+#define EICON_STATE_IBWAIT   5
+#define EICON_STATE_OBWAIT   6
+#define EICON_STATE_BWAIT    7
+#define EICON_STATE_BHWAIT   8
+#define EICON_STATE_BHWAIT2  9
+#define EICON_STATE_DHWAIT  10
+#define EICON_STATE_DHWAIT2 11
+#define EICON_STATE_BSETUP  12
+#define EICON_STATE_ACTIVE  13
+#define EICON_STATE_ICALLW  14
+#define EICON_STATE_LISTEN  15
+#define EICON_STATE_WMCONN  16
+
+#define EICON_MAX_QUEUE  2138
+
+typedef struct {
+	__u8 ret;
+	__u8 id;
+	__u8 ch;
+} eicon_ack;
+
+typedef struct {
+	__u8 code;
+	__u8 id;
+	__u8 ch;
+} eicon_req;
+
+typedef struct {
+	__u8 ret;
+	__u8 id;
+	__u8 ch;
+	__u8 more;
+} eicon_indhdr;
+
+/*
+ * Per card driver data
+ */
+typedef struct eicon_card {
+	DESCRIPTOR d;			 /* IDI Descriptor		     */
+        u_char ptype;                    /* Protocol type (1TR6 or Euro)     */
+        u_char type;                     /* Cardtype (EICON_CTYPE_...)       */
+	struct eicon_card *qnext;  	 /* Pointer to next quadro adapter   */
+        int Feature;                     /* Protocol Feature Value           */
+        struct eicon_card *next;	 /* Pointer to next device struct    */
+        int myid;                        /* Driver-Nr. assigned by linklevel */
+        unsigned long flags;             /* Statusflags                      */
+	struct sk_buff_head rcvq;        /* Receive-Message queue            */
+	struct sk_buff_head sndq;        /* Send-Message queue               */
+	struct sk_buff_head rackq;       /* Req-Ack-Message queue            */
+	struct sk_buff_head sackq;       /* Data-Ack-Message queue           */
+	struct sk_buff_head statq;       /* Status-Message queue             */
+	int statq_entries;
+	eicon_chan*	IdTable[256];	 /* Table to find entity   */
+	__u16  ref_in;
+	__u16  ref_out;
+	int    nchannels;                /* Number of B-Channels             */
+	int    ReadyInt;		 /* Ready Interrupt		     */
+	eicon_chan *bch;                 /* B-Channel status/control         */
+	DBUFFER *dbuf;			 /* Dbuffer for Diva Server	     */
+	BUFFERS *sbuf;			 /* Buffer for Diva Server	     */
+	char *sbufp;			 /* Data Buffer for Diva Server	     */
+        isdn_if interface;               /* Interface to upper layer         */
+        char regname[35];                /* Drivers card name 		     */
+	spinlock_t lock;		 /* spin lock per card		     */
+        struct tq_struct tq;             /* task queue for thread            */
+} eicon_card;
+
+#include "i4l_idi.h"
+
+extern eicon_card *cards;
+extern char *eicon_ctype_name[];
+
+extern ulong DebugVar;
+extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
+extern void eicon_putstatus(eicon_card * card, char * buf);
+
+extern void eicon_tx_request(struct eicon_card *);
+
+extern spinlock_t eicon_lock;
+
+#endif  /* __KERNEL__ */
+
+#endif	/* i4lididrv_h */
diff -Nru a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/idifunc.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,318 @@
+/* $Id: idifunc.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * User Mode IDI Interface 
+ *
+ * Copyright 2000-2002 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "um_xdi.h"
+#include "um_idi.h"
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+extern char *DRIVERRELEASE;
+
+extern void DIVA_DIDD_Read (void *, int);
+extern int diva_user_mode_idi_create_adapter (const DESCRIPTOR*, int);
+extern void diva_user_mode_idi_remove_adapter (int);
+
+#define MAX_DESCRIPTORS  32
+
+static dword notify_handle;
+static DESCRIPTOR DAdapter;
+static DESCRIPTOR MAdapter;
+
+static void no_printf (unsigned char * x ,...)
+{
+  /* dummy debug function */
+}
+DIVA_DI_PRINTF dprintf = no_printf;
+
+#include "debuglib.c"
+
+/*
+ * stop debug
+ */
+static void stop_dbg(void)
+{
+		DbgDeregister();
+		memset(&MAdapter, 0, sizeof(MAdapter));
+		dprintf = no_printf;
+}
+
+typedef struct _udiva_card {
+    struct _udiva_card *next;
+    int Id;
+    DESCRIPTOR  d;
+} udiva_card;
+
+static udiva_card *cards;
+static diva_os_spin_lock_t ll_lock;
+
+/*
+ * add card to list
+ */
+static void add_card_to_list(udiva_card *c)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "add card");
+  c->next = cards;
+  cards = c;
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "add card");
+}
+
+/*
+ * find card in list
+ */
+static udiva_card * find_card_in_list(DESCRIPTOR *d)
+{
+  udiva_card *card;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "find card");
+  card = cards;
+  while(card) {
+    if (card->d.request == d->request) {
+			diva_os_leave_spin_lock (&ll_lock, &old_irql, "find card");
+      return(card);
+    }
+    card = card->next;
+  }
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "find card");
+  return((udiva_card *)NULL);
+}
+
+/*
+ * remove card from list
+ */
+static void remove_card_from_list(udiva_card *c)
+{
+  udiva_card *list = NULL, *last;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "remove card");
+  list = cards;
+  last = list;
+  while(list) {
+    if(list == c) {
+      if(cards == c) {
+        cards = c->next;
+      } else {
+        last->next = c->next;
+      }
+      break;
+    }
+    last = list;
+    list = list->next;
+  }
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "remove card");
+}
+
+/*
+ * new card
+ */
+static void um_new_card(DESCRIPTOR *d)
+{
+  int adapter_nr = 0;
+  udiva_card *card = NULL;
+  IDI_SYNC_REQ sync_req;
+
+  if(!(card = diva_os_malloc(0, sizeof(udiva_card)))) {
+    DBG_ERR(("cannot get buffer for card"));
+    return;
+  }
+  memcpy(&card->d, d, sizeof(DESCRIPTOR));
+  sync_req.xdi_logical_adapter_number.Req = 0;
+  sync_req.xdi_logical_adapter_number.Rc = IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
+  card->d.request((ENTITY *)&sync_req);
+  adapter_nr = sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
+  card->Id = adapter_nr;
+  if(!(diva_user_mode_idi_create_adapter(d, adapter_nr))) {
+    add_card_to_list(card);
+  } else {
+    DBG_ERR(("could not create user mode idi card %d", adapter_nr));
+  }
+}
+
+/*
+ * remove card
+ */
+static void um_remove_card(DESCRIPTOR *d)
+{
+  udiva_card *card = NULL;
+
+  if(!(card = find_card_in_list(d))) {
+    DBG_ERR(("cannot find card to remove"));
+    return;
+  }
+  diva_user_mode_idi_remove_adapter(card->Id);
+  remove_card_from_list(card);
+  DBG_LOG(("idi proc entry removed for card %d", card->Id));
+  diva_os_free(0, card);
+}
+
+/*
+ * remove all adapter
+ */
+static void DIVA_EXIT_FUNCTION remove_all_idi_proc(void)
+{
+  udiva_card *card, *last;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock (&ll_lock, &old_irql, "remove all");
+  card = cards;
+  cards = NULL;
+	diva_os_leave_spin_lock (&ll_lock, &old_irql, "remove all");
+
+  while(card) {
+    diva_user_mode_idi_remove_adapter(card->Id);
+    last = card;
+    card = card->next;
+    diva_os_free(0, last);
+  }
+}
+
+/*
+ * DIDD notify callback
+ */
+static void * didd_callback(void *context, DESCRIPTOR* adapter, int removal)
+{
+  if (adapter->type == IDI_DADAPTER)
+  {
+    DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
+    return(NULL);
+  }
+  else if (adapter->type == IDI_DIMAINT)
+  {
+    if (removal)
+    {
+				stop_dbg();
+    }
+    else
+    {
+      memcpy(&MAdapter, adapter, sizeof(MAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      DbgRegister("User IDI", DRIVERRELEASE, DBG_DEFAULT);
+    }
+  }
+  else if ((adapter->type > 0) &&
+           (adapter->type < 16))
+  {  /* IDI Adapter */
+    if (removal)
+    {
+      um_remove_card(adapter);
+    }
+    else
+    {
+      um_new_card(adapter);
+    }
+  }
+  return(NULL);
+}
+
+/*
+ * connect DIDD
+ */
+static int DIVA_INIT_FUNCTION connect_didd(void)
+{
+  int x = 0;
+  int dadapter = 0;
+  IDI_SYNC_REQ req;
+  DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+  DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+  for (x = 0; x < MAX_DESCRIPTORS; x++)
+  {
+    if (DIDD_Table[x].type == IDI_DADAPTER)
+    {  /* DADAPTER found */
+      dadapter = 1;
+      memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      req.didd_notify.e.Req = 0;
+      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+      req.didd_notify.info.callback = didd_callback;
+      req.didd_notify.info.context = 0;
+      DAdapter.request((ENTITY *)&req);
+      if (req.didd_notify.e.Rc != 0xff)
+			{
+					stop_dbg();
+					return(0);
+			}
+      notify_handle = req.didd_notify.info.handle;
+    }
+    else if (DIDD_Table[x].type == IDI_DIMAINT)
+    {  /* MAINT found */
+      memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      DbgRegister("User IDI", DRIVERRELEASE, DBG_DEFAULT);
+    }
+    else if ((DIDD_Table[x].type > 0) &&
+             (DIDD_Table[x].type < 16))
+    {  /* IDI Adapter found */
+      um_new_card(&DIDD_Table[x]);
+    }
+  }
+
+	if (!dadapter)
+	{
+			stop_dbg();
+	}
+	
+  return(dadapter);
+}
+
+/*
+ *  Disconnect from DIDD
+ */
+static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+{
+  IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+  req.didd_notify.e.Req = 0;
+  req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+  req.didd_notify.info.handle = notify_handle;
+  DAdapter.request((ENTITY *)&req);
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION idifunc_init(void)
+{
+	diva_os_initialize_spin_lock (&ll_lock, "idifunc");
+
+	if (diva_user_mode_idi_init ()) {
+    DBG_ERR(("init: init failed."));
+		return(0);
+  }
+
+	if(!connect_didd()) {
+		diva_user_mode_idi_finit ();
+    DBG_ERR(("init: failed to connect to DIDD."));
+		return(0);
+  }
+  return(1);
+}
+
+/*
+ * finit
+ */
+void DIVA_EXIT_FUNCTION idifunc_finit(void)
+{
+  diva_user_mode_idi_finit ();
+  disconnect_didd();
+  remove_all_idi_proc();
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/io.c b/drivers/isdn/hardware/eicon/io.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/io.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,817 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "divasync.h"
+#define MIPS_SCOM
+#include "pkmaint.h" /* pc_main.h, packed in os-dependent fashion */
+#include "di.h"
+#include "mi_pc.h"
+#include "io.h"
+extern ADAPTER * adapter[MAX_ADAPTER];
+extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+void request (PISDN_ADAPTER, ENTITY *);
+void pcm_req (PISDN_ADAPTER, ENTITY *);
+/* --------------------------------------------------------------------------
+  local functions
+  -------------------------------------------------------------------------- */
+#define ReqFunc(N) \
+static void Request##N(ENTITY *e) \
+{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }
+ReqFunc(0)
+ReqFunc(1)
+ReqFunc(2)
+ReqFunc(3)
+ReqFunc(4)
+ReqFunc(5)
+ReqFunc(6)
+ReqFunc(7)
+ReqFunc(8)
+ReqFunc(9)
+ReqFunc(10)
+ReqFunc(11)
+ReqFunc(12)
+ReqFunc(13)
+ReqFunc(14)
+ReqFunc(15)
+IDI_CALL Requests[MAX_ADAPTER] =
+{ &Request0, &Request1, &Request2, &Request3,
+ &Request4, &Request5, &Request6, &Request7,
+ &Request8, &Request9, &Request10, &Request11,
+ &Request12, &Request13, &Request14, &Request15
+};
+/*****************************************************************************/
+/*
+  This array should indicate all new services, that this version of XDI
+  is able to provide to his clients
+  */
+static byte extended_xdi_features[DIVA_XDI_EXTENDED_FEATURES_MAX_SZ+1] = {
+ (DIVA_XDI_EXTENDED_FEATURES_VALID       |
+  DIVA_XDI_EXTENDED_FEATURE_CMA          |
+  DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR    |
+  DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS    |
+#if defined(DIVA_IDI_RX_DMA)
+  DIVA_XDI_EXTENDED_FEATURE_RX_DMA       |
+#endif
+  DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC),
+ 0
+};
+/*****************************************************************************/
+void
+dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc)
+{
+ dword   logLen ;
+ word *Xlog   = xlogDesc->buf ;
+ word  logCnt = xlogDesc->cnt ;
+ word  logOut = xlogDesc->out / sizeof(*Xlog) ;
+ DBG_FTL(("%s: ************* XLOG recovery (%d) *************",
+          &IoAdapter->Name[0], (int)logCnt))
+ DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0]))
+ for ( ; logCnt > 0 ; --logCnt )
+ {
+  if ( !READ_WORD(&Xlog[logOut]) )
+  {
+   if ( --logCnt == 0 )
+    break ;
+   logOut = 0 ;
+  }
+  if ( READ_WORD(&Xlog[logOut]) <= (logOut * sizeof(*Xlog)) )
+  {
+   if ( logCnt > 2 )
+   {
+    DBG_FTL(("Possibly corrupted XLOG: %d entries left",
+             (int)logCnt))
+   }
+   break ;
+  }
+  logLen = (dword)(READ_WORD(&Xlog[logOut]) - (logOut * sizeof(*Xlog))) ;
+  DBG_FTL_MXLOG(( (char *)&Xlog[logOut + 1], (dword)(logLen - 2) ))
+  logOut = (READ_WORD(&Xlog[logOut]) + 1) / sizeof(*Xlog) ;
+ }
+ DBG_FTL(("%s: ***************** end of XLOG *****************",
+          &IoAdapter->Name[0]))
+}
+/*****************************************************************************/
+char *(ExceptionCauseTable[]) =
+{
+ "Interrupt",
+ "TLB mod /IBOUND",
+ "TLB load /DBOUND",
+ "TLB store",
+ "Address error load",
+ "Address error store",
+ "Instruction load bus error",
+ "Data load/store bus error",
+ "Syscall",
+ "Breakpoint",
+ "Reverd instruction",
+ "Coprocessor unusable",
+ "Overflow",
+ "TRAP",
+ "VCEI",
+ "Floating Point Exception",
+ "CP2",
+ "Reserved 17",
+ "Reserved 18",
+ "Reserved 19",
+ "Reserved 20",
+ "Reserved 21",
+ "Reserved 22",
+ "WATCH",
+ "Reserved 24",
+ "Reserved 25",
+ "Reserved 26",
+ "Reserved 27",
+ "Reserved 28",
+ "Reserved 29",
+ "Reserved 30",
+ "VCED"
+} ;
+void
+dump_trap_frame (PISDN_ADAPTER IoAdapter, byte *exceptionFrame)
+{
+ MP_XCPTC *xcept = (MP_XCPTC *)exceptionFrame ;
+ dword    *regs  = &xcept->regs[0] ;
+ DBG_FTL(("%s: ***************** CPU TRAPPED *****************",
+          &IoAdapter->Name[0]))
+ DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0]))
+ DBG_FTL(("Cause: %s",
+          ExceptionCauseTable[(READ_DWORD(&xcept->cr) & 0x0000007c) >> 2]))
+ DBG_FTL(("sr    0x%08x cr    0x%08x epc   0x%08x vaddr 0x%08x",
+          READ_DWORD(&xcept->sr), READ_DWORD(&xcept->cr),
+					READ_DWORD(&xcept->epc), READ_DWORD(&xcept->vaddr)))
+ DBG_FTL(("zero  0x%08x at    0x%08x v0    0x%08x v1    0x%08x",
+          READ_DWORD(&regs[ 0]), READ_DWORD(&regs[ 1]),
+					READ_DWORD(&regs[ 2]), READ_DWORD(&regs[ 3])))
+ DBG_FTL(("a0    0x%08x a1    0x%08x a2    0x%08x a3    0x%08x",
+          READ_DWORD(&regs[ 4]), READ_DWORD(&regs[ 5]),
+					READ_DWORD(&regs[ 6]), READ_DWORD(&regs[ 7])))
+ DBG_FTL(("t0    0x%08x t1    0x%08x t2    0x%08x t3    0x%08x",
+          READ_DWORD(&regs[ 8]), READ_DWORD(&regs[ 9]),
+					READ_DWORD(&regs[10]), READ_DWORD(&regs[11])))
+ DBG_FTL(("t4    0x%08x t5    0x%08x t6    0x%08x t7    0x%08x",
+          READ_DWORD(&regs[12]), READ_DWORD(&regs[13]),
+					READ_DWORD(&regs[14]), READ_DWORD(&regs[15])))
+ DBG_FTL(("s0    0x%08x s1    0x%08x s2    0x%08x s3    0x%08x",
+          READ_DWORD(&regs[16]), READ_DWORD(&regs[17]),
+					READ_DWORD(&regs[18]), READ_DWORD(&regs[19])))
+ DBG_FTL(("s4    0x%08x s5    0x%08x s6    0x%08x s7    0x%08x",
+          READ_DWORD(&regs[20]), READ_DWORD(&regs[21]),
+					READ_DWORD(&regs[22]), READ_DWORD(&regs[23])))
+ DBG_FTL(("t8    0x%08x t9    0x%08x k0    0x%08x k1    0x%08x",
+          READ_DWORD(&regs[24]), READ_DWORD(&regs[25]),
+					READ_DWORD(&regs[26]), READ_DWORD(&regs[27])))
+ DBG_FTL(("gp    0x%08x sp    0x%08x s8    0x%08x ra    0x%08x",
+          READ_DWORD(&regs[28]), READ_DWORD(&regs[29]),
+					READ_DWORD(&regs[30]), READ_DWORD(&regs[31])))
+ DBG_FTL(("md    0x%08x|%08x         resvd 0x%08x class 0x%08x",
+          READ_DWORD(&xcept->mdhi), READ_DWORD(&xcept->mdlo),
+					READ_DWORD(&xcept->reseverd), READ_DWORD(&xcept->xclass)))
+}
+/* --------------------------------------------------------------------------
+  Real XDI Request function
+  -------------------------------------------------------------------------- */
+void request(PISDN_ADAPTER IoAdapter, ENTITY * e)
+{
+ byte i;
+ diva_os_spin_lock_magic_t irql;
+/*
+ * if the Req field in the entity structure is 0,
+ * we treat this request as a special function call
+ */
+ if ( !e->Req )
+ {
+  IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e ;
+  switch (e->Rc)
+  {
+#if defined(DIVA_IDI_RX_DMA)
+    case IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION: {
+      diva_xdi_dma_descriptor_operation_t* pI = \
+                                   &syncReq->xdi_dma_descriptor_operation.info;
+      if (!IoAdapter->dma_map) {
+        pI->operation         = -1;
+        pI->descriptor_number = -1;
+        return;
+      }
+      diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op");
+      if (pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC) {
+        pI->descriptor_number = diva_alloc_dma_map_entry (\
+                               (struct _diva_dma_map_entry*)IoAdapter->dma_map);
+        if (pI->descriptor_number >= 0) {
+          dword dma_magic;
+          void* local_addr;
+          DBG_TRC(("A(%d) dma_alloc(%d)",
+                   IoAdapter->ANum, pI->descriptor_number))
+          diva_get_dma_map_entry (\
+                               (struct _diva_dma_map_entry*)IoAdapter->dma_map,
+                               pI->descriptor_number,
+                               &local_addr, &dma_magic);
+          pI->descriptor_address  = local_addr;
+          pI->descriptor_magic    = dma_magic;
+          pI->operation           = 0;
+        } else {
+          pI->operation           = -1;
+        }
+      } else if ((pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE) &&
+                 (pI->descriptor_number >= 0)) {
+        DBG_TRC(("A(%d) dma_free(%d)", IoAdapter->ANum, pI->descriptor_number))
+        diva_free_dma_map_entry((struct _diva_dma_map_entry*)IoAdapter->dma_map,
+                                pI->descriptor_number);
+        pI->descriptor_number = -1;
+        pI->operation         = 0;
+      } else {
+        pI->descriptor_number = -1;
+        pI->operation         = -1;
+      }
+      diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op");
+    } return;
+#endif
+    case IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER: {
+      diva_xdi_get_logical_adapter_number_s_t *pI = \
+                                     &syncReq->xdi_logical_adapter_number.info;
+      pI->logical_adapter_number = IoAdapter->ANum;
+      pI->controller = IoAdapter->ControllerNumber;
+    } return;
+    case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: {
+       diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info;
+       memset (&prms, 0x00, sizeof(prms));
+       prms.structure_length = MIN(sizeof(prms), pI->structure_length);
+       memset (pI, 0x00, pI->structure_length);
+       prms.flag_dynamic_l1_down    = (IoAdapter->capi_cfg.cfg_1 & \
+         DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? 1 : 0;
+       prms.group_optimization_enabled = (IoAdapter->capi_cfg.cfg_1 & \
+         DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) ? 1 : 0;
+       memcpy (pI, &prms, prms.structure_length);
+      } return;
+    case IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR:
+      syncReq->xdi_sdram_bar.info.bar = IoAdapter->sdram_bar;
+      return;
+    case IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES: {
+      dword i;
+      diva_xdi_get_extended_xdi_features_t* pI =\
+                                 &syncReq->xdi_extended_features.info;
+      pI->buffer_length_in_bytes &= ~0x80000000;
+      if (pI->buffer_length_in_bytes && pI->features) {
+        memset (pI->features, 0x00, pI->buffer_length_in_bytes);
+      }
+      for (i = 0; ((pI->features) && (i < pI->buffer_length_in_bytes) &&
+                   (i < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ)); i++) {
+        pI->features[i] = extended_xdi_features[i];
+      }
+      if ((pI->buffer_length_in_bytes < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ) ||
+          (!pI->features)) {
+        pI->buffer_length_in_bytes =\
+                           (0x80000000 | DIVA_XDI_EXTENDED_FEATURES_MAX_SZ);
+      }
+     } return;
+    case IDI_SYNC_REQ_XDI_GET_STREAM:
+      if (IoAdapter) {
+        diva_xdi_provide_istream_info (&IoAdapter->a,
+                                       &syncReq->xdi_stream_info.info);
+      } else {
+        syncReq->xdi_stream_info.info.provided_service = 0;
+      }
+      return;
+  case IDI_SYNC_REQ_GET_NAME:
+   if ( IoAdapter )
+   {
+    strcpy (&syncReq->GetName.name[0], IoAdapter->Name) ;
+    DBG_TRC(("xdi: Adapter %d / Name '%s'",
+             IoAdapter->ANum, IoAdapter->Name))
+    return ;
+   }
+   syncReq->GetName.name[0] = '\0' ;
+   break ;
+  case IDI_SYNC_REQ_GET_SERIAL:
+   if ( IoAdapter )
+   {
+    syncReq->GetSerial.serial = IoAdapter->serialNo ;
+    DBG_TRC(("xdi: Adapter %d / SerialNo %ld",
+             IoAdapter->ANum, IoAdapter->serialNo))
+    return ;
+   }
+   syncReq->GetSerial.serial = 0 ;
+   break ;
+  case IDI_SYNC_REQ_GET_XLOG:
+   if ( IoAdapter )
+   {
+    pcm_req (IoAdapter, e) ;
+    return ;
+   }
+   e->Ind = 0 ;
+   break ;
+  case IDI_SYNC_REQ_GET_FEATURES:
+   if ( IoAdapter )
+   {
+    syncReq->GetFeatures.features =
+      (unsigned short)IoAdapter->features ;
+    return ;
+   }
+   syncReq->GetFeatures.features = 0 ;
+   break ;
+        case IDI_SYNC_REQ_PORTDRV_HOOK:
+            if ( IoAdapter )
+            {
+                DBG_TRC(("Xdi:IDI_SYNC_REQ_PORTDRV_HOOK - ignored"))
+                return ;
+            }
+            break;
+  }
+  if ( IoAdapter )
+  {
+   DBG_FTL(("xdi: unknown Req 0 / Rc %d !", e->Rc))
+   return ;
+  }
+ }
+ DBG_TRC(("xdi: Id 0x%x / Req 0x%x / Rc 0x%x", e->Id, e->Req, e->Rc))
+ if ( !IoAdapter )
+ {
+  DBG_FTL(("xdi: uninitialized Adapter used - ignore request"))
+  return ;
+ }
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+/*
+ * assign an entity
+ */
+ if ( !(e->Id &0x1f) )
+ {
+  if ( IoAdapter->e_count >= IoAdapter->e_max )
+  {
+   DBG_FTL(("xdi: all Ids in use (max=%d) --> Req ignored",
+            IoAdapter->e_max))
+   diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+   return ;
+  }
+/*
+ * find a new free id
+ */
+  for ( i = 1 ; IoAdapter->e_tbl[i].e ; ++i ) ;
+  IoAdapter->e_tbl[i].e = e ;
+  IoAdapter->e_count++ ;
+  e->No = (byte)i ;
+  e->More = 0 ;
+  e->RCurrent = 0xff ;
+ }
+ else
+ {
+  i = e->No ;
+ }
+/*
+ * if the entity is still busy, ignore the request call
+ */
+ if ( e->More & XBUSY )
+ {
+  DBG_FTL(("xdi: Id 0x%x busy --> Req 0x%x ignored", e->Id, e->Req))
+  if ( !IoAdapter->trapped && IoAdapter->trapFnc )
+  {
+   IoAdapter->trapFnc (IoAdapter) ;
+      /*
+        Firs trap, also notify user if supported
+       */
+      if (IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) {
+        (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum);
+      }
+  }
+  diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+  return ;
+ }
+/*
+ * initialize transmit status variables
+ */
+ e->More |= XBUSY ;
+ e->More &= ~XMOREF ;
+ e->XCurrent = 0 ;
+ e->XOffset = 0 ;
+/*
+ * queue this entity in the adapter request queue
+ */
+ IoAdapter->e_tbl[i].next = 0 ;
+ if ( IoAdapter->head )
+ {
+  IoAdapter->e_tbl[IoAdapter->tail].next = i ;
+  IoAdapter->tail = i ;
+ }
+ else
+ {
+  IoAdapter->head = i ;
+  IoAdapter->tail = i ;
+ }
+/*
+ * queue the DPC to process the request
+ */
+ diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+}
+/* ---------------------------------------------------------------------
+  Main DPC routine
+   --------------------------------------------------------------------- */
+void DIDpcRoutine (struct _diva_os_soft_isr* psoft_isr, void* Context) {
+ PISDN_ADAPTER IoAdapter  = (PISDN_ADAPTER)Context ;
+ ADAPTER* a        = &IoAdapter->a ;
+ diva_os_atomic_t* pin_dpc = &IoAdapter->in_dpc;
+ if (diva_os_atomic_increment (pin_dpc) == 1) {
+  do {
+   if ( IoAdapter->tst_irq (a) )
+   {
+    if ( !IoAdapter->Unavailable )
+     IoAdapter->dpc (a) ;
+    IoAdapter->clr_irq (a) ;
+   }
+   IoAdapter->out (a) ;
+  } while (diva_os_atomic_decrement (pin_dpc) > 0);
+  /* ----------------------------------------------------------------
+    Look for XLOG request (cards with indirect addressing)
+    ---------------------------------------------------------------- */
+  if (IoAdapter->pcm_pending) {
+   struct pc_maint *pcm;
+   diva_os_spin_lock_magic_t OldIrql ;
+   diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_dpc");
+   pcm = (struct pc_maint *)IoAdapter->pcm_data;
+   switch (IoAdapter->pcm_pending) {
+    case 1: /* ask card for XLOG */
+     a->ram_out (a, &IoAdapter->pcm->rc, 0) ;
+     a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ;
+     IoAdapter->pcm_pending = 2;
+     break;
+    case 2: /* Try to get XLOG from the card */
+     if ((int)(a->ram_in (a, &IoAdapter->pcm->rc))) {
+      a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ;
+      IoAdapter->pcm_pending = 3;
+     }
+     break;
+    case 3: /* let XDI recovery XLOG */
+     break;
+   }
+   diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_dpc");
+  }
+  /* ---------------------------------------------------------------- */
+ }
+}
+/* --------------------------------------------------------------------------
+  XLOG interface
+  -------------------------------------------------------------------------- */
+void
+pcm_req (PISDN_ADAPTER IoAdapter, ENTITY *e)
+{
+ diva_os_spin_lock_magic_t OldIrql ;
+ int              i, rc ;
+ ADAPTER         *a = &IoAdapter->a ;
+ struct pc_maint *pcm = (struct pc_maint *)&e->Ind ;
+/*
+ * special handling of I/O based card interface
+ * the memory access isn't an atomic operation !
+ */
+ if ( IoAdapter->Properties.Card == CARD_MAE )
+ {
+  diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_1");
+  IoAdapter->pcm_data = (unsigned long)pcm;
+  IoAdapter->pcm_pending = 1;
+  diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
+  diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_1");
+  for ( rc = 0, i = (IoAdapter->trapped ? 3000 : 250) ; !rc && (i > 0) ; --i )
+  {
+   diva_os_sleep (1) ;
+   if (IoAdapter->pcm_pending == 3) {
+    diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+                 &OldIrql,
+                 "data_pcm_3");
+    IoAdapter->pcm_pending = 0;
+    IoAdapter->pcm_data   = 0;
+    diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+                 &OldIrql,
+                 "data_pcm_3");
+    return ;
+   }
+   diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_pcm_2");
+   diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
+   diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_pcm_2");
+  }
+  diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_4");
+  IoAdapter->pcm_pending = 0;
+  IoAdapter->pcm_data   = 0;
+  diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_4");
+  goto Trapped ;
+ }
+/*
+ * memory based shared ram is accessable from different
+ * processors without disturbing concurrent processes.
+ */
+ a->ram_out (a, &IoAdapter->pcm->rc, 0) ;
+ a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ;
+ for ( i = (IoAdapter->trapped ? 3000 : 250) ; --i > 0 ; )
+ {
+  diva_os_sleep (1) ;
+  rc = (int)(a->ram_in (a, &IoAdapter->pcm->rc)) ;
+  if ( rc )
+  {
+   a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ;
+   return ;
+  }
+ }
+Trapped:
+ if ( IoAdapter->trapFnc )
+ {
+    int trapped = IoAdapter->trapped;
+  IoAdapter->trapFnc (IoAdapter) ;
+    /*
+      Firs trap, also notify user if supported
+     */
+    if (!trapped && IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) {
+      (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum);
+    }
+ }
+}
+/*------------------------------------------------------------------*/
+/* ram access functions for memory mapped cards                     */
+/*------------------------------------------------------------------*/
+byte mem_in (ADAPTER *a, void *addr)
+{
+ byte* Base = (byte*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ return (*Base) ;
+}
+word mem_inw (ADAPTER *a, void *addr)
+{
+ word* Base = (word*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ return (READ_WORD(Base)) ;
+}
+void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords)
+{
+ volatile dword* Base = (dword*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ while (dwords--) {
+  *data++ = READ_DWORD(Base);
+  Base++;
+ }
+}
+void mem_in_buffer (ADAPTER *a, void *addr, void *buffer, word length)
+{
+ byte* Base = (byte*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ memcpy (buffer, Base, length) ;
+}
+void mem_look_ahead (ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+ PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
+ IoAdapter->RBuffer.length = mem_inw (a, &RBuffer->length) ;
+ mem_in_buffer (a, RBuffer->P, IoAdapter->RBuffer.P,
+                IoAdapter->RBuffer.length) ;
+ e->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
+}
+void mem_out (ADAPTER *a, void *addr, byte data)
+{
+ byte* Base = (byte*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ *Base = data ;
+}
+void mem_outw (ADAPTER *a, void *addr, word data)
+{
+ word* Base = (word*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ WRITE_WORD(Base, data);
+}
+void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords)
+{
+ volatile dword* Base = (dword*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ while (dwords--) {
+	WRITE_DWORD(Base, *data);
+  Base++;
+	data++;
+ }
+}
+void mem_out_buffer (ADAPTER *a, void *addr, void *buffer, word length)
+{
+ byte* Base = (byte*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ memcpy (Base, buffer, length) ;
+}
+void mem_inc (ADAPTER *a, void *addr)
+{
+ byte* Base = (byte*)&((PISDN_ADAPTER)a->io)->ram[(unsigned long)addr] ;
+ byte  x = *Base ;
+ *Base = x + 1 ;
+}
+/*------------------------------------------------------------------*/
+/* ram access functions for io-mapped cards                         */
+/*------------------------------------------------------------------*/
+byte io_in(ADAPTER * a, void * adr)
+{
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  return inpp(((PISDN_ADAPTER)a->io)->port);
+}
+word io_inw(ADAPTER * a, void * adr)
+{
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  return inppw(((PISDN_ADAPTER)a->io)->port);
+}
+void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len)
+{
+ byte* P = (byte*)buffer;
+  if ((long)adr & 1) {
+    outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+    *P = inpp(((PISDN_ADAPTER)a->io)->port);
+    P++;
+    adr = ((byte *) adr) + 1;
+    len--;
+    if (!len) return;
+  }
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  inppw_buffer (((PISDN_ADAPTER)a->io)->port, P, len+1);
+}
+void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e)
+{
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)RBuffer);
+  ((PISDN_ADAPTER)a->io)->RBuffer.length = inppw(((PISDN_ADAPTER)a->io)->port);
+  inppw_buffer (((PISDN_ADAPTER)a->io)->port, ((PISDN_ADAPTER)a->io)->RBuffer.P, ((PISDN_ADAPTER)a->io)->RBuffer.length + 1);
+  e->RBuffer = (DBUFFER *) &(((PISDN_ADAPTER)a->io)->RBuffer);
+}
+void io_out(ADAPTER * a, void * adr, byte data)
+{
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  outpp(((PISDN_ADAPTER)a->io)->port, data);
+}
+void io_outw(ADAPTER * a, void * adr, word data)
+{
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  outppw(((PISDN_ADAPTER)a->io)->port, data);
+}
+void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len)
+{
+ byte* P = (byte*)buffer;
+  if ((long)adr & 1) {
+    outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+    outpp(((PISDN_ADAPTER)a->io)->port, *P);
+    P++;
+    adr = ((byte *) adr) + 1;
+    len--;
+    if (!len) return;
+  }
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  outppw_buffer (((PISDN_ADAPTER)a->io)->port, P, len+1);
+}
+void io_inc(ADAPTER * a, void * adr)
+{
+  byte x;
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  x = inpp(((PISDN_ADAPTER)a->io)->port);
+  outppw(((PISDN_ADAPTER)a->io)->port+4, (word)(unsigned long)adr);
+  outpp(((PISDN_ADAPTER)a->io)->port, x+1);
+}
+/*------------------------------------------------------------------*/
+/* OS specific functions related to queuing of entities             */
+/*------------------------------------------------------------------*/
+void free_entity(ADAPTER * a, byte e_no)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free");
+  IoAdapter->e_tbl[e_no].e = NULL;
+  IoAdapter->e_count--;
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free");
+}
+void assign_queue(ADAPTER * a, byte e_no, word ref)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign");
+  IoAdapter->e_tbl[e_no].assign_ref = ref;
+  IoAdapter->e_tbl[e_no].next = (byte)IoAdapter->assign;
+  IoAdapter->assign = e_no;
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign");
+}
+byte get_assign(ADAPTER * a, word ref)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  byte e_no;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+              &irql,
+              "data_assign_get");
+  for(e_no = (byte)IoAdapter->assign;
+      e_no && IoAdapter->e_tbl[e_no].assign_ref!=ref;
+      e_no = IoAdapter->e_tbl[e_no].next);
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+              &irql,
+              "data_assign_get");
+  return e_no;
+}
+void req_queue(ADAPTER * a, byte e_no)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q");
+  IoAdapter->e_tbl[e_no].next = 0;
+  if(IoAdapter->head) {
+    IoAdapter->e_tbl[IoAdapter->tail].next = e_no;
+    IoAdapter->tail = e_no;
+  }
+  else {
+    IoAdapter->head = e_no;
+    IoAdapter->tail = e_no;
+  }
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q");
+}
+byte look_req(ADAPTER * a)
+{
+  PISDN_ADAPTER IoAdapter;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+  return ((byte)IoAdapter->head) ;
+}
+void next_req(ADAPTER * a)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next");
+  IoAdapter->head = IoAdapter->e_tbl[IoAdapter->head].next;
+  if(!IoAdapter->head) IoAdapter->tail = 0;
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next");
+}
+/*------------------------------------------------------------------*/
+/* memory map functions                                             */
+/*------------------------------------------------------------------*/
+ENTITY * entity_ptr(ADAPTER * a, byte e_no)
+{
+  PISDN_ADAPTER IoAdapter;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+  return (IoAdapter->e_tbl[e_no].e);
+}
+void * PTR_X(ADAPTER * a, ENTITY * e)
+{
+  return ((void *) e->X);
+}
+void * PTR_R(ADAPTER * a, ENTITY * e)
+{
+  return ((void *) e->R);
+}
+void * PTR_P(ADAPTER * a, ENTITY * e, void * P)
+{
+  return P;
+}
+void CALLBACK(ADAPTER * a, ENTITY * e)
+{
+ if ( e && e->callback )
+  e->callback (e) ;
+}
+/* --------------------------------------------------------------------------
+  routines for aligned reading and writing on RISC
+  -------------------------------------------------------------------------- */
+void outp_words_from_buffer (word* adr, byte* P, word len)
+{
+  word i = 0;
+  word w;
+  while (i < (len & 0xfffe)) {
+    w = P[i++];
+    w += (P[i++])<<8;
+    outppw (adr, w);
+  }
+}
+void inp_words_to_buffer (word* adr, byte* P, word len)
+{
+  word i = 0;
+  word w;
+  while (i < (len & 0xfffe)) {
+    w = inppw (adr);
+    P[i++] = (byte)(w);
+    P[i++] = (byte)(w>>8);
+  }
+}
diff -Nru a/drivers/isdn/hardware/eicon/io.h b/drivers/isdn/hardware/eicon/io.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/io.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,281 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_XDI_COMMON_IO_H_INC__ /* { */
+#define __DIVA_XDI_COMMON_IO_H_INC__
+/*
+ maximum = 16 adapters
+ */
+#define DI_MAX_LINKS    MAX_ADAPTER
+#define ISDN_MAX_NUM_LEN 60
+/* --------------------------------------------------------------------------
+  structure for quadro card management (obsolete for
+  systems that do provide per card load event)
+  -------------------------------------------------------------------------- */
+typedef struct {
+ dword         Num ;
+ DEVICE_NAME   DeviceName[4] ;
+ PISDN_ADAPTER QuadroAdapter[4] ;
+} ADAPTER_LIST_ENTRY, *PADAPTER_LIST_ENTRY ;
+/* --------------------------------------------------------------------------
+  Special OS memory support structures
+  -------------------------------------------------------------------------- */
+#define MAX_MAPPED_ENTRIES 8
+typedef struct {
+ void  * Address;
+ dword    Length;
+} ADAPTER_MEMORY ;
+/* --------------------------------------------------------------------------
+  Configuration of XDI clients carried by XDI
+  -------------------------------------------------------------------------- */
+#define DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON      0x01
+#define DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON 0x02
+typedef struct _diva_xdi_capi_cfg {
+  byte cfg_1;
+} diva_xdi_capi_cfg_t;
+/* --------------------------------------------------------------------------
+  Main data structure kept per adapter
+  -------------------------------------------------------------------------- */
+struct _ISDN_ADAPTER {
+ void             (* DIRequest)(PISDN_ADAPTER, ENTITY *) ;
+ int                 Initialized ;
+ int         RegisteredWithDidd ;
+ int                 Unavailable ;  /* callback function possible? */
+ int         ResourcesClaimed ;
+ int         PnpBiosConfigUsed ;
+ dword        Logging ;
+ dword        features ;
+ char        ProtocolIdString[80] ;
+ /*
+  remember mapped memory areas
+ */
+ ADAPTER_MEMORY     MappedMemory[MAX_MAPPED_ENTRIES] ;
+ CARD_PROPERTIES     Properties ;
+ dword               cardType ;
+ dword               protocol_id ;       /* configured protocol identifier */
+ char                protocol_name[8] ;  /* readable name of protocol */
+ dword               BusType ;
+ dword               BusNumber ;
+ dword               slotNumber ;
+ dword               slotId ;
+ dword               ControllerNumber ;  /* for QUADRO cards only */
+ PISDN_ADAPTER       MultiMaster ;       /* for 4-BRI card only - use MultiMaster or QuadroList */
+ PADAPTER_LIST_ENTRY QuadroList ;        /* for QUADRO card  only */
+ PDEVICE_OBJECT      DeviceObject ;
+ dword               DeviceId ;
+ diva_os_adapter_irq_info_t irq_info;
+ dword volatile      IrqCount ;
+ int                 trapped ;
+ dword               DspCodeBaseAddr ;
+ dword               MaxDspCodeSize ;
+ dword               downloadAddr ;
+ dword               DspCodeBaseAddrTable[4] ; /* add. for MultiMaster */
+ dword               MaxDspCodeSizeTable[4] ; /* add. for MultiMaster */
+ dword               downloadAddrTable[4] ; /* add. for MultiMaster */
+ dword               MemoryBase ;
+ dword               MemorySize ;
+ byte       *Address ;
+ byte       *reset ;
+ byte       *port ;
+ byte       *ram ;
+ byte       *cfg ;
+ byte       *prom ;
+ byte       *ctlReg ;
+ struct pc_maint  *pcm ;
+ diva_os_dependent_devica_name_t os_name;
+ byte                Name[32] ;
+ dword               serialNo ;
+ dword               ANum ;
+ dword               ArchiveType ; /* ARCHIVE_TYPE_NONE ..._SINGLE ..._USGEN ..._MULTI */
+ char               *ProtocolSuffix ; /* internal protocolfile table */
+ char                Archive[32] ;
+ char                Protocol[32] ;
+ char                Oad1[ISDN_MAX_NUM_LEN] ;
+ char                Osa1[ISDN_MAX_NUM_LEN] ;
+ char                Oad2[ISDN_MAX_NUM_LEN] ;
+ char                Osa2[ISDN_MAX_NUM_LEN] ;
+ char                Spid1[ISDN_MAX_NUM_LEN] ;
+ char                Spid2[ISDN_MAX_NUM_LEN] ;
+  byte                nosig ;
+  byte                BriLayer2LinkCount ; /* amount of TEI's that adapter will support in P2MP mode */
+ dword               Channels ;
+ dword               tei ;
+ dword               nt2 ;
+ dword               TerminalCount ;
+ dword               WatchDog ;
+ dword               Permanent ;
+ dword               BChMask ; /* B channel mask for unchannelized modes */
+ dword               StableL2 ;
+ dword               DidLen ;
+ dword               NoOrderCheck ;
+ dword               ForceLaw; /* VoiceCoding - default:0, a-law: 1, my-law: 2 */
+ dword               SigFlags ;
+ dword               LowChannel ;
+ dword               NoHscx30 ;
+ dword               ProtVersion ;
+ dword               crc4 ;
+ dword               L1TristateOrQsig ; /* enable Layer 1 Tristate (bit 2)Or Qsig params (bit 0,1)*/
+ dword               InitialDspInfo ;
+ dword               ModemGuardTone ;
+ dword               ModemMinSpeed ;
+ dword               ModemMaxSpeed ;
+ dword               ModemOptions ;
+ dword               ModemOptions2 ;
+ dword               ModemNegotiationMode ;
+ dword               ModemModulationsMask ;
+ dword               ModemTransmitLevel ;
+ dword               FaxOptions ;
+ dword               FaxMaxSpeed ;
+ dword               Part68LevelLimiter ;
+ dword               UsEktsNumCallApp ;
+ byte                UsEktsFeatAddConf ;
+ byte                UsEktsFeatRemoveConf ;
+ byte                UsEktsFeatCallTransfer ;
+ byte                UsEktsFeatMsgWaiting ;
+ byte                QsigDialect;
+ byte                ForceVoiceMailAlert;
+ byte                DisableAutoSpid;
+ byte                ModemCarrierWaitTimeSec;
+ byte                ModemCarrierLossWaitTimeTenthSec;
+ byte                PiafsLinkTurnaroundInFrames;
+ word                QsigFeatures;
+ dword               GenerateRingtone ;
+ diva_os_spin_lock_t isr_spin_lock;
+ diva_os_spin_lock_t data_spin_lock;
+ diva_os_soft_isr_t req_soft_isr;
+ diva_os_soft_isr_t isr_soft_isr;
+ diva_os_atomic_t  in_dpc;
+ PBUFFER             RBuffer;        /* Copy of receive lookahead buffer */
+ word                e_max;
+ word                e_count;
+ E_INFO             *e_tbl;
+ word                assign;         /* list of pending ASSIGNs  */
+ word                head;           /* head of request queue    */
+ word                tail;           /* tail of request queue    */
+ ADAPTER             a ;             /* not a seperate structure */
+ void        (* out)(ADAPTER * a) ;
+ byte        (* dpc)(ADAPTER * a) ;
+ byte        (* tst_irq)(ADAPTER * a) ;
+ void        (* clr_irq)(ADAPTER * a) ;
+ int         (* load)(PISDN_ADAPTER) ;
+ int         (* mapmem)(PISDN_ADAPTER) ;
+ int         (* chkIrq)(PISDN_ADAPTER) ;
+ void        (* disIrq)(PISDN_ADAPTER) ;
+ void        (* start)(PISDN_ADAPTER) ;
+ void        (* stop)(PISDN_ADAPTER) ;
+ void        (* rstFnc)(PISDN_ADAPTER) ;
+ void        (* trapFnc)(PISDN_ADAPTER) ;
+ void        (* os_trap_nfy_Fnc)(PISDN_ADAPTER, dword) ;
+ diva_os_isr_callback_t diva_isr_handler;
+ dword               sdram_bar;
+ dword               fpga_features;
+ volatile int        pcm_pending;
+ volatile unsigned long      pcm_data;
+ diva_xdi_capi_cfg_t capi_cfg;
+ dword               tasks;
+ void*               dma_map;
+};
+/* ---------------------------------------------------------------------
+  Entity table
+   --------------------------------------------------------------------- */
+struct e_info_s {
+  ENTITY *      e;
+  byte          next;                   /* chaining index           */
+  word          assign_ref;             /* assign reference         */
+};
+/* ---------------------------------------------------------------------
+  S-cards shared ram structure for loading
+   --------------------------------------------------------------------- */
+struct s_load {
+ byte ctrl;
+ byte card;
+ byte msize;
+ byte fill0;
+ word ebit;
+ word elocl;
+ word eloch;
+ byte reserved[20];
+ word signature;
+ byte fill[224];
+ byte b[256];
+};
+#define PR_RAM  ((struct pr_ram *)0)
+#define RAM ((struct dual *)0)
+/* ---------------------------------------------------------------------
+  Functions for port io
+   --------------------------------------------------------------------- */
+void outp_words_from_buffer (word* adr, byte* P, word len);
+void inp_words_to_buffer  (word* adr, byte* P, word len);
+/* ---------------------------------------------------------------------
+  platform specific conversions
+   --------------------------------------------------------------------- */
+extern void * PTR_P(ADAPTER * a, ENTITY * e, void * P);
+extern void * PTR_X(ADAPTER * a, ENTITY * e);
+extern void * PTR_R(ADAPTER * a, ENTITY * e);
+extern void CALLBACK(ADAPTER * a, ENTITY * e);
+extern void set_ram(void * * adr_ptr);
+/* ---------------------------------------------------------------------
+  ram access functions for io mapped cards
+   --------------------------------------------------------------------- */
+byte io_in(ADAPTER * a, void * adr);
+word io_inw(ADAPTER * a, void * adr);
+void io_in_buffer(ADAPTER * a, void * adr, void * P, word length);
+void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
+void io_out(ADAPTER * a, void * adr, byte data);
+void io_outw(ADAPTER * a, void * adr, word data);
+void io_out_buffer(ADAPTER * a, void * adr, void * P, word length);
+void io_inc(ADAPTER * a, void * adr);
+/* ---------------------------------------------------------------------
+  ram access functions for memory mapped cards
+   --------------------------------------------------------------------- */
+byte mem_in(ADAPTER * a, void * adr);
+word mem_inw(ADAPTER * a, void * adr);
+void mem_in_buffer(ADAPTER * a, void * adr, void * P, word length);
+void mem_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
+void mem_out(ADAPTER * a, void * adr, byte data);
+void mem_outw(ADAPTER * a, void * adr, word data);
+void mem_out_buffer(ADAPTER * a, void * adr, void * P, word length);
+void mem_inc(ADAPTER * a, void * adr);
+void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords);
+void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords);
+/* ---------------------------------------------------------------------
+  functions exported by io.c
+   --------------------------------------------------------------------- */
+extern IDI_CALL Requests[MAX_ADAPTER] ;
+extern void     DIDpcRoutine (struct _diva_os_soft_isr* psoft_isr,
+               void* context);
+extern void     request (PISDN_ADAPTER, ENTITY *) ;
+/* ---------------------------------------------------------------------
+  trapFn helpers, used to recover debug trace from dead card
+   --------------------------------------------------------------------- */
+typedef struct {
+ word *buf ;
+ word  cnt ;
+ word  out ;
+} Xdesc ;
+extern void     dump_trap_frame  (PISDN_ADAPTER IoAdapter, byte *exception) ;
+extern void     dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc) ;
+/* --------------------------------------------------------------------- */
+#endif  /* } __DIVA_XDI_COMMON_IO_H_INC__ */
diff -Nru a/drivers/isdn/hardware/eicon/istream.c b/drivers/isdn/hardware/eicon/istream.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/istream.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,226 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#if defined(DIVA_ISTREAM) /* { */
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "di.h"
+#if !defined USE_EXTENDED_DEBUGS
+  #include "dimaint.h"
+#else
+  #define dprintf
+#endif
+#include "dfifo.h"
+int diva_istream_write (void* context,
+             int   Id,
+              void* data,
+             int length,
+             int final,
+            byte usr1,
+            byte usr2);
+int diva_istream_read (void* context,
+            int Id,
+            void* data,
+            int max_length,
+            int* final,
+            byte* usr1,
+            byte* usr2);
+/* -------------------------------------------------------------------
+  Does provide iStream interface to the client
+   ------------------------------------------------------------------- */
+void diva_xdi_provide_istream_info (ADAPTER* a,
+                  diva_xdi_stream_interface_t* pi) {
+  pi->provided_service = 0;
+}
+/* ------------------------------------------------------------------
+  Does write the data from caller's buffer to the card's
+  stream interface.
+  If synchronous service was requested, then function
+  does return amount of data written to stream.
+  'final' does indicate that pice of data to be written is
+  final part of frame (necessary only by structured datatransfer)
+  return  0 if zero lengh packet was written
+  return -1 if stream is full
+  ------------------------------------------------------------------ */
+int diva_istream_write (void* context,
+                int   Id,
+                  void* data,
+                 int length,
+                 int final,
+                byte usr1,
+                byte usr2) {
+ ADAPTER* a = (ADAPTER*)context;
+ int written = 0, to_write = -1;
+ char tmp[4];
+ byte* data_ptr = (byte*)data;
+ for (;;) {
+  a->ram_in_dw (a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]),
+#else
+         (void*)(a->tx_stream[Id] + a->tx_pos[Id]),
+#endif
+                  (dword*)&tmp[0],
+         1);
+  if (tmp[0] & DIVA_DFIFO_READY) { /* No free blocks more */
+   if (to_write < 0)
+    return (-1); /* was not able to write       */
+   break;     /* only part of message was written */
+  }
+  to_write = MIN(length, DIVA_DFIFO_DATA_SZ);
+  if (to_write) {
+   a->ram_out_buffer (a,
+#ifdef PLATFORM_GT_32BIT
+            ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]+4),
+#else
+              (void*)(a->tx_stream[Id] + a->tx_pos[Id] + 4),
+#endif
+                         data_ptr,
+             (word)to_write);
+   length  -= to_write;
+   written  += to_write;
+   data_ptr += to_write;
+  }
+  tmp[1] = (char)to_write;
+  tmp[0] = (tmp[0] & DIVA_DFIFO_WRAP) |
+       DIVA_DFIFO_READY |
+       ((!length && final) ? DIVA_DFIFO_LAST : 0);
+  if (tmp[0] & DIVA_DFIFO_LAST) {
+   tmp[2] = usr1;
+   tmp[3] = usr2;
+  }
+    a->ram_out_dw (a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]),
+#else
+           (void*)(a->tx_stream[Id] + a->tx_pos[Id]),
+#endif
+                   (dword*)&tmp[0],
+          1);
+  if (tmp[0] & DIVA_DFIFO_WRAP) {
+   a->tx_pos[Id]  = 0;
+  } else {
+   a->tx_pos[Id] += DIVA_DFIFO_STEP;
+  }
+  if (!length) {
+   break;
+  }
+ }
+ return (written);
+}
+/* -------------------------------------------------------------------
+  In case of SYNCRONOUS service:
+  Does write data from stream in caller's buffer.
+  Does return amount of data written to buffer
+  Final flag is set on return if last part of structured frame
+  was received
+  return 0  if zero packet was received
+  return -1 if stream is empty
+    return -2 if read buffer does not profide sufficient space
+              to accomodate entire segment
+  max_length should be at least 68 bytes
+  ------------------------------------------------------------------- */
+int diva_istream_read (void* context,
+                int Id,
+                void* data,
+                int max_length,
+                int* final,
+               byte* usr1,
+               byte* usr2) {
+ ADAPTER* a = (ADAPTER*)context;
+ int read = 0, to_read = -1;
+ char tmp[4];
+ byte* data_ptr = (byte*)data;
+ *final = 0;
+ for (;;) {
+  a->ram_in_dw (a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id]),
+#else
+         (void*)(a->rx_stream[Id] + a->rx_pos[Id]),
+#endif
+                  (dword*)&tmp[0],
+         1);
+  if (tmp[1] > max_length) {
+   if (to_read < 0)
+    return (-2); /* was not able to read */
+   break;
+    }
+  if (!(tmp[0] & DIVA_DFIFO_READY)) {
+   if (to_read < 0)
+    return (-1); /* was not able to read */
+   break;
+  }
+  to_read = MIN(max_length, tmp[1]);
+  if (to_read) {
+   a->ram_in_buffer(a,
+#ifdef PLATFORM_GT_32BIT
+           ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id] + 4),
+#else
+            (void*)(a->rx_stream[Id] + a->rx_pos[Id] + 4),
+#endif
+                       data_ptr,
+            (word)to_read);
+   max_length -= to_read;
+   read     += to_read;
+   data_ptr  += to_read;
+  }
+  if (tmp[0] & DIVA_DFIFO_LAST) {
+   *final = 1;
+  }
+  tmp[0] &= DIVA_DFIFO_WRAP;
+    a->ram_out_dw(a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id]),
+#else
+         (void*)(a->rx_stream[Id] + a->rx_pos[Id]),
+#endif
+         (dword*)&tmp[0],
+         1);
+  if (tmp[0] & DIVA_DFIFO_WRAP) {
+   a->rx_pos[Id]  = 0;
+  } else {
+   a->rx_pos[Id] += DIVA_DFIFO_STEP;
+  }
+  if (*final) {
+   if (usr1)
+    *usr1 = tmp[2];
+   if (usr2)
+    *usr2 = tmp[3];
+   break;
+  }
+ }
+ return (read);
+}
+/* ---------------------------------------------------------------------
+  Does check if one of streams had caused interrupt and does
+  wake up corresponding application
+   --------------------------------------------------------------------- */
+void pr_stream (ADAPTER * a) {
+}
+#endif /* } */
diff -Nru a/drivers/isdn/hardware/eicon/kst_ifc.h b/drivers/isdn/hardware/eicon/kst_ifc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/kst_ifc.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,336 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2000.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_EICON_TRACE_API__
+#define __DIVA_EICON_TRACE_API__
+
+#define DIVA_TRACE_LINE_TYPE_LEN 64
+#define DIVA_TRACE_IE_LEN        64
+#define DIVA_TRACE_FAX_PRMS_LEN  128
+
+typedef struct _diva_trace_ie {
+	byte length;
+	byte data[DIVA_TRACE_IE_LEN];
+} diva_trace_ie_t;
+
+/*
+	Structure used to represent "State\\BX\\Modem" directory
+	to user.
+	*/
+typedef struct _diva_trace_modem_state {
+	dword	ChannelNumber;
+
+	dword	Event;
+
+	dword	Norm;
+
+	dword Options; /* Options received from Application */
+
+	dword	TxSpeed;
+	dword	RxSpeed;
+
+	dword RoundtripMsec;
+
+	dword SymbolRate;
+
+	int		RxLeveldBm;
+	int		EchoLeveldBm;
+
+	dword	SNRdb;
+	dword MAE;
+
+	dword LocalRetrains;
+	dword RemoteRetrains;
+	dword LocalResyncs;
+	dword RemoteResyncs;
+
+	dword DiscReason;
+
+} diva_trace_modem_state_t;
+
+/*
+	Representation of "State\\BX\\FAX" directory
+	*/
+typedef struct _diva_trace_fax_state {
+	dword	ChannelNumber;
+	dword Event;
+	dword Page_Counter;
+	dword Features;
+	char Station_ID[DIVA_TRACE_FAX_PRMS_LEN];
+	char Subaddress[DIVA_TRACE_FAX_PRMS_LEN];
+	char Password[DIVA_TRACE_FAX_PRMS_LEN];
+	dword Speed;
+	dword Resolution;
+	dword Paper_Width;
+	dword Paper_Length;
+	dword Scanline_Time;
+	dword Disc_Reason;
+	dword	dummy;
+} diva_trace_fax_state_t;
+
+/*
+	Structure used to represent Interface State in the abstract
+	and interface/D-channel protocol independent form.
+	*/
+typedef struct _diva_trace_interface_state {
+	char Layer1[DIVA_TRACE_LINE_TYPE_LEN];
+	char Layer2[DIVA_TRACE_LINE_TYPE_LEN];
+} diva_trace_interface_state_t;
+
+typedef struct _diva_incoming_call_statistics {
+	dword Calls;
+	dword Connected;
+	dword User_Busy;
+	dword Call_Rejected;
+	dword Wrong_Number;
+	dword Incompatible_Dst;
+	dword Out_of_Order;
+	dword Ignored;
+} diva_incoming_call_statistics_t;
+
+typedef struct _diva_outgoing_call_statistics {
+	dword Calls;
+	dword Connected;
+	dword User_Busy;
+	dword No_Answer;
+	dword Wrong_Number;
+	dword Call_Rejected;
+	dword Other_Failures;
+} diva_outgoing_call_statistics_t;
+
+typedef struct _diva_modem_call_statistics {
+	dword Disc_Normal;
+	dword Disc_Unspecified;
+	dword Disc_Busy_Tone;
+	dword Disc_Congestion;
+	dword Disc_Carr_Wait;
+	dword Disc_Trn_Timeout;
+	dword Disc_Incompat;
+	dword Disc_Frame_Rej;
+	dword Disc_V42bis;
+} diva_modem_call_statistics_t;
+
+typedef struct _diva_fax_call_statistics {
+	dword Disc_Normal;
+	dword Disc_Not_Ident;
+	dword Disc_No_Response;
+	dword Disc_Retries;
+	dword Disc_Unexp_Msg;
+	dword Disc_No_Polling;
+	dword Disc_Training;
+	dword Disc_Unexpected;
+	dword Disc_Application;
+	dword Disc_Incompat;
+	dword Disc_No_Command;
+	dword Disc_Long_Msg;
+	dword Disc_Supervisor;
+	dword Disc_SUB_SEP_PWD;
+	dword Disc_Invalid_Msg;
+	dword Disc_Page_Coding;
+	dword Disc_App_Timeout;
+	dword Disc_Unspecified;
+} diva_fax_call_statistics_t;
+
+typedef struct _diva_prot_statistics {
+	dword X_Frames;
+	dword X_Bytes;
+	dword X_Errors;
+	dword R_Frames;
+	dword R_Bytes;
+	dword R_Errors;
+} diva_prot_statistics_t;
+
+typedef struct _diva_ifc_statistics {
+	diva_incoming_call_statistics_t	inc;
+	diva_outgoing_call_statistics_t outg;
+	diva_modem_call_statistics_t		mdm;
+	diva_fax_call_statistics_t			fax;
+	diva_prot_statistics_t					b1;
+	diva_prot_statistics_t					b2;
+	diva_prot_statistics_t					d1;
+	diva_prot_statistics_t					d2;
+} diva_ifc_statistics_t;
+
+/*
+	Structure used to represent "State\\BX" directory
+	to user.
+	*/
+typedef struct _diva_trace_line_state {
+	dword	ChannelNumber;
+
+	char Line[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char Framing[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char Layer2[DIVA_TRACE_LINE_TYPE_LEN];
+	char Layer3[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char RemoteAddress[DIVA_TRACE_LINE_TYPE_LEN];
+	char RemoteSubAddress[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char LocalAddress[DIVA_TRACE_LINE_TYPE_LEN];
+	char LocalSubAddress[DIVA_TRACE_LINE_TYPE_LEN];
+
+	diva_trace_ie_t	call_BC;
+	diva_trace_ie_t	call_HLC;
+	diva_trace_ie_t	call_LLC;
+
+	dword Charges;
+
+	dword CallReference;
+
+	dword LastDisconnecCause;
+
+	char UserID[DIVA_TRACE_LINE_TYPE_LEN];
+
+	diva_trace_modem_state_t modem;
+	diva_trace_fax_state_t   fax;
+
+	diva_trace_interface_state_t* pInterface;
+
+	diva_ifc_statistics_t*				pInterfaceStat;
+
+} diva_trace_line_state_t;
+
+#define DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE             ('l')
+#define DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE            ('m')
+#define DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE              ('f')
+#define DIVA_SUPER_TRACE_INTERFACE_CHANGE               ('i')
+#define DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE             ('s')
+#define DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE         ('M')
+#define DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE         ('F')
+
+struct _diva_strace_library_interface;
+typedef void (*diva_trace_channel_state_change_proc_t)(void* user_context,
+							struct _diva_strace_library_interface* hLib,
+							int Adapter,
+							diva_trace_line_state_t* channel, int notify_subject);
+typedef void (*diva_trace_channel_trace_proc_t)(void* user_context,
+							struct _diva_strace_library_interface* hLib,
+							int Adapter, void* xlog_buffer, int length);
+typedef void (*diva_trace_error_proc_t)(void* user_context,
+							struct _diva_strace_library_interface* hLib,
+							int Adapter,
+							int error, const char* file, int line);
+
+/*
+	This structure creates interface from user to library
+	*/
+typedef struct _diva_trace_library_user_interface {
+	void*																		user_context;
+	diva_trace_channel_state_change_proc_t	notify_proc;
+	diva_trace_channel_trace_proc_t					trace_proc;
+	diva_trace_error_proc_t									error_notify_proc;
+} diva_trace_library_user_interface_t;
+
+/*
+	Interface from Library to User
+	*/
+typedef int   (*DivaSTraceLibraryStart_proc_t)(void* hLib);
+typedef int   (*DivaSTraceLibraryFinit_proc_t)(void* hLib);
+typedef int   (*DivaSTraceMessageInput_proc_t)(void* hLib);
+typedef void*	(*DivaSTraceGetHandle_proc_t)(void* hLib);
+
+/*
+	Turn Audio Tap trace on/off
+	Channel should be in the range 1 ... Number of Channels
+	*/
+typedef int (*DivaSTraceSetAudioTap_proc_t)(void* hLib, int Channel, int on);
+
+/*
+	Turn B-channel trace on/off
+	Channel should be in the range 1 ... Number of Channels
+	*/
+typedef int (*DivaSTraceSetBChannel_proc_t)(void* hLib, int Channel, int on);
+
+/*
+	Turn	D-channel (Layer1/Layer2/Layer3) trace on/off
+		Layer1 - All D-channel frames received/sent over the interface
+						 inclusive Layer 2 headers, Layer 2 frames and TEI management frames
+		Layer2 - Events from LAPD protocol instance with SAPI of signalling protocol
+		Layer3 - All D-channel frames addressed to assigned to the card TEI and
+						 SAPI of signalling protocol, and signalling protocol events.
+	*/
+typedef int (*DivaSTraceSetDChannel_proc_t)(void* hLib, int on);
+
+/*
+	Get overall card statistics
+	*/
+typedef int (*DivaSTraceGetOutgoingCallStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetIncomingCallStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetModemStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetFaxStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetBLayer1Statistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetBLayer2Statistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetDLayer1Statistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetDLayer2Statistics_proc_t)(void* hLib);
+
+/*
+	Call control
+	*/
+typedef int (*DivaSTraceClearCall_proc_t)(void* hLib, int Channel);
+
+typedef struct _diva_strace_library_interface {
+	void* hLib;
+  DivaSTraceLibraryStart_proc_t DivaSTraceLibraryStart;
+  DivaSTraceLibraryStart_proc_t DivaSTraceLibraryStop;
+	DivaSTraceLibraryFinit_proc_t DivaSTraceLibraryFinit;
+	DivaSTraceMessageInput_proc_t DivaSTraceMessageInput;
+	DivaSTraceGetHandle_proc_t    DivaSTraceGetHandle;
+	DivaSTraceSetAudioTap_proc_t  DivaSTraceSetAudioTap;
+	DivaSTraceSetBChannel_proc_t  DivaSTraceSetBChannel;
+	DivaSTraceSetDChannel_proc_t  DivaSTraceSetDChannel;
+	DivaSTraceSetDChannel_proc_t  DivaSTraceSetInfo;
+	DivaSTraceGetOutgoingCallStatistics_proc_t \
+																DivaSTraceGetOutgoingCallStatistics;
+	DivaSTraceGetIncomingCallStatistics_proc_t \
+																DivaSTraceGetIncomingCallStatistics;
+	DivaSTraceGetModemStatistics_proc_t \
+																DivaSTraceGetModemStatistics;
+	DivaSTraceGetFaxStatistics_proc_t \
+																DivaSTraceGetFaxStatistics;
+	DivaSTraceGetBLayer1Statistics_proc_t \
+																DivaSTraceGetBLayer1Statistics;
+	DivaSTraceGetBLayer2Statistics_proc_t \
+																DivaSTraceGetBLayer2Statistics;
+	DivaSTraceGetDLayer1Statistics_proc_t \
+																DivaSTraceGetDLayer1Statistics;
+	DivaSTraceGetDLayer2Statistics_proc_t \
+																DivaSTraceGetDLayer2Statistics;
+	DivaSTraceClearCall_proc_t    DivaSTraceClearCall;
+} diva_strace_library_interface_t;
+
+/*
+	Create and return Library interface
+	*/
+diva_strace_library_interface_t* DivaSTraceLibraryCreateInstance (int Adapter,
+													const diva_trace_library_user_interface_t* user_proc,
+                          byte* pmem);
+dword DivaSTraceGetMemotyRequirement (int channels);
+
+#define DIVA_MAX_ADAPTERS  64
+#define DIVA_MAX_LINES     32
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/main_if.h b/drivers/isdn/hardware/eicon/main_if.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/main_if.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,50 @@
+/*
+ *
+  Copyright (c) Eicon Technology Corporation, 2000.
+ *
+  This source file is supplied for the use with Eicon
+  Technology Corporation's range of DIVA Server Adapters.
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+/*------------------------------------------------------------------*/
+/* file: main_if.h                                                  */
+/*------------------------------------------------------------------*/
+# ifndef MAIN_IF___H
+# define MAIN_IF___H
+
+# include "debug_if.h"
+
+void  DI_lock (void) ;
+void  DI_unlock (void) ;
+
+#ifdef NOT_YET_NEEDED
+void  DI_nttime (LARGE_INTEGER *NTtime) ;
+void  DI_ntlcltime(LARGE_INTEGER *NTtime, LARGE_INTEGER *lclNTtime) ;
+void  DI_nttimefields(LARGE_INTEGER *NTtime, TIME_FIELDS *TimeFields);
+unsigned long  DI_wintime(LARGE_INTEGER *NTtime) ;
+
+unsigned short  DiInsertProcessorNumber (int type) ;
+void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap);
+
+void  StartIoctlTimer (void (*Handler)(void), unsigned long msec) ;
+void  StopIoctlTimer (void) ;
+void  UnpendIoctl (DbgRequest *pDbgReq) ;
+#endif
+
+void add_to_q(int, char* , unsigned int);
+# endif /* MAIN_IF___H */
+
diff -Nru a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/maintidi.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,2147 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2000.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "kst_ifc.h"
+#include "di_defs.h"
+#include "maintidi.h"
+#include "pc.h"
+#include "man_defs.h"
+
+
+extern void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...);
+
+#define MODEM_PARSE_ENTRIES  16 /* amount of variables of interest */
+#define FAX_PARSE_ENTRIES    12 /* amount of variables of interest */
+#define LINE_PARSE_ENTRIES   15 /* amount of variables of interest */
+#define STAT_PARSE_ENTRIES   70 /* amount of variables of interest */
+
+/*
+	LOCAL FUNCTIONS
+	*/
+static int DivaSTraceLibraryStart (void* hLib);
+static int DivaSTraceLibraryStop  (void* hLib);
+static int SuperTraceLibraryFinit (void* hLib);
+static void*	SuperTraceGetHandle (void* hLib);
+static int SuperTraceMessageInput (void* hLib);
+static int SuperTraceSetAudioTap  (void* hLib, int Channel, int on);
+static int SuperTraceSetBChannel  (void* hLib, int Channel, int on);
+static int SuperTraceSetDChannel  (void* hLib, int on);
+static int SuperTraceSetInfo      (void* hLib, int on);
+static int SuperTraceClearCall (void* hLib, int Channel);
+static int SuperTraceGetOutgoingCallStatistics (void* hLib);
+static int SuperTraceGetIncomingCallStatistics (void* hLib);
+static int SuperTraceGetModemStatistics (void* hLib);
+static int SuperTraceGetFaxStatistics (void* hLib);
+static int SuperTraceGetBLayer1Statistics (void* hLib);
+static int SuperTraceGetBLayer2Statistics (void* hLib);
+static int SuperTraceGetDLayer1Statistics (void* hLib);
+static int SuperTraceGetDLayer2Statistics (void* hLib);
+
+/*
+	LOCAL FUNCTIONS
+	*/
+static int ScheduleNextTraceRequest (diva_strace_context_t* pLib);
+static int process_idi_event (diva_strace_context_t* pLib,
+															diva_man_var_header_t* pVar);
+static int process_idi_info  (diva_strace_context_t* pLib,
+															diva_man_var_header_t* pVar);
+static int diva_modem_event (diva_strace_context_t* pLib, int Channel);
+static int diva_fax_event   (diva_strace_context_t* pLib, int Channel);
+static int diva_line_event (diva_strace_context_t* pLib, int Channel);
+static int diva_modem_info (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar);
+static int diva_fax_info   (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar);
+static int diva_line_info  (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar);
+static int diva_ifc_statistics (diva_strace_context_t* pLib,
+																diva_man_var_header_t* pVar);
+static diva_man_var_header_t* get_next_var (diva_man_var_header_t* pVar);
+static diva_man_var_header_t* find_var (diva_man_var_header_t* pVar,
+																				const char* name);
+static int diva_strace_read_int  (diva_man_var_header_t* pVar, int* var);
+static int diva_strace_read_uint (diva_man_var_header_t* pVar, dword* var);
+static int diva_strace_read_asz  (diva_man_var_header_t* pVar, char* var);
+static int diva_strace_read_asc  (diva_man_var_header_t* pVar, char* var);
+static int  diva_strace_read_ie  (diva_man_var_header_t* pVar,
+																	diva_trace_ie_t* var);
+static void diva_create_parse_table (diva_strace_context_t* pLib);
+static void diva_trace_error (diva_strace_context_t* pLib,
+															int error, const char* file, int line);
+static void diva_trace_notify_user (diva_strace_context_t* pLib,
+														 int Channel,
+														 int notify_subject);
+static int diva_trace_read_variable (diva_man_var_header_t* pVar,
+																		 void* variable);
+
+/*
+	Initialize the library and return context
+	of the created trace object that will represent
+	the IDI adapter.
+	Return 0 on error.
+	*/
+diva_strace_library_interface_t* DivaSTraceLibraryCreateInstance (int Adapter,
+											const diva_trace_library_user_interface_t* user_proc,
+                      byte* pmem) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)pmem;
+	int i;
+
+	if (!pLib) {
+		return (0);
+	}
+
+  pmem += sizeof(*pLib);
+	memset (pLib, 0x00, sizeof(pLib));
+
+	pLib->Adapter  = Adapter;
+
+	/*
+		Set up Library Interface
+		*/
+	pLib->instance.hLib                                = pLib;
+  pLib->instance.DivaSTraceLibraryStart              = DivaSTraceLibraryStart;
+  pLib->instance.DivaSTraceLibraryStop               = DivaSTraceLibraryStop;
+	pLib->instance.DivaSTraceLibraryFinit              = SuperTraceLibraryFinit;
+	pLib->instance.DivaSTraceMessageInput              = SuperTraceMessageInput;
+	pLib->instance.DivaSTraceGetHandle                 = SuperTraceGetHandle;
+	pLib->instance.DivaSTraceSetAudioTap               = SuperTraceSetAudioTap;
+	pLib->instance.DivaSTraceSetBChannel               = SuperTraceSetBChannel;
+	pLib->instance.DivaSTraceSetDChannel               = SuperTraceSetDChannel;
+	pLib->instance.DivaSTraceSetInfo                   = SuperTraceSetInfo;
+	pLib->instance.DivaSTraceGetOutgoingCallStatistics = \
+																			SuperTraceGetOutgoingCallStatistics;
+	pLib->instance.DivaSTraceGetIncomingCallStatistics = \
+																			SuperTraceGetIncomingCallStatistics;
+	pLib->instance.DivaSTraceGetModemStatistics        = \
+																			SuperTraceGetModemStatistics;
+	pLib->instance.DivaSTraceGetFaxStatistics          = \
+																			SuperTraceGetFaxStatistics;
+	pLib->instance.DivaSTraceGetBLayer1Statistics      = \
+																			SuperTraceGetBLayer1Statistics;
+	pLib->instance.DivaSTraceGetBLayer2Statistics      = \
+																			SuperTraceGetBLayer2Statistics;
+	pLib->instance.DivaSTraceGetDLayer1Statistics      = \
+																			SuperTraceGetDLayer1Statistics;
+	pLib->instance.DivaSTraceGetDLayer2Statistics      = \
+																			SuperTraceGetDLayer2Statistics;
+	pLib->instance.DivaSTraceClearCall                 = SuperTraceClearCall;
+
+
+	if (user_proc) {
+		pLib->user_proc_table.user_context      = user_proc->user_context;
+		pLib->user_proc_table.notify_proc       = user_proc->notify_proc;
+		pLib->user_proc_table.trace_proc        = user_proc->trace_proc;
+		pLib->user_proc_table.error_notify_proc = user_proc->error_notify_proc;
+	}
+
+	if (!(pLib->hAdapter = SuperTraceOpenAdapter (Adapter))) {
+    diva_mnt_internal_dprintf (0, DLI_ERR, "Can not open XDI adapter");
+		return (0);
+	}
+	pLib->Channels = SuperTraceGetNumberOfChannels (pLib->hAdapter);
+
+	/*
+		Calculate amount of parte table entites necessary to translate
+		information from all events of onterest
+		*/
+	pLib->parse_entries = (MODEM_PARSE_ENTRIES + FAX_PARSE_ENTRIES + \
+												 STAT_PARSE_ENTRIES + \
+												 LINE_PARSE_ENTRIES + 1) * pLib->Channels;
+	pLib->parse_table = (diva_strace_path2action_t*)pmem;
+
+	for (i = 0; i < 30; i++) {
+		pLib->lines[i].pInterface     = &pLib->Interface;
+		pLib->lines[i].pInterfaceStat = &pLib->InterfaceStat;
+	}
+
+  pLib->e.R = &pLib->RData;
+
+	pLib->req_busy = 1;
+	pLib->rc_ok    = ASSIGN_OK;
+
+	diva_create_parse_table (pLib);
+
+	return ((diva_strace_library_interface_t*)pLib);
+}
+
+static int DivaSTraceLibraryStart (void* hLib) {
+  diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+  return (SuperTraceASSIGN (pLib->hAdapter, pLib->buffer));
+}
+
+/*
+  Return (-1) on error
+  Return (0) if was initiated or pending
+  Return (1) if removal is complete
+  */
+static int DivaSTraceLibraryStop  (void* hLib) {
+  diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+  if (!pLib->e.Id) { /* Was never started/assigned */
+    return (1);
+  }
+
+  switch (pLib->removal_state) {
+    case 0:
+      pLib->removal_state = 1;
+      ScheduleNextTraceRequest(pLib);
+      break;
+
+    case 3:
+      return (1);
+  }
+
+  return (0);
+}
+
+static int SuperTraceLibraryFinit (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	if (pLib) {
+		if (pLib->hAdapter) {
+			SuperTraceCloseAdapter  (pLib->hAdapter);
+		}
+		return (0);
+	}
+	return (-1);
+}
+
+static void*	SuperTraceGetHandle (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+  return (&pLib->e);
+}
+
+/*
+	After library handle object is gone in signaled state
+	this function should be called and will pick up incoming
+	IDI messages (return codes and indications).
+	*/
+static int SuperTraceMessageInput (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	int ret = 0;
+  byte Rc, Ind;
+
+  if (pLib->e.complete == 255) {
+    /*
+      Process return code
+      */
+    pLib->req_busy = 0;
+    Rc             = pLib->e.Rc;
+    pLib->e.Rc     = 0;
+
+    if (pLib->removal_state == 2) {
+      pLib->removal_state = 3;
+      return (0);
+    }
+
+		if (Rc != pLib->rc_ok) {
+      int ignore = 0;
+      /*
+        Auto-detect amount of events/channels and features
+        */
+      if (pLib->general_b_ch_event == 1) {
+        pLib->general_b_ch_event = 2;
+        ignore = 1;
+      } else if (pLib->general_fax_event == 1) {
+        pLib->general_fax_event = 2;
+        ignore = 1;
+      } else if (pLib->general_mdm_event == 1) {
+        pLib->general_mdm_event = 2;
+        ignore = 1;
+      } else if ((pLib->ChannelsTraceActive < pLib->Channels) && pLib->ChannelsTraceActive) {
+        pLib->ChannelsTraceActive = pLib->Channels;
+        ignore = 1;
+      } else if (pLib->ModemTraceActive < pLib->Channels) {
+        pLib->ModemTraceActive = pLib->Channels;
+        ignore = 1;
+      } else if (pLib->FaxTraceActive < pLib->Channels) {
+        pLib->FaxTraceActive = pLib->Channels;
+        ignore = 1;
+      } else if (pLib->audio_trace_init == 2) {
+        ignore = 1;
+        pLib->audio_trace_init = 1;
+      } else if (pLib->eye_pattern_pending) {
+				pLib->eye_pattern_pending =  0;
+				ignore = 1;
+			} else if (pLib->audio_tap_pending) {
+				pLib->audio_tap_pending = 0;
+				ignore = 1;
+      }
+
+      if (!ignore) {
+        return (-1); /* request failed */
+      }
+    } else {
+      if (pLib->general_b_ch_event == 1) {
+        pLib->ChannelsTraceActive = pLib->Channels;
+        pLib->general_b_ch_event = 2;
+      } else if (pLib->general_fax_event == 1) {
+        pLib->general_fax_event = 2;
+        pLib->FaxTraceActive = pLib->Channels;
+      } else if (pLib->general_mdm_event == 1) {
+        pLib->general_mdm_event = 2;
+        pLib->ModemTraceActive = pLib->Channels;
+      }
+    }
+    if (pLib->audio_trace_init == 2) {
+      pLib->audio_trace_init = 1;
+    }
+    pLib->rc_ok = 0xff; /* default OK after assign was done */
+    if ((ret = ScheduleNextTraceRequest(pLib))) {
+      return (-1);
+    }
+  } else {
+    /*
+      Process indication
+      Always 'RNR' indication if return code is pending
+      */
+    Ind         = pLib->e.Ind;
+    pLib->e.Ind = 0;
+    if (pLib->removal_state) {
+      pLib->e.RNum	= 0;
+      pLib->e.RNR	= 2;
+    } else if (pLib->req_busy) {
+      pLib->e.RNum	= 0;
+      pLib->e.RNR	= 1;
+    } else {
+      if (pLib->e.complete != 0x02) {
+        /*
+          Look-ahead call, set up buffers
+          */
+        pLib->e.RNum       = 1;
+        pLib->e.R->P       = (byte*)&pLib->buffer[0];
+        pLib->e.R->PLength = (word)(sizeof(pLib->buffer) - 1);
+      } else {
+        /*
+          Indication reception complete, process it now
+          */
+        byte* p = (byte*)&pLib->buffer[0];
+        pLib->buffer[pLib->e.R->PLength] = 0; /* terminate I.E. with zero */
+        switch (Ind) {
+          case MAN_INFO_IND:
+            if (process_idi_info (pLib, (diva_man_var_header_t*)p)) {
+              return (-1);
+            }
+            break;
+					case MAN_EVENT_IND:
+            if (process_idi_event (pLib, (diva_man_var_header_t*)p)) {
+              return (-1);
+            }
+            break;
+          case MAN_TRACE_IND:
+            if (pLib->trace_on == 1) {
+              /*
+                Ignore first trace event that is result of
+                EVENT_ON operation
+              */
+              pLib->trace_on++;
+            } else {
+              /*
+                Delivery XLOG buffer to application
+                */
+              if (pLib->user_proc_table.trace_proc) {
+                (*(pLib->user_proc_table.trace_proc))(pLib->user_proc_table.user_context,
+                                                      &pLib->instance, pLib->Adapter,
+                                                      p, pLib->e.R->PLength);
+              }
+            }
+            break;
+          default:
+            diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind: %02x", Ind);
+        }
+      }
+    }
+  }
+
+	if ((ret = ScheduleNextTraceRequest(pLib))) {
+		return (-1);
+	}
+
+	return (ret);
+}
+
+/*
+	Internal state machine responsible for scheduling of requests
+	*/
+static int ScheduleNextTraceRequest (diva_strace_context_t* pLib) {
+	char name[64];
+	int ret = 0;
+	int i;
+
+	if (pLib->req_busy) {
+		return (0);
+	}
+
+  if (pLib->removal_state == 1) {
+		if (SuperTraceREMOVE (pLib->hAdapter)) {
+      pLib->removal_state = 3;
+    } else {
+      pLib->req_busy = 1;
+      pLib->removal_state = 2;
+    }
+    return (0);
+  }
+
+  if (pLib->removal_state) {
+    return (0);
+  }
+
+  if (!pLib->general_b_ch_event) {
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\B Event", pLib->buffer))) {
+      return (-1);
+    }
+    pLib->general_b_ch_event = 1;
+		pLib->req_busy = 1;
+		return (0);
+  }
+
+  if (!pLib->general_fax_event) {
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\FAX Event", pLib->buffer))) {
+      return (-1);
+    }
+    pLib->general_fax_event = 1;
+		pLib->req_busy = 1;
+		return (0);
+  }
+
+  if (!pLib->general_mdm_event) {
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\Modem Event", pLib->buffer))) {
+      return (-1);
+    }
+    pLib->general_mdm_event = 1;
+		pLib->req_busy = 1;
+		return (0);
+  }
+
+	if (pLib->ChannelsTraceActive < pLib->Channels) {
+		pLib->ChannelsTraceActive++;
+		sprintf (name, "State\\B%d\\Line", pLib->ChannelsTraceActive);
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->ChannelsTraceActive--;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->ModemTraceActive < pLib->Channels) {
+		pLib->ModemTraceActive++;
+		sprintf (name, "State\\B%d\\Modem\\Event", pLib->ModemTraceActive);
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->ModemTraceActive--;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->FaxTraceActive < pLib->Channels) {
+		pLib->FaxTraceActive++;
+		sprintf (name, "State\\B%d\\FAX\\Event", pLib->FaxTraceActive);
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->FaxTraceActive--;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_mask_init) {
+		word tmp = 0x0000;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\Event Enable",
+												 		&tmp,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->trace_mask_init = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->audio_trace_init) {
+		dword tmp = 0x00000000;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\AudioCh# Enable",
+												 		&tmp,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->audio_trace_init = 2;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->bchannel_init) {
+		dword tmp = 0x00000000;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\B-Ch# Enable",
+												 		&tmp,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->bchannel_init = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_length_init) {
+		word tmp = 30;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\Max Log Length",
+												 		&tmp,
+														0x82, /* MI_UINT */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->trace_length_init = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_on) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"Trace\\Log Buffer",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->trace_on = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->trace_event_mask != pLib->current_trace_event_mask) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\Event Enable",
+												 		&pLib->trace_event_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->trace_event_mask))) {
+			return (-1);
+		}
+		pLib->current_trace_event_mask = pLib->trace_event_mask;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if ((pLib->audio_tap_pending >= 0) && (pLib->audio_tap_mask != pLib->current_audio_tap_mask)) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\AudioCh# Enable",
+												 		&pLib->audio_tap_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->audio_tap_mask))) {
+			return (-1);
+		}
+		pLib->current_audio_tap_mask = pLib->audio_tap_mask;
+		pLib->audio_tap_pending = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if ((pLib->eye_pattern_pending >= 0) && (pLib->audio_tap_mask != pLib->current_eye_pattern_mask)) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\EyeCh# Enable",
+												 		&pLib->audio_tap_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->audio_tap_mask))) {
+			return (-1);
+		}
+		pLib->current_eye_pattern_mask = pLib->audio_tap_mask;
+		pLib->eye_pattern_pending = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->bchannel_trace_mask != pLib->current_bchannel_trace_mask) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\B-Ch# Enable",
+												 		&pLib->bchannel_trace_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->bchannel_trace_mask))) {
+			return (-1);
+		}
+		pLib->current_bchannel_trace_mask = pLib->bchannel_trace_mask;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_events_down) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"Events Down",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->trace_events_down = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->l1_trace) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"State\\Layer1",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->l1_trace = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->l2_trace) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"State\\Layer2 No1",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->l2_trace = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	for (i = 0; i < 30; i++) {
+		if (pLib->pending_line_status & (1L << i)) {
+			sprintf (name, "State\\B%d", i+1);
+			if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->pending_line_status &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+		if (pLib->pending_modem_status & (1L << i)) {
+			sprintf (name, "State\\B%d\\Modem", i+1);
+			if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->pending_modem_status &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+		if (pLib->pending_fax_status & (1L << i)) {
+			sprintf (name, "State\\B%d\\FAX", i+1);
+			if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->pending_fax_status &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+		if (pLib->clear_call_command & (1L << i)) {
+			sprintf (name, "State\\B%d\\Clear Call", i+1);
+			if (SuperTraceExecuteRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->clear_call_command &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+	}
+
+	if (pLib->outgoing_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\Outgoing Calls",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->outgoing_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->incoming_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\Incoming Calls",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->incoming_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->modem_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\Modem",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->modem_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->fax_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\FAX",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->fax_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->b1_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\B-Layer1",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->b1_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->b2_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\B-Layer2",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->b2_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->d1_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\D-Layer1",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->d1_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->d2_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\D-Layer2",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->d2_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->IncomingCallsCallsActive) {
+		pLib->IncomingCallsCallsActive = 1;
+		sprintf (name, "%s", "Statistics\\Incoming Calls\\Calls");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->IncomingCallsCallsActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+	if (!pLib->IncomingCallsConnectedActive) {
+		pLib->IncomingCallsConnectedActive = 1;
+		sprintf (name, "%s", "Statistics\\Incoming Calls\\Connected");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->IncomingCallsConnectedActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+	if (!pLib->OutgoingCallsCallsActive) {
+		pLib->OutgoingCallsCallsActive = 1;
+		sprintf (name, "%s", "Statistics\\Outgoing Calls\\Calls");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->OutgoingCallsCallsActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+	if (!pLib->OutgoingCallsConnectedActive) {
+		pLib->OutgoingCallsConnectedActive = 1;
+		sprintf (name, "%s", "Statistics\\Outgoing Calls\\Connected");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->OutgoingCallsConnectedActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	return (0);
+}
+
+static int process_idi_event (diva_strace_context_t* pLib,
+															diva_man_var_header_t* pVar) {
+	const char* path = (char*)&pVar->path_length+1;
+	char name[64];
+	int i;
+
+	if (!strncmp("State\\B Event", path, pVar->path_length)) {
+    dword ch_id;
+    if (!diva_trace_read_variable (pVar, &ch_id)) {
+      if (!pLib->line_init_event && !pLib->pending_line_status) {
+        for (i = 1; i <= pLib->Channels; i++) {
+          diva_line_event(pLib, i);
+        }
+        return (0);
+      } else if (ch_id && ch_id <= pLib->Channels) {
+        return (diva_line_event(pLib, (int)ch_id));
+      }
+      return (0);
+    }
+    return (-1);
+  }
+
+	if (!strncmp("State\\FAX Event", path, pVar->path_length)) {
+    dword ch_id;
+    if (!diva_trace_read_variable (pVar, &ch_id)) {
+      if (!pLib->pending_fax_status && !pLib->fax_init_event) {
+        for (i = 1; i <= pLib->Channels; i++) {
+          diva_fax_event(pLib, i);
+        }
+        return (0);
+      } else if (ch_id && ch_id <= pLib->Channels) {
+        return (diva_fax_event(pLib, (int)ch_id));
+      }
+      return (0);
+    }
+    return (-1);
+  }
+
+	if (!strncmp("State\\Modem Event", path, pVar->path_length)) {
+    dword ch_id;
+    if (!diva_trace_read_variable (pVar, &ch_id)) {
+      if (!pLib->pending_modem_status && !pLib->modem_init_event) {
+        for (i = 1; i <= pLib->Channels; i++) {
+          diva_modem_event(pLib, i);
+        }
+        return (0);
+      } else if (ch_id && ch_id <= pLib->Channels) {
+        return (diva_modem_event(pLib, (int)ch_id));
+      }
+      return (0);
+    }
+    return (-1);
+  }
+
+	/*
+		First look for Line Event
+		*/
+	for (i = 1; i <= pLib->Channels; i++) {
+		sprintf (name, "State\\B%d\\Line", i);
+		if (find_var (pVar, name)) {
+			return (diva_line_event(pLib, i));
+		}
+	}
+
+	/*
+		Look for Moden Progress Event
+		*/
+	for (i = 1; i <= pLib->Channels; i++) {
+		sprintf (name, "State\\B%d\\Modem\\Event", i);
+		if (find_var (pVar, name)) {
+			return (diva_modem_event (pLib, i));
+		}
+	}
+
+	/*
+		Look for Fax Event
+		*/
+	for (i = 1; i <= pLib->Channels; i++) {
+		sprintf (name, "State\\B%d\\FAX\\Event", i);
+		if (find_var (pVar, name)) {
+			return (diva_fax_event (pLib, i));
+		}
+	}
+
+	/*
+		Notification about loss of events
+		*/
+	if (!strncmp("Events Down", path, pVar->path_length)) {
+		if (pLib->trace_events_down == 1) {
+			pLib->trace_events_down = 2;
+		} else {
+			diva_trace_error (pLib, 1, "Events Down", 0);
+		}
+		return (0);
+	}
+
+	if (!strncmp("State\\Layer1", path, pVar->path_length)) {
+		diva_strace_read_asz  (pVar, &pLib->lines[0].pInterface->Layer1[0]);
+		if (pLib->l1_trace == 1) {
+			pLib->l1_trace = 2;
+		} else {
+			diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_INTERFACE_CHANGE);
+		}
+		return (0);
+	}
+	if (!strncmp("State\\Layer2 No1", path, pVar->path_length)) {
+		char* tmp = &pLib->lines[0].pInterface->Layer2[0];
+    dword l2_state;
+    diva_strace_read_uint (pVar, &l2_state);
+
+		switch (l2_state) {
+			case 0:
+				strcpy (tmp, "Idle");
+				break;
+			case 1:
+				strcpy (tmp, "Layer2 UP");
+				break;
+			case 2:
+				strcpy (tmp, "Layer2 Disconnecting");
+				break;
+			case 3:
+				strcpy (tmp, "Layer2 Connecting");
+				break;
+			case 4:
+				strcpy (tmp, "SPID Initializing");
+				break;
+			case 5:
+				strcpy (tmp, "SPID Initialised");
+				break;
+			case 6:
+				strcpy (tmp, "Layer2 Connecting");
+				break;
+
+			case  7:
+				strcpy (tmp, "Auto SPID Stopped");
+				break;
+
+			case  8:
+				strcpy (tmp, "Auto SPID Idle");
+				break;
+
+			case  9:
+				strcpy (tmp, "Auto SPID Requested");
+				break;
+
+			case  10:
+				strcpy (tmp, "Auto SPID Delivery");
+				break;
+
+			case 11:
+				strcpy (tmp, "Auto SPID Complete");
+				break;
+
+			default:
+				sprintf (tmp, "U:%d", (int)l2_state);
+		}
+		if (pLib->l2_trace == 1) {
+			pLib->l2_trace = 2;
+		} else {
+			diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_INTERFACE_CHANGE);
+		}
+		return (0);
+	}
+
+	if (!strncmp("Statistics\\Incoming Calls\\Calls", path, pVar->path_length) ||
+			!strncmp("Statistics\\Incoming Calls\\Connected", path, pVar->path_length)) {
+		return (SuperTraceGetIncomingCallStatistics (pLib));
+	}
+
+	if (!strncmp("Statistics\\Outgoing Calls\\Calls", path, pVar->path_length) ||
+			!strncmp("Statistics\\Outgoing Calls\\Connected", path, pVar->path_length)) {
+		return (SuperTraceGetOutgoingCallStatistics (pLib));
+	}
+
+	return (-1);
+}
+
+static int diva_line_event (diva_strace_context_t* pLib, int Channel) {
+	pLib->pending_line_status |= (1L << (Channel-1));
+	return (0);
+}
+
+static int diva_modem_event (diva_strace_context_t* pLib, int Channel) {
+	pLib->pending_modem_status |= (1L << (Channel-1));
+	return (0);
+}
+
+static int diva_fax_event (diva_strace_context_t* pLib, int Channel) {
+	pLib->pending_fax_status |= (1L << (Channel-1));
+	return (0);
+}
+
+/*
+	Process INFO indications that arrive from the card
+	Uses path of first I.E. to detect the source of the
+	infication
+	*/
+static int process_idi_info  (diva_strace_context_t* pLib,
+															diva_man_var_header_t* pVar) {
+	const char* path = (char*)&pVar->path_length+1;
+	char name[64];
+	int i, len;
+
+	/*
+		First look for Modem Status Info
+		*/
+	for (i = pLib->Channels; i > 0; i--) {
+		len = sprintf (name, "State\\B%d\\Modem", i);
+		if (!strncmp(name, path, len)) {
+			return (diva_modem_info (pLib, i, pVar));
+		}
+	}
+
+	/*
+		Look for Fax Status Info
+		*/
+	for (i = pLib->Channels; i > 0; i--) {
+		len = sprintf (name, "State\\B%d\\FAX", i);
+		if (!strncmp(name, path, len)) {
+			return (diva_fax_info (pLib, i, pVar));
+		}
+	}
+
+	/*
+		Look for Line Status Info
+		*/
+	for (i = pLib->Channels; i > 0; i--) {
+		len = sprintf (name, "State\\B%d", i);
+		if (!strncmp(name, path, len)) {
+			return (diva_line_info (pLib, i, pVar));
+		}
+	}
+
+	if (!diva_ifc_statistics (pLib, pVar)) {
+		return (0);
+	}
+
+	return (-1);
+}
+
+/*
+	MODEM INSTANCE STATE UPDATE
+
+	Update Modem Status Information and issue notification to user,
+	that will inform about change in the state of modem instance, that is
+	associuated with this channel
+	*/
+static int diva_modem_info (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, nr = Channel - 1;
+
+	for (i  = pLib->modem_parse_entry_first[nr];
+			 i <= pLib->modem_parse_entry_last[nr]; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+		} else {
+			diva_trace_error (pLib, -2 , __FILE__, __LINE__);
+			return (-1);
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+		*/
+	if (pLib->modem_init_event & (1L << nr)) {
+		diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE);
+	} else {
+		pLib->modem_init_event |= (1L << nr);
+	}
+
+	return (0);
+}
+
+static int diva_fax_info (diva_strace_context_t* pLib,
+													int Channel,
+													diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, nr = Channel - 1;
+
+	for (i  = pLib->fax_parse_entry_first[nr];
+			 i <= pLib->fax_parse_entry_last[nr]; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+		} else {
+			diva_trace_error (pLib, -2 , __FILE__, __LINE__);
+			return (-1);
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+		*/
+	if (pLib->fax_init_event & (1L << nr)) {
+		diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE);
+	} else {
+		pLib->fax_init_event |= (1L << nr);
+	}
+
+	return (0);
+}
+
+/*
+	LINE STATE UPDATE
+	Update Line Status Information and issue notification to user,
+	that will inform about change in the line state.
+	*/
+static int diva_line_info  (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, nr = Channel - 1;
+
+	for (i  = pLib->line_parse_entry_first[nr];
+			 i <= pLib->line_parse_entry_last[nr]; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+		} else {
+			diva_trace_error (pLib, -2 , __FILE__, __LINE__);
+			return (-1);
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+
+		Exception is is if the line is "online". In this case we have to notify
+		user about this confition.
+		*/
+	if (pLib->line_init_event & (1L << nr)) {
+		diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE);
+	} else {
+		pLib->line_init_event |= (1L << nr);
+		if (strcmp (&pLib->lines[nr].Line[0], "Idle")) {
+			diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE);
+		}
+	}
+
+	return (0);
+}
+
+/*
+	Move position to next vatianle in the chain
+	*/
+static diva_man_var_header_t* get_next_var (diva_man_var_header_t* pVar) {
+	byte* msg   = (byte*)pVar;
+	byte* start;
+	int msg_length;
+
+	if (*msg != ESC) return (0);
+
+	start = msg + 2;
+	msg_length = *(msg+1);
+	msg = (start+msg_length);
+
+	if (*msg != ESC) return (0);
+
+	return ((diva_man_var_header_t*)msg);
+}
+
+/*
+	Move position to variable with given name
+	*/
+static diva_man_var_header_t* find_var (diva_man_var_header_t* pVar,
+																				const char* name) {
+	const char* path;
+
+	do {
+		path = (char*)&pVar->path_length+1;
+
+		if (!strncmp (name, path, pVar->path_length)) {
+			break;
+		}
+	} while ((pVar = get_next_var (pVar)));
+
+	return (pVar);
+}
+
+static void diva_create_line_parse_table  (diva_strace_context_t* pLib,
+																					 int Channel) {
+	diva_trace_line_state_t* pLine = &pLib->lines[Channel];
+	int nr = Channel+1;
+
+	if ((pLib->cur_parse_entry + LINE_PARSE_ENTRIES) >= pLib->parse_entries) {
+		diva_trace_error (pLib, -1, __FILE__, __LINE__);
+		return;
+	}
+
+	pLine->ChannelNumber = nr;
+
+	pLib->line_parse_entry_first[Channel] = pLib->cur_parse_entry;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Framing", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Framing[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Line", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Line[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Layer2", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Layer2[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Layer3", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Layer3[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Remote Address", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->RemoteAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Remote SubAddr", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->RemoteSubAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Local Address", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->LocalAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Local SubAddr", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->LocalSubAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\BC", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_BC;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\HLC", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_HLC;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\LLC", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_LLC;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Charges", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Charges;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Call Reference", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->CallReference;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Last Disc Cause", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																										&pLine->LastDisconnecCause;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\User ID", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->UserID[0];
+
+	pLib->line_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
+}
+
+static void diva_create_fax_parse_table (diva_strace_context_t* pLib,
+																				 int Channel) {
+	diva_trace_fax_state_t* pFax = &pLib->lines[Channel].fax;
+	int nr = Channel+1;
+
+	if ((pLib->cur_parse_entry + FAX_PARSE_ENTRIES) >= pLib->parse_entries) {
+		diva_trace_error (pLib, -1, __FILE__, __LINE__);
+		return;
+	}
+	pFax->ChannelNumber = nr;
+
+	pLib->fax_parse_entry_first[Channel] = pLib->cur_parse_entry;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Event", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Event;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Page Counter", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Page_Counter;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Features", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Features;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Station ID", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Station_ID[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Subaddress", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Subaddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Password", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Password[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Speed", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Speed;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Resolution", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Resolution;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Paper Width", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Paper_Width;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Paper Length", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Paper_Length;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Scanline Time", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Scanline_Time;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Disc Reason", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Disc_Reason;
+
+	pLib->fax_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
+}
+
+static void diva_create_modem_parse_table (diva_strace_context_t* pLib,
+																					 int Channel) {
+	diva_trace_modem_state_t* pModem = &pLib->lines[Channel].modem;
+	int nr = Channel+1;
+
+	if ((pLib->cur_parse_entry + MODEM_PARSE_ENTRIES) >= pLib->parse_entries) {
+		diva_trace_error (pLib, -1, __FILE__, __LINE__);
+		return;
+	}
+	pModem->ChannelNumber = nr;
+
+	pLib->modem_parse_entry_first[Channel] = pLib->cur_parse_entry;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Event", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Event;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Norm", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Norm;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Options", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Options;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\TX Speed", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->TxSpeed;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\RX Speed", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RxSpeed;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Roundtrip ms", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RoundtripMsec;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Symbol Rate", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->SymbolRate;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\RX Level dBm", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RxLeveldBm;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Echo Level dBm", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->EchoLeveldBm;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\SNR dB", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->SNRdb;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\MAE", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->MAE;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Local Retrains", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->LocalRetrains;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Remote Retrains", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RemoteRetrains;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Local Resyncs", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->LocalResyncs;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Remote Resyncs", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RemoteResyncs;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Disc Reason", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->DiscReason;
+
+	pLib->modem_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
+}
+
+static void diva_create_parse_table (diva_strace_context_t* pLib) {
+	int i;
+
+	for (i = 0; i < pLib->Channels; i++) {
+		diva_create_line_parse_table  (pLib, i);
+		diva_create_modem_parse_table (pLib, i);
+		diva_create_fax_parse_table   (pLib, i);
+	}
+
+	pLib->statistic_parse_first = pLib->cur_parse_entry;
+
+	/*
+		Outgoing Calls
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Calls");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Calls;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Connected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Connected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\User Busy");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.User_Busy;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\No Answer");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.No_Answer;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Wrong Number");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Wrong_Number;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Call Rejected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Call_Rejected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Other Failures");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Other_Failures;
+
+	/*
+		Incoming Calls
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Calls");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Calls;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Connected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Connected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\User Busy");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.User_Busy;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Call Rejected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Call_Rejected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Wrong Number");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Wrong_Number;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Incompatible Dst");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Incompatible_Dst;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Out of Order");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Out_of_Order;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Ignored");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Ignored;
+
+	/*
+		Modem Statistics
+		*/
+	pLib->mdm_statistic_parse_first = pLib->cur_parse_entry;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Normal");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Normal;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Unspecified");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Unspecified;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Busy Tone");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Busy_Tone;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Congestion");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Congestion;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Carr. Wait");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Carr_Wait;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Trn Timeout");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Trn_Timeout;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Incompat.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Incompat;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Frame Rej.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Frame_Rej;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc V42bis");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_V42bis;
+
+	pLib->mdm_statistic_parse_last  = pLib->cur_parse_entry - 1;
+
+	/*
+		Fax Statistics
+		*/
+	pLib->fax_statistic_parse_first = pLib->cur_parse_entry;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Normal");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Normal;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Not Ident.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Not_Ident;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc No Response");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_No_Response;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Retries");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Retries;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Unexp. Msg.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Unexp_Msg;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc No Polling.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_No_Polling;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Training");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Training;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Unexpected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Unexpected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Application");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Application;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Incompat.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Incompat;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc No Command");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_No_Command;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Long Msg");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Long_Msg;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Supervisor");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Supervisor;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc SUB SEP PWD");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_SUB_SEP_PWD;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Invalid Msg");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Invalid_Msg;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Page Coding");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Page_Coding;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc App Timeout");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_App_Timeout;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Unspecified");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Unspecified;
+
+	pLib->fax_statistic_parse_last  = pLib->cur_parse_entry - 1;
+
+	/*
+		B-Layer1"
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.R_Errors;
+
+	/*
+		B-Layer2
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.R_Errors;
+
+	/*
+		D-Layer1
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.R_Errors;
+
+	/*
+		D-Layer2
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.R_Errors;
+
+
+	pLib->statistic_parse_last  = pLib->cur_parse_entry - 1;
+}
+
+static void diva_trace_error (diva_strace_context_t* pLib,
+															int error, const char* file, int line) {
+	if (pLib->user_proc_table.error_notify_proc) {
+		(*(pLib->user_proc_table.error_notify_proc))(\
+																						pLib->user_proc_table.user_context,
+																						&pLib->instance, pLib->Adapter,
+																						error, file, line);
+	}
+}
+
+/*
+	Delivery notification to user
+	*/
+static void diva_trace_notify_user (diva_strace_context_t* pLib,
+														 int Channel,
+														 int notify_subject) {
+	if (pLib->user_proc_table.notify_proc) {
+		(*(pLib->user_proc_table.notify_proc))(pLib->user_proc_table.user_context,
+																					 &pLib->instance,
+																					 pLib->Adapter,
+																					 &pLib->lines[Channel],
+																					 notify_subject);
+	}
+}
+
+/*
+	Read variable value to they destination based on the variable type
+	*/
+static int diva_trace_read_variable (diva_man_var_header_t* pVar,
+																		 void* variable) {
+	switch (pVar->type) {
+		case 0x03: /* MI_ASCIIZ - syting                               */
+			return (diva_strace_read_asz  (pVar, (char*)variable));
+		case 0x04: /* MI_ASCII  - string                               */
+			return (diva_strace_read_asc  (pVar, (char*)variable));
+		case 0x05: /* MI_NUMBER - counted sequence of bytes            */
+			return (diva_strace_read_ie  (pVar, (diva_trace_ie_t*)variable));
+		case 0x81: /* MI_INT    - signed integer                       */
+			return (diva_strace_read_int (pVar, (int*)variable));
+		case 0x82: /* MI_UINT   - unsigned integer                     */
+			return (diva_strace_read_uint (pVar, (dword*)variable));
+		case 0x83: /* MI_HINT   - unsigned integer, hex representetion */
+			return (diva_strace_read_uint (pVar, (dword*)variable));
+		case 0x87: /* MI_BITFLD - unsigned integer, bit representation */
+			return (diva_strace_read_uint (pVar, (dword*)variable));
+	}
+
+	/*
+		This type of variable is not handled, indicate error
+		Or one problem in management interface, or in application recodeing
+		table, or this application should handle it.
+		*/
+	return (-1);
+}
+
+/*
+	Read signed integer to destination
+	*/
+static int diva_strace_read_int  (diva_man_var_header_t* pVar, int* var) {
+	byte* ptr = (char*)&pVar->path_length;
+	int value;
+
+	ptr += (pVar->path_length + 1);
+
+	switch (pVar->value_length) {
+		case 1:
+			value = *(char*)ptr;
+			break;
+
+		case 2:
+			value = (short)READ_WORD(ptr);
+			break;
+
+		case 4:
+			value = (int)READ_DWORD(ptr);
+			break;
+
+		default:
+			return (-1);
+	}
+
+	*var = value;
+
+	return (0);
+}
+
+static int diva_strace_read_uint (diva_man_var_header_t* pVar, dword* var) {
+	byte* ptr = (char*)&pVar->path_length;
+	dword value;
+
+	ptr += (pVar->path_length + 1);
+
+	switch (pVar->value_length) {
+		case 1:
+			value = (byte)(*ptr);
+			break;
+
+		case 2:
+			value = (word)READ_WORD(ptr);
+			break;
+
+		case 3:
+			value  = (dword)READ_DWORD(ptr);
+			value &= 0x00ffffff;
+			break;
+
+		case 4:
+			value = (dword)READ_DWORD(ptr);
+			break;
+
+		default:
+			return (-1);
+	}
+
+	*var = value;
+
+	return (0);
+}
+
+/*
+	Read zero terminated ASCII string
+	*/
+static int diva_strace_read_asz  (diva_man_var_header_t* pVar, char* var) {
+	char* ptr = (char*)&pVar->path_length;
+	int length;
+
+	ptr += (pVar->path_length + 1);
+
+	if (!(length = pVar->value_length)) {
+		length = strlen (ptr);
+	}
+	memcpy (var, ptr, length);
+	var[length] = 0;
+
+	return (0);
+}
+
+/*
+	Read counted (with leading length byte) ASCII string
+	*/
+static int diva_strace_read_asc  (diva_man_var_header_t* pVar, char* var) {
+	char* ptr = (char*)&pVar->path_length;
+
+	ptr += (pVar->path_length + 1);
+	memcpy (var, ptr+1, *ptr);
+	var[(int)*ptr] = 0;
+
+	return (0);
+}
+
+/*
+		Read one information element - i.e. one string of byte values with
+		one length byte in front
+	*/
+static int  diva_strace_read_ie  (diva_man_var_header_t* pVar,
+																	diva_trace_ie_t* var) {
+	char* ptr = (char*)&pVar->path_length;
+
+	ptr += (pVar->path_length + 1);
+
+	var->length = *ptr;
+	memcpy (&var->data[0], ptr+1, *ptr);
+
+	return (0);
+}
+
+static int SuperTraceSetAudioTap  (void* hLib, int Channel, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if ((Channel < 1) || (Channel > pLib->Channels)) {
+		return (-1);
+	}
+	Channel--;
+
+	if (on) {
+		pLib->audio_tap_mask |=  (1L << Channel);
+	} else {
+		pLib->audio_tap_mask &= ~(1L << Channel);
+	}
+
+  /*
+    EYE patterns have TM_M_DATA set as additional
+    condition
+    */
+  if (pLib->audio_tap_mask) {
+    pLib->trace_event_mask |= TM_M_DATA;
+  } else {
+    pLib->trace_event_mask &= ~TM_M_DATA;
+  }
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceSetBChannel  (void* hLib, int Channel, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if ((Channel < 1) || (Channel > pLib->Channels)) {
+		return (-1);
+	}
+	Channel--;
+
+	if (on) {
+		pLib->bchannel_trace_mask |=  (1L << Channel);
+	} else {
+		pLib->bchannel_trace_mask &= ~(1L << Channel);
+	}
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceSetDChannel  (void* hLib, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if (on) {
+		pLib->trace_event_mask |= (TM_D_CHAN | TM_C_COMM | TM_DL_ERR | TM_LAYER1);
+	} else {
+		pLib->trace_event_mask &= ~(TM_D_CHAN | TM_C_COMM | TM_DL_ERR | TM_LAYER1);
+	}
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceSetInfo (void* hLib, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if (on) {
+		pLib->trace_event_mask |= TM_STRING;
+	} else {
+		pLib->trace_event_mask &= ~TM_STRING;
+	}
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceClearCall (void* hLib, int Channel) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if ((Channel < 1) || (Channel > pLib->Channels)) {
+		return (-1);
+	}
+	Channel--;
+
+	pLib->clear_call_command |= (1L << Channel);
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+/*
+	Parse and update cumulative statistice
+	*/
+static int diva_ifc_statistics (diva_strace_context_t* pLib,
+																diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, one_updated = 0, mdm_updated = 0, fax_updated = 0;
+
+	for (i  = pLib->statistic_parse_first; i <= pLib->statistic_parse_last; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+			one_updated = 1;
+      if ((i >= pLib->mdm_statistic_parse_first) && (i <= pLib->mdm_statistic_parse_last)) {
+        mdm_updated = 1;
+      }
+      if ((i >= pLib->fax_statistic_parse_first) && (i <= pLib->fax_statistic_parse_last)) {
+        fax_updated = 1;
+      }
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+		*/
+  if (mdm_updated) {
+		diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE);
+  } else if (fax_updated) {
+		diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE);
+  } else if (one_updated) {
+		diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE);
+	}
+
+	return (one_updated ? 0 : -1);
+}
+
+static int SuperTraceGetOutgoingCallStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->outgoing_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetIncomingCallStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->incoming_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetModemStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->modem_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetFaxStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->fax_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetBLayer1Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->b1_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetBLayer2Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->b2_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetDLayer1Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->d1_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetDLayer2Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->d2_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+dword DivaSTraceGetMemotyRequirement (int channels) {
+  dword parse_entries = (MODEM_PARSE_ENTRIES + FAX_PARSE_ENTRIES + \
+												 STAT_PARSE_ENTRIES + \
+												 LINE_PARSE_ENTRIES + 1) * channels;
+  return (sizeof(diva_strace_context_t) + \
+          (parse_entries * sizeof(diva_strace_path2action_t)));
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/maintidi.h b/drivers/isdn/hardware/eicon/maintidi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/maintidi.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,170 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2000.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_EICON_TRACE_IDI_IFC_H__
+#define __DIVA_EICON_TRACE_IDI_IFC_H__
+
+void* SuperTraceOpenAdapter   (int AdapterNumber);
+int   SuperTraceCloseAdapter  (void* AdapterHandle);
+int   SuperTraceWrite         (void* AdapterHandle,
+                               const void* data, int length);
+int   SuperTraceReadRequest   (void* AdapterHandle,const char* name,byte* data);
+int   SuperTraceGetNumberOfChannels (void* AdapterHandle);
+int   SuperTraceASSIGN        (void* AdapterHandle, byte* data);
+int   SuperTraceREMOVE        (void* AdapterHandle);
+int   SuperTraceTraceOnRequest(void* hAdapter, const char* name, byte* data);
+int   SuperTraceWriteVar (void* AdapterHandle,
+												byte* data,
+										 		const char* name,
+										 		void* var,
+										 		byte type,
+										 		byte var_length);
+int   SuperTraceExecuteRequest (void* AdapterHandle,
+																const char* name,
+																byte* data);
+
+typedef struct _diva_strace_path2action {
+	char               path[64]; /* Full path to variable            */
+	void*							 variable; /* Variable that will receive value */
+} diva_strace_path2action_t;
+
+typedef struct _diva_strace_context {
+	diva_strace_library_interface_t	instance;
+
+	int   Adapter;
+	void* hAdapter;
+
+	int Channels;
+	int	req_busy;
+
+  ENTITY   e;
+  IDI_CALL request;
+  BUFFERS  XData;
+  BUFFERS  RData;
+	byte buffer[2048+512+1];
+  int removal_state;
+  int general_b_ch_event;
+  int general_fax_event;
+  int general_mdm_event;
+
+	byte	rc_ok;
+
+	/*
+		Initialization request state machine
+		*/
+	int ChannelsTraceActive;
+	int ModemTraceActive;
+	int FaxTraceActive;
+	int IncomingCallsCallsActive;
+	int IncomingCallsConnectedActive;
+	int OutgoingCallsCallsActive;
+	int OutgoingCallsConnectedActive;
+
+	int trace_mask_init;
+	int audio_trace_init;
+	int bchannel_init;
+	int trace_length_init;
+	int	trace_on;
+	int trace_events_down;
+	int l1_trace;
+	int l2_trace;
+
+	/*
+		Trace\Event Enable
+		*/
+	word trace_event_mask;
+	word current_trace_event_mask;
+
+	dword audio_tap_mask;
+	dword current_audio_tap_mask;
+	dword current_eye_pattern_mask;
+	int   audio_tap_pending;
+	int   eye_pattern_pending;
+
+	dword bchannel_trace_mask;
+	dword current_bchannel_trace_mask;
+
+
+	diva_trace_line_state_t lines[30];
+
+	int	parse_entries;
+	int	cur_parse_entry;
+	diva_strace_path2action_t* parse_table;
+
+	diva_trace_library_user_interface_t user_proc_table;
+
+	int line_parse_entry_first[30];
+	int line_parse_entry_last[30];
+
+	int modem_parse_entry_first[30];
+	int modem_parse_entry_last[30];
+
+	int fax_parse_entry_first[30];
+	int fax_parse_entry_last[30];
+
+	int statistic_parse_first;
+	int statistic_parse_last;
+
+	int mdm_statistic_parse_first;
+	int mdm_statistic_parse_last;
+
+	int fax_statistic_parse_first;
+	int fax_statistic_parse_last;
+
+	dword	line_init_event;
+	dword	modem_init_event;
+	dword	fax_init_event;
+
+	dword	pending_line_status;
+	dword	pending_modem_status;
+	dword	pending_fax_status;
+
+	dword clear_call_command;
+
+	int outgoing_ifc_stats;
+	int incoming_ifc_stats;
+	int modem_ifc_stats;
+	int fax_ifc_stats;
+	int b1_ifc_stats;
+	int b2_ifc_stats;
+	int d1_ifc_stats;
+	int d2_ifc_stats;
+
+	diva_trace_interface_state_t Interface;
+	diva_ifc_statistics_t				 InterfaceStat;
+} diva_strace_context_t;
+
+typedef struct _diva_man_var_header {
+	byte   escape;
+	byte   length;
+	byte   management_id;
+	byte   type;
+	byte   attribute;
+	byte   status;
+	byte   value_length;
+	byte	 path_length;
+} diva_man_var_header_t;
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/man_defs.h b/drivers/isdn/hardware/eicon/man_defs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/man_defs.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,133 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+/* Definitions for use with the Management Information Element      */
+
+/*------------------------------------------------------------------*/
+/* Management information element                                   */
+/* ----------------------------------------------------------       */
+/* Byte     Coding            Comment                               */
+/* ----------------------------------------------------------       */
+/*    0 | 0 1 1 1 1 1 1 1 | ESC                                     */
+/*    1 | 0 x x x x x x x | Length of information element (m-1)     */
+/*    2 | 1 0 0 0 0 0 0 0 | Management Information Id               */
+/*    3 | x x x x x x x x | Type                                    */
+/*    4 | x x x x x x x x | Attribute                               */
+/*    5 | x x x x x x x x | Status                                  */
+/*    6 | x x x x x x x x | Variable Value Length (m-n)             */
+/*    7 | x x x x x x x x | Path / Variable Name String Length (n-8)*/
+/* 8..n | x x x x x x x x | Path/Node Name String separated by '\'  */
+/* n..m | x x x x x x x x | Variable content                        */
+/*------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------*/
+/* Type Field                                                       */
+/*                                                                  */
+/* MAN_READ:      not used                                          */
+/* MAN_WRITE:     not used                                          */
+/* MAN_EVENT_ON:  not used                                          */
+/* MAN_EVENT_OFF: not used                                          */
+/* MAN_INFO_IND:  type of variable                                  */
+/* MAN_EVENT_IND: type of variable                                  */
+/* MAN_TRACE_IND  not used                                          */
+/*------------------------------------------------------------------*/
+#define MI_DIR          0x01  /* Directory string (zero terminated) */
+#define MI_EXECUTE      0x02  /* Executable function (has no value) */
+#define MI_ASCIIZ       0x03  /* Zero terminated string             */
+#define MI_ASCII        0x04  /* String, first byte is length       */
+#define MI_NUMBER       0x05  /* Number string, first byte is length*/
+#define MI_TRACE        0x06  /* Trace information, format see below*/
+
+#define MI_FIXED_LENGTH 0x80  /* get length from MAN_INFO max_len   */
+#define MI_INT          0x81  /* number to display as signed int    */
+#define MI_UINT         0x82  /* number to display as unsigned int  */
+#define MI_HINT         0x83  /* number to display in hex format    */
+#define MI_HSTR         0x84  /* number to display as a hex string  */
+#define MI_BOOLEAN      0x85  /* number to display as boolean       */
+#define MI_IP_ADDRESS   0x86  /* number to display as IP address    */
+#define MI_BITFLD       0x87  /* number to display as bit field     */
+#define MI_SPID_STATE   0x88  /* state# of SPID initialisation      */
+
+/*------------------------------------------------------------------*/
+/* Attribute Field                                                  */
+/*                                                                  */
+/* MAN_READ:      not used                                          */
+/* MAN_WRITE:     not used                                          */
+/* MAN_EVENT_ON:  not used                                          */
+/* MAN_EVENT_OFF: not used                                          */
+/* MAN_INFO_IND:  set according to capabilities of that variable    */
+/* MAN_EVENT_IND: not used                                          */
+/* MAN_TRACE_IND  not used                                          */
+/*------------------------------------------------------------------*/
+#define MI_WRITE        0x01  /* Variable is writeable              */
+#define MI_EVENT        0x02  /* Variable can indicate changes      */
+
+/*------------------------------------------------------------------*/
+/* Status Field                                                     */
+/*                                                                  */
+/* MAN_READ:      not used                                          */
+/* MAN_WRITE:     not used                                          */
+/* MAN_EVENT_ON:  not used                                          */
+/* MAN_EVENT_OFF: not used                                          */
+/* MAN_INFO_IND:  set according to the actual status                */
+/* MAN_EVENT_IND: set according to the actual statu                 */
+/* MAN_TRACE_IND  not used                                          */
+/*------------------------------------------------------------------*/
+#define MI_LOCKED       0x01  /* write protected by another instance*/
+#define MI_EVENT_ON     0x02  /* Event logging switched on          */
+#define MI_PROTECTED    0x04  /* write protected by this instance   */
+
+/*------------------------------------------------------------------*/
+/* Data Format used for MAN_TRACE_IND (no MI-element used)          */
+/*------------------------------------------------------------------*/
+typedef struct mi_xlog_hdr_s MI_XLOG_HDR;
+struct mi_xlog_hdr_s
+{
+  unsigned long  time;   /* Timestamp in msec units                 */
+  unsigned short size;   /* Size of data that follows               */
+  unsigned short code;   /* code of trace event                     */
+};                       /* unspecified data follows this header    */
+
+/*------------------------------------------------------------------*/
+/* Trace mask definitions for trace events except B channel and     */
+/* debug trace events                                               */
+/*------------------------------------------------------------------*/
+#define TM_D_CHAN   0x0001  /* D-Channel        (D-.) Code 3,4      */
+#define TM_L_LAYER  0x0002  /* Low Layer        (LL)  Code 6,7      */
+#define TM_N_LAYER  0x0004  /* Network Layer    (N)   Code 14,15    */
+#define TM_DL_ERR   0x0008  /* Data Link Error  (MDL) Code 9        */
+#define TM_LAYER1   0x0010  /* Layer 1                Code 20       */
+#define TM_C_COMM   0x0020  /* Call Comment     (SIG) Code 5,21,22  */
+#define TM_M_DATA   0x0040  /* Modulation Data  (EYE) Code 23       */
+#define TM_STRING   0x0080  /* Sting data             Code 24       */
+#define TM_N_USED2  0x0100  /* not used                             */
+#define TM_N_USED3  0x0200  /* not used                             */
+#define TM_N_USED4  0x0400  /* not used                             */
+#define TM_N_USED5  0x0800  /* not used                             */
+#define TM_N_USED6  0x1000  /* not used                             */
+#define TM_N_USED7  0x2000  /* not used                             */
+#define TM_N_USED8  0x4000  /* not used                             */
+#define TM_REST     0x8000  /* Codes 10,11,12,13,16,18,19,128,129   */
+
+/*------ End of file -----------------------------------------------*/
diff -Nru a/drivers/isdn/hardware/eicon/mdm_msg.h b/drivers/isdn/hardware/eicon/mdm_msg.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/mdm_msg.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,346 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __EICON_MDM_MSG_H__
+#define __EICON_MDM_MSG_H__
+#define DSP_UDATA_INDICATION_DCD_OFF  0x01
+#define DSP_UDATA_INDICATION_DCD_ON  0x02
+#define DSP_UDATA_INDICATION_CTS_OFF  0x03
+#define DSP_UDATA_INDICATION_CTS_ON  0x04
+/* =====================================================================
+DCD_OFF Message:
+  <word> time of DCD off (sampled from counter at 8kHz)
+DCD_ON Message:
+  <word> time of DCD on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s, max of tx and rx speed)
+  <word> roundtrip delay (ms)
+  <dword> connected speed tx (bit/s)
+  <dword> connected speed rx (bit/s)
+  Size of this message == 19 bytes, but we will receive only 11
+  ===================================================================== */
+#define DSP_CONNECTED_NORM_UNSPECIFIED      0
+#define DSP_CONNECTED_NORM_V21              1
+#define DSP_CONNECTED_NORM_V23              2
+#define DSP_CONNECTED_NORM_V22              3
+#define DSP_CONNECTED_NORM_V22_BIS          4
+#define DSP_CONNECTED_NORM_V32_BIS          5
+#define DSP_CONNECTED_NORM_V34              6
+#define DSP_CONNECTED_NORM_V8               7
+#define DSP_CONNECTED_NORM_BELL_212A        8
+#define DSP_CONNECTED_NORM_BELL_103         9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
+#define DSP_CONNECTED_NORM_V90              12
+#define DSP_CONNECTED_NORM_V21_CH2          13
+#define DSP_CONNECTED_NORM_V27_TER          14
+#define DSP_CONNECTED_NORM_V29              15
+#define DSP_CONNECTED_NORM_V33              16
+#define DSP_CONNECTED_NORM_V17              17
+#define DSP_CONNECTED_NORM_V32              18
+#define DSP_CONNECTED_NORM_K56_FLEX         19
+#define DSP_CONNECTED_NORM_X2               20
+#define DSP_CONNECTED_NORM_V18              21
+#define DSP_CONNECTED_NORM_V18_LOW_HIGH     22
+#define DSP_CONNECTED_NORM_V18_HIGH_LOW     23
+#define DSP_CONNECTED_NORM_V21_LOW_HIGH     24
+#define DSP_CONNECTED_NORM_V21_HIGH_LOW     25
+#define DSP_CONNECTED_NORM_BELL103_LOW_HIGH 26
+#define DSP_CONNECTED_NORM_BELL103_HIGH_LOW 27
+#define DSP_CONNECTED_NORM_V23_75_1200      28
+#define DSP_CONNECTED_NORM_V23_1200_75      29
+#define DSP_CONNECTED_NORM_EDT_110          30
+#define DSP_CONNECTED_NORM_BAUDOT_45        31
+#define DSP_CONNECTED_NORM_BAUDOT_47        32
+#define DSP_CONNECTED_NORM_BAUDOT_50        33
+#define DSP_CONNECTED_NORM_DTMF             34
+#define DSP_CONNECTED_NORM_V18_RESERVED_13  35
+#define DSP_CONNECTED_NORM_V18_RESERVED_14  36
+#define DSP_CONNECTED_NORM_V18_RESERVED_15  37
+#define DSP_CONNECTED_NORM_VOWN             38
+#define DSP_CONNECTED_NORM_V23_OFF_HOOK     39
+#define DSP_CONNECTED_NORM_V23_ON_HOOK      40
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_3  41
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_4  42
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_5  43
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_6  44
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_7  45
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_8  46
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_9  47
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_10 48
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_11 49
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_12 50
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_13 51
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_14 52
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_15 53
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_16 54
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_17 55
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_18 56
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_19 57
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_20 58
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_21 59
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_22 60
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_23 61
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_24 62
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_25 63
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_26 64
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_27 65
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_28 66
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_29 67
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_30 68
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_31 69
+#define DSP_CONNECTED_OPTION_TRELLIS             0x0001
+#define DSP_CONNECTED_OPTION_V42_TRANS           0x0002
+#define DSP_CONNECTED_OPTION_V42_LAPM            0x0004
+#define DSP_CONNECTED_OPTION_SHORT_TRAIN         0x0008
+#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
+#define DSP_CONNECTED_OPTION_V42BIS              0x0020
+#define DSP_CONNECTED_OPTION_MNP2                0x0040
+#define DSP_CONNECTED_OPTION_MNP3                0x0080
+#define DSP_CONNECTED_OPTION_MNP4                0x00c0
+#define DSP_CONNECTED_OPTION_MNP5                0x0100
+#define DSP_CONNECTED_OPTION_MNP10               0x0200
+#define DSP_CONNECTED_OPTION_MASK_V42            0x0024
+#define DSP_CONNECTED_OPTION_MASK_MNP            0x03c0
+#define DSP_CONNECTED_OPTION_MASK_ERROR_CORRECT  0x03e4
+#define DSP_CONNECTED_OPTION_MASK_COMPRESSION    0x0320
+#define DSP_UDATA_INDICATION_DISCONNECT         5
+/*
+returns:
+  <byte> cause
+*/
+/* ==========================================================
+    DLC: B2 modem configuration
+   ========================================================== */
+/*
+Fields in assign DLC information element for modem protocol V.42/MNP:
+  <byte> length of information element
+  <word> information field length
+  <byte> address A       (not used, default 3)
+  <byte> address B       (not used, default 1)
+  <byte> modulo mode     (not used, default 7)
+  <byte> window size     (not used, default 7)
+  <word> XID length      (not used, default 0)
+  ...    XID information (not used, default empty)
+  <byte> modem protocol negotiation options
+  <byte> modem protocol options
+  <byte> modem protocol break configuration
+  <byte> modem protocol application options
+*/
+#define DLC_MODEMPROT_DISABLE_V42_V42BIS     0x01
+#define DLC_MODEMPROT_DISABLE_MNP_MNP5       0x02
+#define DLC_MODEMPROT_REQUIRE_PROTOCOL       0x04
+#define DLC_MODEMPROT_DISABLE_V42_DETECT     0x08
+#define DLC_MODEMPROT_DISABLE_COMPRESSION    0x10
+#define DLC_MODEMPROT_REQUIRE_PROTOCOL_V34UP 0x20
+#define DLC_MODEMPROT_NO_PROTOCOL_IF_1200    0x01
+#define DLC_MODEMPROT_BUFFER_IN_V42_DETECT   0x02
+#define DLC_MODEMPROT_DISABLE_V42_SREJ       0x04
+#define DLC_MODEMPROT_DISABLE_MNP3           0x08
+#define DLC_MODEMPROT_DISABLE_MNP4           0x10
+#define DLC_MODEMPROT_DISABLE_MNP10          0x20
+#define DLC_MODEMPROT_NO_PROTOCOL_IF_V22BIS  0x40
+#define DLC_MODEMPROT_NO_PROTOCOL_IF_V32BIS  0x80
+#define DLC_MODEMPROT_BREAK_DISABLED         0x00
+#define DLC_MODEMPROT_BREAK_NORMAL           0x01
+#define DLC_MODEMPROT_BREAK_EXPEDITED        0x02
+#define DLC_MODEMPROT_BREAK_DESTRUCTIVE      0x03
+#define DLC_MODEMPROT_BREAK_CONFIG_MASK      0x03
+#define DLC_MODEMPROT_APPL_EARLY_CONNECT     0x01
+#define DLC_MODEMPROT_APPL_PASS_INDICATIONS  0x02
+/* ==========================================================
+    CAI parameters used for the modem L1 configuration
+   ========================================================== */
+/*
+Fields in assign CAI information element:
+  <byte> length of information element
+  <byte> info field and B-channel hardware
+  <byte> rate adaptation bit rate
+  <byte> async framing parameters
+  <byte> reserved
+  <word> packet length
+  <byte> modem line taking options
+  <byte> modem modulation negotiation parameters
+  <byte> modem modulation options
+  <byte> modem disabled modulations mask low
+  <byte> modem disabled modulations mask high
+  <byte> modem enabled modulations mask
+  <word> modem min TX speed
+  <word> modem max TX speed
+  <word> modem min RX speed
+  <word> modem max RX speed
+  <byte> modem disabled symbol rates mask
+  <byte> modem info options mask
+  <byte> modem transmit level adjust
+  <byte> modem speaker parameters
+  <word> modem private debug config
+  <struct> modem reserved
+  <struct> v18 config parameters
+  <struct> v18 probing sequence
+  <struct> v18 probing message
+*/
+#define DSP_CAI_HARDWARE_HDLC_64K          0x05
+#define DSP_CAI_HARDWARE_HDLC_56K          0x08
+#define DSP_CAI_HARDWARE_TRANSP            0x09
+#define DSP_CAI_HARDWARE_V110_SYNC         0x0c
+#define DSP_CAI_HARDWARE_V110_ASYNC        0x0d
+#define DSP_CAI_HARDWARE_HDLC_128K         0x0f
+#define DSP_CAI_HARDWARE_FAX               0x10
+#define DSP_CAI_HARDWARE_MODEM_ASYNC       0x11
+#define DSP_CAI_HARDWARE_MODEM_SYNC        0x12
+#define DSP_CAI_HARDWARE_V110_HDLCA        0x13
+#define DSP_CAI_HARDWARE_ADVANCED_VOICE    0x14
+#define DSP_CAI_HARDWARE_TRANSP_DTMF       0x16
+#define DSP_CAI_HARDWARE_DTMF_VOICE_ISDN   0x17
+#define DSP_CAI_HARDWARE_DTMF_VOICE_LOCAL  0x18
+#define DSP_CAI_HARDWARE_MASK              0x3f
+#define DSP_CAI_ENABLE_INFO_INDICATIONS    0x80
+#define DSP_CAI_RATE_ADAPTATION_300        0x00
+#define DSP_CAI_RATE_ADAPTATION_600        0x01
+#define DSP_CAI_RATE_ADAPTATION_1200       0x02
+#define DSP_CAI_RATE_ADAPTATION_2400       0x03
+#define DSP_CAI_RATE_ADAPTATION_4800       0x04
+#define DSP_CAI_RATE_ADAPTATION_9600       0x05
+#define DSP_CAI_RATE_ADAPTATION_19200      0x06
+#define DSP_CAI_RATE_ADAPTATION_38400      0x07
+#define DSP_CAI_RATE_ADAPTATION_48000      0x08
+#define DSP_CAI_RATE_ADAPTATION_56000      0x09
+#define DSP_CAI_RATE_ADAPTATION_7200       0x0a
+#define DSP_CAI_RATE_ADAPTATION_14400      0x0b
+#define DSP_CAI_RATE_ADAPTATION_28800      0x0c
+#define DSP_CAI_RATE_ADAPTATION_12000      0x0d
+#define DSP_CAI_RATE_ADAPTATION_1200_75    0x0e
+#define DSP_CAI_RATE_ADAPTATION_75_1200    0x0f
+#define DSP_CAI_RATE_ADAPTATION_MASK       0x0f
+#define DSP_CAI_ASYNC_PARITY_ENABLE        0x01
+#define DSP_CAI_ASYNC_PARITY_SPACE         0x00
+#define DSP_CAI_ASYNC_PARITY_ODD           0x02
+#define DSP_CAI_ASYNC_PARITY_EVEN          0x04
+#define DSP_CAI_ASYNC_PARITY_MARK          0x06
+#define DSP_CAI_ASYNC_PARITY_MASK          0x06
+#define DSP_CAI_ASYNC_ONE_STOP_BIT         0x00
+#define DSP_CAI_ASYNC_TWO_STOP_BITS        0x20
+#define DSP_CAI_ASYNC_CHAR_LENGTH_8        0x00
+#define DSP_CAI_ASYNC_CHAR_LENGTH_7        0x40
+#define DSP_CAI_ASYNC_CHAR_LENGTH_6        0x80
+#define DSP_CAI_ASYNC_CHAR_LENGTH_5        0xc0
+#define DSP_CAI_ASYNC_CHAR_LENGTH_MASK     0xc0
+#define DSP_CAI_MODEM_LEASED_LINE_MODE     0x01
+#define DSP_CAI_MODEM_4_WIRE_OPERATION     0x02
+#define DSP_CAI_MODEM_DISABLE_BUSY_DETECT  0x04
+#define DSP_CAI_MODEM_DISABLE_CALLING_TONE 0x08
+#define DSP_CAI_MODEM_DISABLE_ANSWER_TONE  0x10
+#define DSP_CAI_MODEM_ENABLE_DIAL_TONE_DET 0x20
+#define DSP_CAI_MODEM_USE_POTS_INTERFACE   0x40
+#define DSP_CAI_MODEM_FORCE_RAY_TAYLOR_FAX 0x80
+#define DSP_CAI_MODEM_NEGOTIATE_HIGHEST    0x00
+#define DSP_CAI_MODEM_NEGOTIATE_DISABLED   0x01
+#define DSP_CAI_MODEM_NEGOTIATE_IN_CLASS   0x02
+#define DSP_CAI_MODEM_NEGOTIATE_V100       0x03
+#define DSP_CAI_MODEM_NEGOTIATE_V8         0x04
+#define DSP_CAI_MODEM_NEGOTIATE_V8BIS      0x05
+#define DSP_CAI_MODEM_NEGOTIATE_MASK       0x07
+#define DSP_CAI_MODEM_GUARD_TONE_NONE      0x00
+#define DSP_CAI_MODEM_GUARD_TONE_550HZ     0x40
+#define DSP_CAI_MODEM_GUARD_TONE_1800HZ    0x80
+#define DSP_CAI_MODEM_GUARD_TONE_MASK      0xc0
+#define DSP_CAI_MODEM_DISABLE_RETRAIN      0x01
+#define DSP_CAI_MODEM_DISABLE_STEPUPDOWN   0x02
+#define DSP_CAI_MODEM_DISABLE_SPLIT_SPEED  0x04
+#define DSP_CAI_MODEM_DISABLE_TRELLIS      0x08
+#define DSP_CAI_MODEM_ALLOW_RDL_TEST_LOOP  0x10
+#define DSP_CAI_MODEM_DISABLE_FLUSH_TIMER  0x40
+#define DSP_CAI_MODEM_REVERSE_DIRECTION    0x80
+#define DSP_CAI_MODEM_DISABLE_V21          0x01
+#define DSP_CAI_MODEM_DISABLE_V23          0x02
+#define DSP_CAI_MODEM_DISABLE_V22          0x04
+#define DSP_CAI_MODEM_DISABLE_V22BIS       0x08
+#define DSP_CAI_MODEM_DISABLE_V32          0x10
+#define DSP_CAI_MODEM_DISABLE_V32BIS       0x20
+#define DSP_CAI_MODEM_DISABLE_V34          0x40
+#define DSP_CAI_MODEM_DISABLE_V90          0x80
+#define DSP_CAI_MODEM_DISABLE_BELL103      0x01
+#define DSP_CAI_MODEM_DISABLE_BELL212A     0x02
+#define DSP_CAI_MODEM_DISABLE_VFC          0x04
+#define DSP_CAI_MODEM_DISABLE_K56FLEX      0x08
+#define DSP_CAI_MODEM_DISABLE_X2           0x10
+#define DSP_CAI_MODEM_ENABLE_V29FDX        0x01
+#define DSP_CAI_MODEM_ENABLE_V33           0x02
+#define DSP_CAI_MODEM_DISABLE_2400_SYMBOLS 0x01
+#define DSP_CAI_MODEM_DISABLE_2743_SYMBOLS 0x02
+#define DSP_CAI_MODEM_DISABLE_2800_SYMBOLS 0x04
+#define DSP_CAI_MODEM_DISABLE_3000_SYMBOLS 0x08
+#define DSP_CAI_MODEM_DISABLE_3200_SYMBOLS 0x10
+#define DSP_CAI_MODEM_DISABLE_3429_SYMBOLS 0x20
+#define DSP_CAI_MODEM_DISABLE_TX_REDUCTION 0x01
+#define DSP_CAI_MODEM_DISABLE_PRECODING    0x02
+#define DSP_CAI_MODEM_DISABLE_PREEMPHASIS  0x04
+#define DSP_CAI_MODEM_DISABLE_SHAPING      0x08
+#define DSP_CAI_MODEM_DISABLE_NONLINEAR_EN 0x10
+#define DSP_CAI_MODEM_SPEAKER_OFF          0x00
+#define DSP_CAI_MODEM_SPEAKER_DURING_TRAIN 0x01
+#define DSP_CAI_MODEM_SPEAKER_TIL_CONNECT  0x02
+#define DSP_CAI_MODEM_SPEAKER_ALWAYS_ON    0x03
+#define DSP_CAI_MODEM_SPEAKER_CONTROL_MASK 0x03
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_MIN   0x00
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_LOW   0x04
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_HIGH  0x08
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_MAX   0x0c
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_MASK  0x0c
+/* ==========================================================
+    DCD/CTS State
+   ========================================================== */
+#define MDM_WANT_CONNECT_B3_ACTIVE_I  0x01
+#define MDM_NCPI_VALID                0x02
+#define MDM_NCPI_CTS_ON_RECEIVED      0x04
+#define MDM_NCPI_DCD_ON_RECEIVED      0x08
+/* ==========================================================
+    CAPI NCPI Constants
+   ========================================================== */
+#define MDM_NCPI_ECM_V42              0x0001
+#define MDM_NCPI_ECM_MNP              0x0002
+#define MDM_NCPI_TRANSPARENT          0x0004
+#define MDM_NCPI_COMPRESSED           0x0010
+/* ==========================================================
+    CAPI B2 Config Constants
+   ========================================================== */
+#define MDM_B2_DISABLE_V42bis         0x0001
+#define MDM_B2_DISABLE_MNP            0x0002
+#define MDM_B2_DISABLE_TRANS          0x0004
+#define MDM_B2_DISABLE_V42            0x0008
+#define MDM_B2_DISABLE_COMP           0x0010
+/* ==========================================================
+    CAPI B1 Config Constants
+   ========================================================== */
+#define MDM_CAPI_DISABLE_RETRAIN      0x0001
+#define MDM_CAPI_DISABLE_RING_TONE    0x0002
+#define MDM_CAPI_GUARD_1800           0x0004
+#define MDM_CAPI_GUARD_550            0x0008
+#define MDM_CAPI_NEG_V8               0x0003
+#define MDM_CAPI_NEG_V100             0x0002
+#define MDM_CAPI_NEG_MOD_CLASS        0x0001
+#define MDM_CAPI_NEG_DISABLED         0x0000
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/message.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,15118 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+
+
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "capi20.h"
+#include "divacapi.h"
+#include "mdm_msg.h"
+#include "divasync.h"
+
+
+
+#define FILE_ "MESSAGE.C"
+#define dprintf
+
+
+
+
+
+
+
+
+
+/*------------------------------------------------------------------*/
+/* This is options supported for all adapters that are server by    */
+/* XDI driver. Allo it is not necessary to ask it from every adapter*/
+/* and it is not necessary to save it separate for every adapter    */
+/* Macrose defined here have only local meaning                     */
+/*------------------------------------------------------------------*/
+dword diva_xdi_extended_features = 0;
+
+#define DIVA_CAPI_USE_CMA                 0x00000001
+#define DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR  0x00000002
+#define DIVA_CAPI_XDI_PROVIDES_NO_CANCEL  0x00000004
+#define DIVA_CAPI_XDI_PROVIDES_RX_DMA     0x00000008
+
+/*
+  CAPI can request to process all return codes self only if:
+  protocol code supports this && xdi supports this
+ */
+#define DIVA_CAPI_SUPPORTS_NO_CANCEL(__a__)   (((__a__)->manufacturer_features&MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)&&    ((__a__)->manufacturer_features & MANUFACTURER_FEATURE_OK_FC_LABEL) &&     (diva_xdi_extended_features   & DIVA_CAPI_XDI_PROVIDES_NO_CANCEL))
+
+/*------------------------------------------------------------------*/
+/* local function prototypes                                        */
+/*------------------------------------------------------------------*/
+
+void group_optimization(DIVA_CAPI_ADAPTER   * a, PLCI   * plci);
+void set_group_ind_mask (PLCI   *plci);
+void set_group_ind_mask_bit (PLCI   *plci, word b);
+void clear_group_ind_mask_bit (PLCI   *plci, word b);
+byte test_group_ind_mask_bit (PLCI   *plci, word b);
+void AutomaticLaw(DIVA_CAPI_ADAPTER   *);
+word CapiRelease(word);
+word CapiRegister(word);
+word api_put(APPL   *, CAPI_MSG   *);
+static word api_parse(byte   *, word, byte *, API_PARSE *);
+static void api_save_msg(API_PARSE   *in, byte *format, API_SAVE   *out);
+static void api_load_msg(API_SAVE   *in, API_PARSE   *out);
+
+word api_remove_start(void);
+void api_remove_complete(void);
+
+void plci_remove(PLCI   *);
+static void diva_get_extended_adapter_features (DIVA_CAPI_ADAPTER  * a);
+static void diva_ask_for_xdi_sdram_bar (DIVA_CAPI_ADAPTER  *, IDI_SYNC_REQ  *);
+
+void   callback(ENTITY   *);
+
+static void control_rc(PLCI   *, byte, byte, byte, byte, byte);
+static void data_rc(PLCI   *, byte);
+static void data_ack(PLCI   *, byte);
+static void sig_ind(PLCI   *);
+static void SendInfo(PLCI   *, dword, byte   * *, byte);
+static void SendSetupInfo(APPL   *, PLCI   *, dword, byte   * *, byte);
+void SendSSExtInd(APPL   *, PLCI   * plci, dword Id, byte   * * parms);
+
+void VSwitchReqInd(PLCI   *plci, dword Id, byte   **parms);
+
+static void nl_ind(PLCI   *);
+
+static byte connect_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_a_res(dword,word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte listen_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte info_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte info_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte alert_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte facility_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte facility_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_a_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte data_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte data_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte reset_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte reset_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_t90_a_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte select_b_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte manufacturer_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte manufacturer_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+
+static word get_plci(DIVA_CAPI_ADAPTER   *);
+static void add_p(PLCI   *, byte, byte   *);
+static void add_s(PLCI   * plci, byte code, API_PARSE * p);
+static void add_ss(PLCI   * plci, byte code, API_PARSE * p);
+static void add_ie(PLCI   * plci, byte code, byte   * p, word p_length);
+static void add_d(PLCI   *, word, byte   *);
+static void add_ai(PLCI   *, API_PARSE *);
+static word add_b1(PLCI   *, API_PARSE *, word, word);
+static word add_b23(PLCI   *, API_PARSE *);
+static word add_modem_b23 (PLCI  * plci, API_PARSE* bp_parms);
+static void sig_req(PLCI   *, byte, byte);
+static void nl_req_ncci(PLCI   *, byte, byte);
+static void send_req(PLCI   *);
+static void send_data(PLCI   *);
+static word plci_remove_check(PLCI   *);
+static void listen_check(DIVA_CAPI_ADAPTER   *);
+static byte AddInfo(byte   **, byte   **, byte   *, byte *);
+static byte getChannel(API_PARSE *);
+static void IndParse(PLCI   *, word *, byte   **, byte);
+static byte ie_compare(byte   *, byte *);
+static word find_cip(DIVA_CAPI_ADAPTER   *, byte   *, byte   *);
+static word CPN_filter_ok(byte   *cpn,DIVA_CAPI_ADAPTER   *,word);
+
+/*
+  XON protocol helpers
+  */
+static void channel_flow_control_remove (PLCI   * plci);
+static void channel_x_off (PLCI   * plci, byte ch, byte flag);
+static void channel_x_on (PLCI   * plci, byte ch);
+static void channel_request_xon (PLCI   * plci, byte ch);
+static void channel_xmit_xon (PLCI   * plci);
+static int channel_can_xon (PLCI   * plci, byte ch);
+static void channel_xmit_extended_xon (PLCI   * plci);
+
+static byte SendMultiIE(PLCI   * plci, dword Id, byte   * * parms, byte ie_type, dword info_mask, byte setupParse);
+static word AdvCodecSupport(DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, byte);
+static void CodecIdCheck(DIVA_CAPI_ADAPTER   *, PLCI   *);
+static void SetVoiceChannel(PLCI   *, byte   *, DIVA_CAPI_ADAPTER   * );
+static void VoiceChannelOff(PLCI   *plci);
+static void adv_voice_write_coefs (PLCI   *plci, word write_command);
+static void adv_voice_clear_config (PLCI   *plci);
+
+static word get_b1_facilities (PLCI   * plci, byte b1_resource);
+static byte add_b1_facilities (PLCI   * plci, byte b1_resource, word b1_facilities);
+static void adjust_b1_facilities (PLCI   *plci, byte new_b1_resource, word new_b1_facilities);
+static word adjust_b_process (dword Id, PLCI   *plci, byte Rc);
+static void adjust_b1_resource (dword Id, PLCI   *plci, API_SAVE   *bp_msg, word b1_facilities, word internal_command);
+static void adjust_b_restore (dword Id, PLCI   *plci, byte Rc);
+static void reset_b3_command (dword Id, PLCI   *plci, byte Rc);
+static void select_b_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_connect_ack_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_edata_ack_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_connect_info_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_adjust_b23_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_disconnect_command (dword Id, PLCI   *plci, byte Rc);
+static void hold_save_command (dword Id, PLCI   *plci, byte Rc);
+static void retrieve_restore_command (dword Id, PLCI   *plci, byte Rc);
+static void init_b1_config (PLCI   *plci);
+static void clear_b1_config (PLCI   *plci);
+
+static void dtmf_command (dword Id, PLCI   *plci, byte Rc);
+static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg);
+static void dtmf_confirmation (dword Id, PLCI   *plci);
+static void dtmf_indication (dword Id, PLCI   *plci, byte   *msg, word length);
+static void dtmf_parameter_write (PLCI   *plci);
+
+
+static void mixer_set_bchannel_id_esc (PLCI   *plci, byte bchannel_id);
+static void mixer_set_bchannel_id (PLCI   *plci, byte   *chi);
+static void mixer_clear_config (PLCI   *plci);
+static void mixer_notify_update (PLCI   *plci, byte others);
+static void mixer_command (dword Id, PLCI   *plci, byte Rc);
+static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg);
+static void mixer_indication_coefs_set (dword Id, PLCI   *plci);
+static void mixer_indication_xconnect_from (dword Id, PLCI   *plci, byte   *msg, word length);
+static void mixer_indication_xconnect_to (dword Id, PLCI   *plci, byte   *msg, word length);
+static void mixer_remove (PLCI   *plci);
+
+
+static void ec_command (dword Id, PLCI   *plci, byte Rc);
+static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg);
+static void ec_indication (dword Id, PLCI   *plci, byte   *msg, word length);
+
+
+static void rtp_connect_b3_req_command (dword Id, PLCI   *plci, byte Rc);
+static void rtp_connect_b3_res_command (dword Id, PLCI   *plci, byte Rc);
+
+
+static int  diva_get_dma_descriptor  (PLCI   *plci, dword   *dma_magic);
+static void diva_free_dma_descriptor (PLCI   *plci, int nr);
+
+/*------------------------------------------------------------------*/
+/* external function prototypes                                     */
+/*------------------------------------------------------------------*/
+
+extern byte MapController (byte);
+extern byte UnMapController (byte);
+#define MapId(Id) (((Id) & 0xffffff00L) | MapController ((byte)(Id)))
+#define UnMapId(Id) (((Id) & 0xffffff00L) | UnMapController ((byte)(Id)))
+
+void   sendf(APPL   *, word, dword, word, byte *, ...);
+void   * TransmitBufferSet(APPL   * appl, dword ref);
+void   * TransmitBufferGet(APPL   * appl, void   * p);
+void TransmitBufferFree(APPL   * appl, void   * p);
+void   * ReceiveBufferGet(APPL   * appl, int Num);
+
+int fax_head_line_time (char *buffer);
+
+
+/*------------------------------------------------------------------*/
+/* Global data definitions                                          */
+/*------------------------------------------------------------------*/
+extern byte max_adapter;
+extern byte max_appl;
+extern DIVA_CAPI_ADAPTER   * adapter;
+extern APPL   * application;
+
+
+
+
+
+
+
+byte remove_started = FALSE;
+PLCI dummy_plci;
+
+
+struct _ftable {
+  word command;
+  byte * format;
+  byte (* function)(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+} ftable[] = {
+  {_DATA_B3_R,                          "dwww",         data_b3_req},
+  {_DATA_B3_I|RESPONSE,                 "w",            data_b3_res},
+  {_INFO_R,                             "ss",           info_req},
+  {_INFO_I|RESPONSE,                    "",             info_res},
+  {_CONNECT_R,                          "wsssssssss",   connect_req},
+  {_CONNECT_I|RESPONSE,                 "wsssss",       connect_res},
+  {_CONNECT_ACTIVE_I|RESPONSE,          "",             connect_a_res},
+  {_DISCONNECT_R,                       "s",            disconnect_req},
+  {_DISCONNECT_I|RESPONSE,              "",             disconnect_res},
+  {_LISTEN_R,                           "dddss",        listen_req},
+  {_ALERT_R,                            "s",            alert_req},
+  {_FACILITY_R,                         "ws",           facility_req},
+  {_FACILITY_I|RESPONSE,                "ws",           facility_res},
+  {_CONNECT_B3_R,                       "s",            connect_b3_req},
+  {_CONNECT_B3_I|RESPONSE,              "ws",           connect_b3_res},
+  {_CONNECT_B3_ACTIVE_I|RESPONSE,       "",             connect_b3_a_res},
+  {_DISCONNECT_B3_R,                    "s",            disconnect_b3_req},
+  {_DISCONNECT_B3_I|RESPONSE,           "",             disconnect_b3_res},
+  {_RESET_B3_R,                         "s",            reset_b3_req},
+  {_RESET_B3_I|RESPONSE,                "",             reset_b3_res},
+  {_CONNECT_B3_T90_ACTIVE_I|RESPONSE,   "ws",           connect_b3_t90_a_res},
+  {_CONNECT_B3_T90_ACTIVE_I|RESPONSE,   "",             connect_b3_t90_a_res},
+  {_SELECT_B_REQ,                       "s",            select_b_req},
+  {_MANUFACTURER_R,                     "dws",          manufacturer_req},
+  {_MANUFACTURER_I|RESPONSE,            "dws",          manufacturer_res},
+  {_MANUFACTURER_I|RESPONSE,            "",             manufacturer_res}
+};
+
+byte * cip_bc[29][2] = {
+  { "",                     ""                     }, /* 0 */
+  { "\x03\x80\x90\xa3",     "\x03\x80\x90\xa2"     }, /* 1 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 2 */
+  { "\x02\x89\x90",         "\x02\x89\x90"         }, /* 3 */
+  { "\x03\x90\x90\xa3",     "\x03\x90\x90\xa2"     }, /* 4 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 5 */
+  { "\x02\x98\x90",         "\x02\x98\x90"         }, /* 6 */
+  { "\x04\x88\xc0\xc6\xe6", "\x04\x88\xc0\xc6\xe6" }, /* 7 */
+  { "\x04\x88\x90\x21\x8f", "\x04\x88\x90\x21\x8f" }, /* 8 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 9 */
+  { "",                     ""                     }, /* 10 */
+  { "",                     ""                     }, /* 11 */
+  { "",                     ""                     }, /* 12 */
+  { "",                     ""                     }, /* 13 */
+  { "",                     ""                     }, /* 14 */
+  { "",                     ""                     }, /* 15 */
+
+  { "\x03\x80\x90\xa3",     "\x03\x80\x90\xa2"     }, /* 16 */
+  { "\x03\x90\x90\xa3",     "\x03\x90\x90\xa2"     }, /* 17 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 18 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 19 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 20 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 21 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 22 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 23 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 24 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 25 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 26 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 27 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }  /* 28 */
+};
+
+byte * cip_hlc[29] = {
+  "",                           /* 0 */
+  "",                           /* 1 */
+  "",                           /* 2 */
+  "",                           /* 3 */
+  "",                           /* 4 */
+  "",                           /* 5 */
+  "",                           /* 6 */
+  "",                           /* 7 */
+  "",                           /* 8 */
+  "",                           /* 9 */
+  "",                           /* 10 */
+  "",                           /* 11 */
+  "",                           /* 12 */
+  "",                           /* 13 */
+  "",                           /* 14 */
+  "",                           /* 15 */
+
+  "\x02\x91\x81",               /* 16 */
+  "\x02\x91\x84",               /* 17 */
+  "\x02\x91\xa1",               /* 18 */
+  "\x02\x91\xa4",               /* 19 */
+  "\x02\x91\xa8",               /* 20 */
+  "\x02\x91\xb1",               /* 21 */
+  "\x02\x91\xb2",               /* 22 */
+  "\x02\x91\xb5",               /* 23 */
+  "\x02\x91\xb8",               /* 24 */
+  "\x02\x91\xc1",               /* 25 */
+  "\x02\x91\x81",               /* 26 */
+  "\x03\x91\xe0\x01",           /* 27 */
+  "\x03\x91\xe0\x02"            /* 28 */
+};
+
+/*------------------------------------------------------------------*/
+
+#define V120_HEADER_LENGTH 1
+#define V120_HEADER_EXTEND_BIT  0x80
+#define V120_HEADER_BREAK_BIT   0x40
+#define V120_HEADER_C1_BIT      0x04
+#define V120_HEADER_C2_BIT      0x08
+#define V120_HEADER_FLUSH_COND  (V120_HEADER_BREAK_BIT | V120_HEADER_C1_BIT | V120_HEADER_C2_BIT)
+
+static byte v120_default_header[] =
+{
+
+  0x83                          /*  Ext, BR , res, res, C2 , C1 , B  , F   */
+
+};
+
+static byte v120_break_header[] =
+{
+
+  0xc3 | V120_HEADER_BREAK_BIT  /*  Ext, BR , res, res, C2 , C1 , B  , F   */
+
+};
+
+
+/*------------------------------------------------------------------*/
+/* API_PUT function                                                 */
+/*------------------------------------------------------------------*/
+
+word api_put(APPL   * appl, CAPI_MSG   * msg)
+{
+  word i, j, k, l, n;
+  word ret;
+  byte c;
+  byte controller;
+  DIVA_CAPI_ADAPTER   * a;
+  PLCI   * plci;
+  NCCI   * ncci_ptr;
+  word ncci;
+  CAPI_MSG   *m;
+    API_PARSE msg_parms[MAX_MSG_PARMS+1];
+
+  if (msg->header.length < sizeof (msg->header) ||
+      msg->header.length > MAX_MSG_SIZE) {
+    dbug(1,dprintf("bad len"));
+    return _BAD_MSG;
+  }
+
+  controller = (byte)((msg->header.controller &0x7f)-1);
+
+  /* controller starts with 0 up to (max_adapter - 1) */
+  if ( controller >= max_adapter )
+  {
+    dbug(1,dprintf("invalid ctrl"));
+    return _BAD_MSG;
+  }
+  
+  a = &adapter[controller];
+  plci = 0;
+  if ((msg->header.plci != 0) && (msg->header.plci <= a->max_plci) && !a->adapter_disabled)
+  {
+    dbug(1,dprintf("plci=%x",msg->header.plci));
+    plci = &a->plci[msg->header.plci-1];
+    ncci = READ_WORD(&msg->header.ncci);
+    if (plci->Id
+     && (plci->appl
+      || (plci->State == INC_CON_PENDING)
+      || (plci->State == INC_CON_ALERT)
+      || (msg->header.command == (_DISCONNECT_I|RESPONSE)))
+     && ((ncci == 0)
+      || (msg->header.command == (_DISCONNECT_B3_I|RESPONSE))
+      || ((ncci < MAX_NCCI+1) && (a->ncci_plci[ncci] == plci->Id))))
+    {
+      i = plci->msg_in_read_pos;
+      j = plci->msg_in_write_pos;
+      if (j >= i)
+      {
+        if (j + msg->header.length + MSG_IN_OVERHEAD <= MSG_IN_QUEUE_SIZE)
+          i += MSG_IN_QUEUE_SIZE - j;
+        else
+          j = 0;
+      }
+      else
+      {
+
+        n = (((CAPI_MSG   *)(plci->msg_in_queue))->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+        if (i > MSG_IN_QUEUE_SIZE - n)
+          i = MSG_IN_QUEUE_SIZE - n + 1;
+        i -= j;
+      }
+
+      if (i <= ((msg->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc))
+
+      {
+        dbug(0,dprintf("Q-FULL1(msg) - len=%d write=%d read=%d wrap=%d free=%d",
+          msg->header.length, plci->msg_in_write_pos,
+          plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
+
+        return _QUEUE_FULL;
+      }
+      c = FALSE;
+      if ((((byte   *) msg) < ((byte   *)(plci->msg_in_queue)))
+       || (((byte   *) msg) >= ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+      {
+        if (plci->msg_in_write_pos != plci->msg_in_read_pos)
+          c = TRUE;
+      }
+      if (msg->header.command == _DATA_B3_R)
+      {
+        if (msg->header.length < 20)
+        {
+          dbug(1,dprintf("DATA_B3 REQ wrong length %d", msg->header.length));
+          return _BAD_MSG;
+        }
+        ncci_ptr = &(a->ncci[ncci]);
+        n = ncci_ptr->data_pending;
+        l = ncci_ptr->data_ack_pending;
+        k = plci->msg_in_read_pos;
+        while (k != plci->msg_in_write_pos)
+        {
+          if (k == plci->msg_in_wrap_pos)
+            k = 0;
+          if ((((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->header.command == _DATA_B3_R)
+           && (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->header.ncci == ncci))
+          {
+            n++;
+            if (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->info.data_b3_req.Flags & 0x0004)
+              l++;
+          }
+
+          k += (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->header.length +
+            MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+        }
+        if ((n >= MAX_DATA_B3) || (l >= MAX_DATA_ACK))
+        {
+          dbug(0,dprintf("Q-FULL2(data) - pending=%d/%d ack_pending=%d/%d",
+                          ncci_ptr->data_pending, n, ncci_ptr->data_ack_pending, l));
+
+          return _QUEUE_FULL;
+        }
+        if (plci->req_in || plci->internal_command)
+        {
+          if ((((byte   *) msg) >= ((byte   *)(plci->msg_in_queue)))
+           && (((byte   *) msg) < ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+          {
+            dbug(0,dprintf("Q-FULL3(requeue)"));
+
+            return _QUEUE_FULL;
+          }
+          c = TRUE;
+        }
+      }
+      else
+      {
+        if (plci->req_in || plci->internal_command)
+          c = TRUE;
+        else
+        {
+          plci->command = msg->header.command;
+          plci->number = msg->header.number;
+        }
+      }
+      if (c)
+      {
+        dbug(1,dprintf("enqueue msg(0x%04x,0x%x,0x%x) - len=%d write=%d read=%d wrap=%d free=%d",
+          msg->header.command, plci->req_in, plci->internal_command,
+          msg->header.length, plci->msg_in_write_pos,
+          plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
+        if (j == 0)
+          plci->msg_in_wrap_pos = plci->msg_in_write_pos;
+        m = (CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[j]);
+        for (i = 0; i < msg->header.length; i++)
+          ((byte   *)(plci->msg_in_queue))[j++] = ((byte   *) msg)[i];
+        if (m->header.command == _DATA_B3_R)
+        {
+
+          m->info.data_b3_req.Data = (dword)(TransmitBufferSet (appl, m->info.data_b3_req.Data));
+
+        }
+
+        j = (j + 3) & 0xfffc;
+
+        *((APPL   *   *)(&((byte   *)(plci->msg_in_queue))[j])) = appl;
+        plci->msg_in_write_pos = j + MSG_IN_OVERHEAD;
+        return 0;
+      }
+    }
+    else
+    {
+      plci = 0;
+    }
+  }
+  dbug(1,dprintf("com=%x",msg->header.command));
+
+  for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
+  for(i=0, ret = _BAD_MSG;
+      i<(sizeof(ftable)/sizeof(struct _ftable));
+      i++) {
+
+    if(ftable[i].command==msg->header.command) {
+      /* break loop if the message is correct, otherwise continue scan  */
+      /* (for example: CONNECT_B3_T90_ACT_RES has two specifications)   */
+      if(!api_parse(msg->info.b,(word)(msg->header.length-12),ftable[i].format,msg_parms)) {
+        ret = 0;
+        break;
+      }
+      for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
+    }
+  }
+  if(ret) {
+    dbug(1,dprintf("BAD_MSG"));
+    if(plci) plci->command = 0;
+    return ret;
+  }
+
+
+  c = ftable[i].function(READ_DWORD(&msg->header.controller),
+                         msg->header.number,
+                         a,
+                         plci,
+                         appl,
+                         msg_parms);
+
+  channel_xmit_extended_xon (plci);
+
+  if(c==1) send_req(plci);
+  if(c==2 && plci) plci->req_in = plci->req_in_start = plci->req_out = 0;
+  if(plci && !plci->req_in) plci->command = 0;
+  return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* api_parse function, check the format of api messages             */
+/*------------------------------------------------------------------*/
+
+word api_parse(byte   * msg, word length, byte * format, API_PARSE * parms)
+{
+  word i;
+  word p;
+
+  for(i=0,p=0; format[i]; i++) {
+    if(parms)
+    {
+      parms[i].info = &msg[p];
+    }
+    switch(format[i]) {
+    case 'b':
+      p +=1;
+      break;
+    case 'w':
+      p +=2;
+      break;
+    case 'd':
+      p +=4;
+      break;
+    case 's':
+      if(msg[p]==0xff) {
+        parms[i].info +=2;
+        parms[i].length = msg[p+1] + (msg[p+2]<<8);
+        p +=(parms[i].length +3);
+      }
+      else {
+        parms[i].length = msg[p];
+        p +=(parms[i].length +1);
+      }
+      break;
+    }
+
+    if(p>length) return TRUE;
+  }
+  if(parms) parms[i].info = 0;
+  return FALSE;
+}
+
+void api_save_msg(API_PARSE   *in, byte *format, API_SAVE   *out)
+{
+  word i, j, n = 0;
+  byte   *p;
+
+  p = out->info;
+  for (i = 0; format[i] != '\0'; i++)
+  {
+    out->parms[i].info = p;
+    out->parms[i].length = in[i].length;
+    switch (format[i])
+    {
+    case 'b':
+      n = 1;
+      break;
+    case 'w':
+      n = 2;
+      break;
+    case 'd':
+      n = 4;
+      break;
+    case 's':
+      n = in[i].length + 1;
+      break;
+    }
+    for (j = 0; j < n; j++)
+      *(p++) = in[i].info[j];
+  }
+  out->parms[i].info = 0;
+  out->parms[i].length = 0;
+}
+
+void api_load_msg(API_SAVE   *in, API_PARSE   *out)
+{
+  word i;
+
+  i = 0;
+  do
+  {
+    out[i].info = in->parms[i].info;
+    out[i].length = in->parms[i].length;
+  } while (in->parms[i++].info);
+}
+
+
+/*------------------------------------------------------------------*/
+/* CAPI remove function                                             */
+/*------------------------------------------------------------------*/
+
+word api_remove_start(void)
+{
+  word i;
+  word j;
+
+  if(!remove_started) {
+    remove_started = TRUE;
+    for(i=0;i<max_adapter;i++) {
+      if(adapter[i].request) {
+        for(j=0;j<adapter[i].max_plci;j++) {
+          if(adapter[i].plci[j].Sig.Id) plci_remove(&adapter[i].plci[j]);
+        }
+      }
+    }
+    return 1;
+  }
+  else {
+    for(i=0;i<max_adapter;i++) {
+      if(adapter[i].request) {
+        for(j=0;j<adapter[i].max_plci;j++) {
+          if(adapter[i].plci[j].Sig.Id) return 1;
+        }
+      }
+    }
+  }
+  api_remove_complete();
+  return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* internal command queue                                           */
+/*------------------------------------------------------------------*/
+
+void init_internal_command_queue (PLCI   *plci)
+{
+  word i;
+
+  dbug (1, dprintf ("%s,%d: init_internal_command_queue",
+    (char   *)(FILE_), __LINE__));
+
+  plci->internal_command = 0;
+  for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS; i++)
+    plci->internal_command_queue[i] = 0;
+}
+
+
+void start_internal_command (dword Id, PLCI   *plci, t_std_internal_command command_function)
+{
+  word i;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: start_internal_command",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  if (plci->internal_command == 0)
+  {
+    plci->internal_command_queue[0] = command_function;
+    (* command_function)(Id, plci, OK);
+  }
+  else
+  {
+    i = 1;
+    while (plci->internal_command_queue[i] != 0)
+      i++;
+    plci->internal_command_queue[i] = command_function;
+  }
+}
+
+
+void next_internal_command (dword Id, PLCI   *plci)
+{
+  word i;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: next_internal_command",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  plci->internal_command = 0;
+  plci->internal_command_queue[0] = 0;
+  while (plci->internal_command_queue[1] != 0)
+  {
+    for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++)
+      plci->internal_command_queue[i] = plci->internal_command_queue[i+1];
+    plci->internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS - 1] = 0;
+    (*(plci->internal_command_queue[0]))(Id, plci, OK);
+    if (plci->internal_command != 0)
+      return;
+    plci->internal_command_queue[0] = 0;
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* NCCI allocate/remove function                                    */
+/*------------------------------------------------------------------*/
+
+static dword ncci_mapping_bug = 0;
+
+static word get_ncci (PLCI   *plci, byte ch, word force_ncci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word ncci, i, j, k;
+
+  a = plci->adapter;
+  if (!ch || a->ch_ncci[ch])
+  {
+    ncci_mapping_bug++;
+    dbug(1,dprintf("NCCI mapping exists %ld %02x %02x %02x-%02x",
+      ncci_mapping_bug, ch, force_ncci, a->ncci_ch[a->ch_ncci[ch]], a->ch_ncci[ch]));
+    ncci = ch;
+  }
+  else
+  {
+    if (force_ncci)
+      ncci = force_ncci;
+    else
+    {
+      if ((ch < MAX_NCCI+1) && !a->ncci_ch[ch])
+        ncci = ch;
+      else
+      {
+        ncci = 1;
+        while ((ncci < MAX_NCCI+1) && a->ncci_ch[ncci])
+          ncci++;
+        if (ncci == MAX_NCCI+1)
+        {
+          ncci_mapping_bug++;
+          i = 1;
+          do
+          {
+            j = 1;
+            while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i))
+              j++;
+            k = j;
+            if (j < MAX_NCCI+1)
+            {
+              do
+              {
+                j++;
+              } while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i));
+            }
+          } while ((i < MAX_NL_CHANNEL+1) && (j < MAX_NCCI+1));
+          if (i < MAX_NL_CHANNEL+1)
+          {
+            dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x %02x-%02x-%02x",
+              ncci_mapping_bug, ch, force_ncci, i, k, j));
+          }
+          else
+          {
+            dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x",
+              ncci_mapping_bug, ch, force_ncci));
+          }
+          ncci = ch;
+        }
+      }
+      a->ncci_plci[ncci] = plci->Id;
+      a->ncci_state[ncci] = IDLE;
+      if (!plci->ncci_ring_list)
+        plci->ncci_ring_list = ncci;
+      else
+        a->ncci_next[ncci] = a->ncci_next[plci->ncci_ring_list];
+      a->ncci_next[plci->ncci_ring_list] = (byte) ncci;
+    }
+    a->ncci_ch[ncci] = ch;
+    a->ch_ncci[ch] = (byte) ncci;
+    dbug(1,dprintf("NCCI mapping established %ld %02x %02x %02x-%02x",
+      ncci_mapping_bug, ch, force_ncci, ch, ncci));
+  }
+  return (ncci);
+}
+
+
+static void ncci_free_receive_buffers (PLCI   *plci, word ncci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  APPL   *appl;
+  word i, ncci_code;
+  dword Id;
+
+  a = plci->adapter;
+  Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
+  if (ncci)
+  {
+    if (a->ncci_plci[ncci] == plci->Id)
+    {
+      if (!plci->appl)
+      {
+        ncci_mapping_bug++;
+        dbug(1,dprintf("NCCI mapping appl expected %ld %08lx",
+          ncci_mapping_bug, Id));
+      }
+      else
+      {
+        appl = plci->appl;
+        ncci_code = ncci | (((word) a->Id) << 8);
+        for (i = 0; i < appl->MaxBuffer; i++)
+        {
+          if ((appl->DataNCCI[i] == ncci_code)
+           && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
+          {
+            appl->DataNCCI[i] = 0;
+          }
+        }
+      }
+    }
+  }
+  else
+  {
+    for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+    {
+      if (a->ncci_plci[ncci] == plci->Id)
+      {
+        if (!plci->appl)
+        {
+          ncci_mapping_bug++;
+          dbug(1,dprintf("NCCI mapping no appl %ld %08lx",
+            ncci_mapping_bug, Id));
+        }
+        else
+        {
+          appl = plci->appl;
+          ncci_code = ncci | (((word) a->Id) << 8);
+          for (i = 0; i < appl->MaxBuffer; i++)
+          {
+            if ((appl->DataNCCI[i] == ncci_code)
+             && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
+            {
+              appl->DataNCCI[i] = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+
+static void cleanup_ncci_data (PLCI   *plci, word ncci)
+{
+  NCCI   *ncci_ptr;
+
+  if (ncci && (plci->adapter->ncci_plci[ncci] == plci->Id))
+  {
+    ncci_ptr = &(plci->adapter->ncci[ncci]);
+    if (plci->appl)
+    {
+      while (ncci_ptr->data_pending != 0)
+      {
+        if (!plci->data_sent || (ncci_ptr->DBuffer[ncci_ptr->data_out].P != plci->data_sent_ptr))
+          TransmitBufferFree (plci->appl, ncci_ptr->DBuffer[ncci_ptr->data_out].P);
+        (ncci_ptr->data_out)++;
+        if (ncci_ptr->data_out == MAX_DATA_B3)
+          ncci_ptr->data_out = 0;
+        (ncci_ptr->data_pending)--;
+      }
+    }
+    ncci_ptr->data_out = 0;
+    ncci_ptr->data_pending = 0;
+    ncci_ptr->data_ack_out = 0;
+    ncci_ptr->data_ack_pending = 0;
+  }
+}
+
+
+static void ncci_remove (PLCI   *plci, word ncci, byte preserve_ncci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  dword Id;
+  word i;
+
+  a = plci->adapter;
+  Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
+  if (!preserve_ncci)
+    ncci_free_receive_buffers (plci, ncci);
+  if (ncci)
+  {
+    if (a->ncci_plci[ncci] != plci->Id)
+    {
+      ncci_mapping_bug++;
+      dbug(1,dprintf("NCCI mapping doesn't exist %ld %08lx %02x",
+        ncci_mapping_bug, Id, preserve_ncci));
+    }
+    else
+    {
+      cleanup_ncci_data (plci, ncci);
+      dbug(1,dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
+        ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
+      a->ch_ncci[a->ncci_ch[ncci]] = 0;
+      if (!preserve_ncci)
+      {
+        a->ncci_ch[ncci] = 0;
+        a->ncci_plci[ncci] = 0;
+        a->ncci_state[ncci] = IDLE;
+        i = plci->ncci_ring_list;
+        while ((i != 0) && (a->ncci_next[i] != plci->ncci_ring_list) && (a->ncci_next[i] != ncci))
+          i = a->ncci_next[i];
+        if ((i != 0) && (a->ncci_next[i] == ncci))
+        {
+          if (i == ncci)
+            plci->ncci_ring_list = 0;
+          else if (plci->ncci_ring_list == ncci)
+            plci->ncci_ring_list = i;
+          a->ncci_next[i] = a->ncci_next[ncci];
+        }
+        a->ncci_next[ncci] = 0;
+      }
+    }
+  }
+  else
+  {
+    for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+    {
+      if (a->ncci_plci[ncci] == plci->Id)
+      {
+        cleanup_ncci_data (plci, ncci);
+        dbug(1,dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
+          ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
+        a->ch_ncci[a->ncci_ch[ncci]] = 0;
+        if (!preserve_ncci)
+        {
+          a->ncci_ch[ncci] = 0;
+          a->ncci_plci[ncci] = 0;
+          a->ncci_state[ncci] = IDLE;
+          a->ncci_next[ncci] = 0;
+        }
+      }
+    }
+    if (!preserve_ncci)
+      plci->ncci_ring_list = 0;
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* PLCI remove function                                             */
+/*------------------------------------------------------------------*/
+
+static void plci_free_msg_in_queue (PLCI   *plci)
+{
+  word i;
+
+  if (plci->appl)
+  {
+    i = plci->msg_in_read_pos;
+    while (i != plci->msg_in_write_pos)
+    {
+      if (i == plci->msg_in_wrap_pos)
+        i = 0;
+      if (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[i]))->header.command == _DATA_B3_R)
+      {
+
+        TransmitBufferFree (plci->appl,
+          (byte   *)(((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[i]))->info.data_b3_req.Data));
+
+      }
+
+      i += (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[i]))->header.length +
+        MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+    }
+  }
+  plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+}
+
+
+void plci_remove(PLCI   * plci)
+{
+
+  if(!plci) {
+    dbug(1,dprintf("plci_remove(no plci)"));
+    return;
+  }
+  init_internal_command_queue (plci);
+  dbug(1,dprintf("plci_remove(%x,tel=%x)",plci->Id,plci->tel));
+  if(plci_remove_check(plci))
+  {
+    return;
+  }
+  if (plci->Sig.Id == 0xff)
+  {
+    dbug(1,dprintf("D-channel X.25 plci->NL.Id:%0x", plci->NL.Id));
+    if (plci->NL.Id && !plci->nl_remove_id)
+    {
+      nl_req_ncci(plci,REMOVE,0);
+      send_req(plci);
+    }
+  }
+  else
+  {
+    if (!plci->sig_remove_id
+     && (plci->Sig.Id
+      || (plci->req_in!=plci->req_out)
+      || (plci->nl_req || plci->sig_req)))
+    {
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+    }
+  }
+  ncci_remove (plci, 0, FALSE);
+  plci_free_msg_in_queue (plci);
+
+  plci->channels = 0;
+  plci->appl = 0;
+  if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT))
+    plci->State = OUTG_DIS_PENDING;
+}
+
+/*------------------------------------------------------------------*/
+/* Application Group function helpers                               */
+/*------------------------------------------------------------------*/
+
+void set_group_ind_mask (PLCI   *plci)
+{
+  word i;
+
+  for (i = 0; i < C_IND_MASK_DWORDS; i++)
+    plci->group_optimization_mask_table[i] = 0xffffffffL;
+}
+
+void set_group_ind_mask_bit (PLCI   *plci, word b)
+{
+  plci->group_optimization_mask_table[b >> 5] |= (1L << (b & 0x1f));
+}
+
+void clear_group_ind_mask_bit (PLCI   *plci, word b)
+{
+  plci->group_optimization_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
+}
+
+byte test_group_ind_mask_bit (PLCI   *plci, word b)
+{
+  return ((plci->group_optimization_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
+}
+
+/*------------------------------------------------------------------*/
+/* c_ind_mask operations for arbitrary MAX_APPL                     */
+/*------------------------------------------------------------------*/
+
+void clear_c_ind_mask (PLCI   *plci)
+{
+  word i;
+
+  for (i = 0; i < C_IND_MASK_DWORDS; i++)
+    plci->c_ind_mask_table[i] = 0;
+}
+
+byte c_ind_mask_empty (PLCI   *plci)
+{
+  word i;
+
+  i = 0;
+  while ((i < C_IND_MASK_DWORDS) && (plci->c_ind_mask_table[i] == 0))
+    i++;
+  return (i == C_IND_MASK_DWORDS);
+}
+
+void set_c_ind_mask_bit (PLCI   *plci, word b)
+{
+  plci->c_ind_mask_table[b >> 5] |= (1L << (b & 0x1f));
+}
+
+void clear_c_ind_mask_bit (PLCI   *plci, word b)
+{
+  plci->c_ind_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
+}
+
+byte test_c_ind_mask_bit (PLCI   *plci, word b)
+{
+  return ((plci->c_ind_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
+}
+
+void dump_c_ind_mask (PLCI   *plci)
+{
+static char hex_digit_table[0x10] =
+  {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+  word i, j, k;
+  dword d;
+    char *p;
+    char buf[40];
+
+  for (i = 0; i < C_IND_MASK_DWORDS; i += 4)
+  {
+    p = buf + 36;
+    *p = '\0';
+    for (j = 0; j < 4; j++)
+    {
+      if (i+j < C_IND_MASK_DWORDS)
+      {
+        d = plci->c_ind_mask_table[i+j];
+        for (k = 0; k < 8; k++)
+        {
+          *(--p) = hex_digit_table[d & 0xf];
+          d >>= 4;
+        }
+      }
+      else if (i != 0)
+      {
+        for (k = 0; k < 8; k++)
+          *(--p) = ' ';
+      }
+      *(--p) = ' ';
+    }
+    dbug(1,dprintf ("c_ind_mask =%s", (char   *) p));
+  }
+}
+
+
+
+
+
+#define dump_plcis(a)
+
+
+
+/*------------------------------------------------------------------*/
+/* translation function for each message                            */
+/*------------------------------------------------------------------*/
+
+byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ch;
+  word i;
+  word Info;
+  word CIP;
+  byte LinkLayer;
+  API_PARSE * ai;
+  API_PARSE * bp;
+    API_PARSE ai_parms[5];
+  word channel = 0;
+  dword ch_mask;
+  byte m;
+  static byte esc_chi[35] = {0x02,0x18,0x01};
+  static byte lli[2] = {0x01,0x00};
+  byte noCh = 0;
+  word dir = 0;
+  byte   *p_chi = "";
+
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+
+  dbug(1,dprintf("connect_req(%d)",parms->length));
+  Info = _WRONG_IDENTIFIER;
+  if(a)
+  {
+    if(a->adapter_disabled)
+    {
+      dbug(1,dprintf("adapter disabled"));
+      Id = ((word)1<<8)|a->Id;
+      sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
+      sendf(appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR);
+      return FALSE;
+    }
+    Info = _OUT_OF_PLCI;
+    if((i=get_plci(a)))
+    {
+      Info = 0;
+      plci = &a->plci[i-1];
+      plci->appl = appl;
+      plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+      /* check 'external controller' bit for codec support */
+      if(Id & EXT_CONTROLLER)
+      {
+        if(AdvCodecSupport(a, plci, appl, 0) )
+        {
+          plci->Id = 0;
+          sendf(appl, _CONNECT_R|CONFIRM, Id, Number, "w", _WRONG_IDENTIFIER);
+          return 2;
+        }
+      }
+      ai = &parms[9];
+      bp = &parms[5];
+      ch = 0;
+      if(bp->length)LinkLayer = bp->info[3];
+      else LinkLayer = 0;
+      if(ai->length)
+      {
+        ch=0xffff;
+        if(!api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
+        {
+          ch = 0;
+          if(ai_parms[0].length)
+          {
+            ch = READ_WORD(ai_parms[0].info+1);
+            if(ch>4) ch=0; /* safety -> ignore ChannelID */
+            if(ch==4) /* explizit CHI in message */
+            {
+              /* check length of B-CH struct */
+              if((ai_parms[0].info)[3]>=1)
+              {
+                if((ai_parms[0].info)[4]==CHI)
+                {
+                  p_chi = &((ai_parms[0].info)[5]);
+                }
+                else
+                {
+                  p_chi = &((ai_parms[0].info)[3]);
+                }
+                if(p_chi[0]>35) /* check length of channel ID */
+                {
+                  Info = _WRONG_MESSAGE_FORMAT;    
+                }
+              }
+              else Info = _WRONG_MESSAGE_FORMAT;    
+            }
+
+            if(ch==3 && ai_parms[0].length>=7 && ai_parms[0].length<=36)
+            {
+              dir = READ_WORD(ai_parms[0].info+3);
+              ch_mask = 0;
+              m = 0x3f;
+              for(i=0; i+5<=ai_parms[0].length; i++)
+              {
+                if(ai_parms[0].info[i+5]!=0)
+                {
+                  if((ai_parms[0].info[i+5] | m) != 0xff)
+                    Info = _WRONG_MESSAGE_FORMAT;
+                  else
+                  {
+                    if (ch_mask == 0)
+                      channel = i;
+                    ch_mask |= 1L << i;
+                  }
+                }
+                m = 0;
+              }
+              if (ch_mask == 0)
+                Info = _WRONG_MESSAGE_FORMAT;
+              if (!Info)
+              {
+                if ((ai_parms[0].length == 36) || (ch_mask != ((dword)(1L << channel))))
+                {
+                  esc_chi[0] = (byte)(ai_parms[0].length - 2);
+                  for(i=0; i+5<=ai_parms[0].length; i++)
+                    esc_chi[i+3] = ai_parms[0].info[i+5];
+                }
+                else
+                  esc_chi[0] = 2;
+                esc_chi[2] = (byte)channel;
+                plci->b_channel = (byte)channel; /* not correct for ETSI ch 17..31 */
+                add_p(plci,LLI,lli);
+                add_p(plci,ESC,esc_chi);
+                plci->State = LOCAL_CONNECT;
+                if(!dir) plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;     /* dir 0=DTE, 1=DCE */
+              }
+            }
+          }
+        }
+        else  Info = _WRONG_MESSAGE_FORMAT;
+      }
+
+      dbug(1,dprintf("ch=%x,dir=%x,p_ch=%d",ch,dir,channel));
+      plci->command = _CONNECT_R;
+      plci->number = Number;
+      /* x.31 or D-ch free SAPI in LinkLayer? */
+      if(ch==1 && LinkLayer!=3 && LinkLayer!=12) noCh = TRUE;
+      if((ch==0 || ch==2 || noCh || ch==3 || ch==4) && !Info)
+      {
+        /* B-channel used for B3 connections (ch==0), or no B channel    */
+        /* is used (ch==2) or perm. connection (3) is used  do a CALL    */
+        if(noCh) Info = add_b1(plci,&parms[5],2,0);    /* no resource    */
+        else     Info = add_b1(plci,&parms[5],ch,0); 
+        add_s(plci,OAD,&parms[2]);
+        add_s(plci,OSA,&parms[4]);
+        add_s(plci,BC,&parms[6]);
+        add_s(plci,LLC,&parms[7]);
+        add_s(plci,HLC,&parms[8]);
+        CIP = READ_WORD(parms[0].info);
+        if (a->Info_Mask[appl->Id-1] & 0x200)
+        {
+          /* early B3 connect (CIP mask bit 9) no release after a disc */
+          add_p(plci,LLI,"\x01\x01");
+        }
+        if(READ_WORD(parms[0].info)<29) {
+          add_p(plci,BC,cip_bc[READ_WORD(parms[0].info)][a->u_law]);
+          add_p(plci,HLC,cip_hlc[READ_WORD(parms[0].info)]);
+        }
+        add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+        sig_req(plci,ASSIGN,DSIG_ID);
+      }
+      else if(ch==1) {
+
+        /* D-Channel used for B3 connections */
+        plci->Sig.Id = 0xff;
+        Info = 0;
+      }
+
+      if(!Info && ch!=2 && !noCh ) {
+        Info = add_b23(plci,&parms[5]);
+        if(!Info) {
+          if(!(plci->tel && !plci->adv_nl))nl_req_ncci(plci,ASSIGN,0);
+        }
+      }
+
+      if(!Info)
+      {
+        if(ch==0 || ch==2 || ch==3 || noCh || ch==4)
+        {
+          if(plci->spoofed_msg==SPOOFING_REQUIRED)
+          {
+            api_save_msg(parms, "wsssssssss", &plci->saved_msg);
+            plci->spoofed_msg = CALL_REQ;
+            plci->internal_command = BLOCK_PLCI;
+            plci->command = 0;
+            dbug(1,dprintf("Spoof"));
+            send_req(plci);
+            return FALSE;
+          }
+          if(ch==4)add_p(plci,CHI,p_chi);
+          add_s(plci,CPN,&parms[1]);
+          add_s(plci,DSA,&parms[3]);
+          if(noCh) add_p(plci,ESC,"\x02\x18\xfd");  /* D-channel, no B-L3 */
+          add_ai(plci,&parms[9]);
+          if(!dir)sig_req(plci,CALL_REQ,0);
+          else
+          {
+            plci->command = PERM_LIST_REQ;
+            plci->appl = appl;
+            sig_req(plci,LISTEN_REQ,0);
+            send_req(plci);
+            return FALSE;
+          }
+        }
+        send_req(plci);
+        return FALSE;
+      }
+      plci->Id = 0;
+    }
+  }
+  sendf(appl,
+        _CONNECT_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return 2;
+}
+
+byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word i, Info;
+  word Reject;
+  static byte cau_t[] = {0,0,0x90,0x91,0xac,0x9d,0x86,0xd8,0x9b};
+  static byte esc_t[] = {0x03,0x08,0x00,0x00};
+  API_PARSE * ai;
+    API_PARSE ai_parms[5];
+  word ch=0;
+
+  if(!plci) {
+    dbug(1,dprintf("connect_res(no plci)"));
+    return 0;  /* no plci, no send */
+  }
+
+  dbug(1,dprintf("connect_res(State=0x%x)",plci->State));
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+  ai = &parms[5];
+  dbug(1,dprintf("ai->length=%d",ai->length));
+
+  if(ai->length)
+  {
+    if(!api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
+    {
+      dbug(1,dprintf("ai_parms[0].length=%d/0x%x",ai_parms[0].length,READ_WORD(ai_parms[0].info+1)));
+      ch = 0;
+      if(ai_parms[0].length)
+      {
+        ch = READ_WORD(ai_parms[0].info+1);
+        dbug(1,dprintf("BCH-I=0x%x",ch));
+      }
+    }
+  }
+
+  if(plci->State==INC_CON_CONNECTED_ALERT)
+  {
+    dbug(1,dprintf("Connected Alert Call_Res"));
+    if (a->Info_Mask[appl->Id-1] & 0x200)
+    {
+    /* early B3 connect (CIP mask bit 9) no release after a disc */
+      add_p(plci,LLI,"\x01\x01");
+    }
+    add_s(plci, CONN_NR, &parms[2]);
+    add_s(plci, LLC, &parms[4]);
+    add_ai(plci, &parms[5]);
+    plci->State = INC_CON_ACCEPT;
+    sig_req(plci, CALL_RES,0);
+    return 1;
+  }
+  else if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT) {
+    clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+    dump_c_ind_mask (plci);
+    Reject = READ_WORD(parms[0].info);
+    dbug(1,dprintf("Reject=0x%x",Reject));
+    if(Reject) 
+    {
+      if(c_ind_mask_empty (plci)) 
+      {
+        if((Reject&0xff00)==0x3400) 
+        {
+          esc_t[2] = ((byte)(Reject&0x00ff)) | 0x80;
+          add_p(plci,ESC,esc_t);
+          add_ai(plci, &parms[5]);
+          sig_req(plci,REJECT,0);
+        }      
+        else if(Reject==1 || Reject>9) 
+        {
+          add_ai(plci, &parms[5]);
+          sig_req(plci,HANGUP,0);
+        }
+        else 
+        {
+          esc_t[2] = cau_t[(Reject&0x000f)];
+          add_p(plci,ESC,esc_t);
+          add_ai(plci, &parms[5]);
+          sig_req(plci,REJECT,0);
+        }
+        plci->appl = appl;
+      }
+      else 
+      {
+        sendf(appl, _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
+      }
+    }
+    else {
+      plci->appl = appl;
+      if(Id & EXT_CONTROLLER){
+        if(AdvCodecSupport(a, plci, appl, 0)){
+          dbug(1,dprintf("connect_res(error from AdvCodecSupport)"));
+          sig_req(plci,HANGUP,0);
+          return 1;
+        }
+        if(plci->tel == ADV_VOICE && a->AdvCodecPLCI)
+        {
+          Info = add_b23(plci, &parms[1]);
+          if (Info)
+          {
+            dbug(1,dprintf("connect_res(error from add_b23)"));
+            sig_req(plci,HANGUP,0);
+            return 1;
+          }
+          if(plci->adv_nl)
+          {
+            nl_req_ncci(plci, ASSIGN, 0);
+          }
+        }
+      }
+      else
+      {
+        plci->tel = 0;
+        if(ch!=2)
+        {
+          Info = add_b23(plci, &parms[1]);
+          if (Info)
+          {
+            dbug(1,dprintf("connect_res(error from add_b23 2)"));
+            sig_req(plci,HANGUP,0);
+            return 1;
+          }
+        }
+        nl_req_ncci(plci, ASSIGN, 0);
+      }
+
+      if(plci->spoofed_msg==SPOOFING_REQUIRED)
+      {
+        api_save_msg(parms, "wsssss", &plci->saved_msg);
+        plci->spoofed_msg = CALL_RES;
+        plci->internal_command = BLOCK_PLCI;
+        plci->command = 0;
+        dbug(1,dprintf("Spoof"));
+      }
+      else
+      {
+        add_b1 (plci, &parms[1], ch, plci->B1_facilities);
+        if (a->Info_Mask[appl->Id-1] & 0x200)
+        {
+          /* early B3 connect (CIP mask bit 9) no release after a disc */
+          add_p(plci,LLI,"\x01\x01");
+        }
+        add_s(plci, CONN_NR, &parms[2]);
+        add_s(plci, LLC, &parms[4]);
+        add_ai(plci, &parms[5]);
+        plci->State = INC_CON_ACCEPT;
+        sig_req(plci, CALL_RES,0);
+      }
+
+      for(i=0; i<max_appl; i++) {
+        if(test_c_ind_mask_bit (plci, i)) {
+          sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
+        }
+      }
+    }
+  }
+  return 1;
+}
+
+byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("connect_a_res"));
+  return FALSE;
+}
+
+byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info;
+  word i;
+
+  dbug(1,dprintf("disconnect_req"));
+
+  Info = _WRONG_IDENTIFIER;
+
+  if(plci)
+  {
+    if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT)
+    {
+      clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+      plci->appl = appl;
+      for(i=0; i<max_appl; i++)
+      {
+        if(test_c_ind_mask_bit (plci, i))
+          sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
+      }
+      plci->State = OUTG_DIS_PENDING;
+    }
+    if(plci->Sig.Id && plci->appl)
+    {
+      Info = 0;
+        if(plci->Sig.Id!=0xff)
+        {
+          if(plci->State!=INC_DIS_PENDING)
+          {
+            add_ai(plci, &msg[0]);
+            sig_req(plci,HANGUP,0);
+            plci->State = OUTG_DIS_PENDING;
+            return 1;
+          }
+        }
+        else
+        {
+          if (plci->NL.Id && !plci->nl_remove_id)
+          {
+            mixer_remove (plci);
+            nl_req_ncci(plci,REMOVE,0);
+          sendf(appl,_DISCONNECT_R|CONFIRM,Id,Number,"w",0);
+          sendf(appl, _DISCONNECT_I, Id, 0, "w", 0);
+          plci->State = INC_DIS_PENDING;
+          }
+          return 1;
+        }
+      }
+    }
+
+  if(!appl)  return FALSE;
+  sendf(appl, _DISCONNECT_R|CONFIRM, Id, Number, "w",Info);
+  return FALSE;
+}
+
+byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("disconnect_res"));
+  if(plci)
+  {
+        /* clear ind mask bit, just in case of collsion of          */
+        /* DISCONNECT_IND and CONNECT_RES                           */
+    clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+    ncci_free_receive_buffers (plci, 0);
+    if(plci_remove_check(plci))
+    {
+      return 0;
+    }
+    if(plci->State==INC_DIS_PENDING
+    || plci->State==SUSPENDING) {
+      if(c_ind_mask_empty (plci)) {
+        if(plci->State!=SUSPENDING)plci->State = IDLE;
+        dbug(1,dprintf("chs=%d",plci->channels));
+        if(!plci->channels) {
+          plci_remove(plci);
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info;
+  byte i;
+
+  dbug(1,dprintf("listen_req(Appl=0x%x)",appl->Id));
+
+  Info = _WRONG_IDENTIFIER;
+  if(a) {
+    Info = 0;
+    a->Info_Mask[appl->Id-1] = READ_DWORD(parms[0].info);
+    a->CIP_Mask[appl->Id-1] = READ_DWORD(parms[1].info);
+    dbug(1,dprintf("CIP_MASK=0x%lx",READ_DWORD(parms[1].info)));
+    if (a->Info_Mask[appl->Id-1] & 0x200){ /* early B3 connect provides */
+      a->Info_Mask[appl->Id-1] |=  0x10;   /* call progression infos    */
+    }
+
+    /* check if external controller listen and switch listen on or off*/
+    if(Id&EXT_CONTROLLER && READ_DWORD(parms[1].info)){
+      if(a->profile.Global_Options & ON_BOARD_CODEC) {
+        dummy_plci.State = IDLE;
+        a->codec_listen[appl->Id-1] = &dummy_plci;
+        a->TelOAD[0] = (byte)(parms[3].length);
+        for(i=1;parms[3].length>=i && i<22;i++) {
+          a->TelOAD[i] = parms[3].info[i];
+        }
+        a->TelOAD[i] = 0;
+        a->TelOSA[0] = (byte)(parms[4].length);
+        for(i=1;parms[4].length>=i && i<22;i++) {
+          a->TelOSA[i] = parms[4].info[i];
+        }
+        a->TelOSA[i] = 0;
+      }
+      else Info = 0x2002; /* wrong controller, codec not supported */
+    }
+    else{               /* clear listen */
+      a->codec_listen[appl->Id-1] = (PLCI   *)0;
+    }
+  }
+  sendf(appl,
+        _LISTEN_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+
+  if (a) listen_check(a);
+  return FALSE;
+}
+
+byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word i;
+  API_PARSE * ai;
+  PLCI   * rc_plci = 0;
+    API_PARSE ai_parms[5];
+  word Info = 0;
+
+  dbug(1,dprintf("info_req"));
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+
+  ai = &msg[1];
+
+  if(ai->length)
+  {
+    if(api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
+    {
+      dbug(1,dprintf("AddInfo wrong"));
+      Info = _WRONG_MESSAGE_FORMAT;
+    }
+  }
+  if(!a) Info = _WRONG_STATE;
+
+  if(!Info && plci)
+  {                /* no fac, with CPN, or KEY */
+    rc_plci = plci;
+    if(!ai_parms[3].length && plci->State && (msg[0].length || ai_parms[1].length) )
+    {
+      /* overlap sending option */
+      dbug(1,dprintf("OvlSnd"));
+      add_s(plci,CPN,&msg[0]);
+      add_s(plci,KEY,&ai_parms[1]);
+      sig_req(plci,INFO_REQ,0);
+      send_req(plci);
+      return FALSE;
+    }
+
+    if(plci->State && ai_parms[2].length)
+    {
+      /* User_Info option */
+      dbug(1,dprintf("UUI"));
+      add_s(plci,UUI,&ai_parms[2]);
+      sig_req(plci,USER_DATA,0);
+    }
+    else if(plci->State && ai_parms[3].length)
+    {
+      /* Facility option */
+      dbug(1,dprintf("FAC"));
+      add_s(plci,CPN,&msg[0]);
+      add_ai(plci, &msg[1]);
+      sig_req(plci,FACILITY_REQ,0);
+    }
+    else
+    {
+      Info = _WRONG_STATE;
+    }
+  }
+  else if((ai_parms[1].length || ai_parms[2].length || ai_parms[3].length) && !Info)
+  {
+    /* NCR_Facility option -> send UUI and Keypad too */
+    dbug(1,dprintf("NCR_FAC"));
+    if((i=get_plci(a)))
+    {
+      rc_plci = &a->plci[i-1];
+      appl->NullCREnable  = TRUE;
+      rc_plci->internal_command = C_NCR_FAC_REQ;
+      rc_plci->appl = appl;
+      add_p(rc_plci,CAI,"\x01\x80");
+      add_p(rc_plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+      sig_req(rc_plci,ASSIGN,DSIG_ID);
+      send_req(rc_plci);
+    }
+    else
+    {
+      Info = _OUT_OF_PLCI;
+    }
+
+    if(!Info)
+    {
+      add_s(rc_plci,CPN,&msg[0]);
+      add_ai(rc_plci, &msg[1]);
+      sig_req(rc_plci,NCR_FACILITY,0);
+      send_req(rc_plci);
+      return FALSE;
+     /* for application controlled supplementary services    */
+    }
+  }
+
+  if (!rc_plci)
+  {
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+
+  if(!Info)
+  {
+    send_req(rc_plci);
+  }
+  else
+  {  /* appl is not assigned to a PLCI or error condition */
+    dbug(1,dprintf("localInfoCon"));
+    sendf(appl,
+          _INFO_R|CONFIRM,
+          Id,
+          Number,
+          "w",Info);
+  }
+  return FALSE;
+}
+
+byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("info_res"));
+  return FALSE;
+}
+
+byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info;
+  byte ret;
+
+  dbug(1,dprintf("alert_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ret = FALSE;
+  if(plci) {
+    Info = _ALERT_IGNORED;
+    if(plci->State!=INC_CON_ALERT) {
+      Info = _WRONG_STATE;
+      if(plci->State==INC_CON_PENDING) {
+        Info = 0;
+        plci->State=INC_CON_ALERT;
+        add_ai(plci, &msg[0]);
+        sig_req(plci,CALL_ALERT,0);
+        ret = 1;
+      }
+    }
+  }
+  sendf(appl,
+        _ALERT_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return ret;
+}
+
+byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info = 0;
+  word i    = 0;
+
+  word selector;
+  word SSreq;
+  long relatedPLCIvalue;
+  DIVA_CAPI_ADAPTER   * relatedadapter;
+  byte * SSparms  = "";
+    byte RCparms[]  = "\x05\x00\x00\x02\x00\x00";
+    byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
+  API_PARSE * parms;
+    API_PARSE ss_parms[11];
+  PLCI   *rplci;
+    byte cai[15];
+  dword d;
+    API_PARSE dummy;
+
+  dbug(1,dprintf("facility_req"));
+  for(i=0;i<9;i++) ss_parms[i].length = 0;
+
+  parms = &msg[1];
+
+  if(!a)
+  {
+    dbug(1,dprintf("wrong Ctrl"));
+    Info = _WRONG_IDENTIFIER;
+  }
+
+  selector = READ_WORD(msg[0].info);
+
+  if(!Info)
+  {
+    switch(selector)
+    {
+      case SELECTOR_HANDSET:
+        Info = AdvCodecSupport(a, plci, appl, HOOK_SUPPORT);
+        break;
+
+      case SELECTOR_SU_SERV:
+        if(!msg[1].length)
+        {
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        SSreq = READ_WORD(&(msg[1].info[1]));
+        WRITE_WORD(&RCparms[1],SSreq);
+        SSparms = RCparms;
+        switch(SSreq)
+        {
+          case S_GET_SUPPORTED_SERVICES:
+            if((i=get_plci(a)))
+            {
+              rplci = &a->plci[i-1];
+              rplci->appl = appl;
+              add_p(rplci,CAI,"\x01\x80");
+              add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(rplci,ASSIGN,DSIG_ID);
+              send_req(rplci);
+            }
+            else
+            {
+              WRITE_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
+              SSparms = (byte *)SSstruct;
+              break;
+            }
+            rplci->internal_command = GETSERV_REQ_PEND;
+            rplci->number = Number;
+            rplci->appl = appl;
+            sig_req(rplci,S_SUPPORTED,0);
+            send_req(rplci);
+            return FALSE;
+            break;
+
+          case S_LISTEN:
+            if(parms->length==7)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            else
+            {
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            a->Notification_Mask[appl->Id-1] = READ_DWORD(ss_parms[2].info);
+            if(a->Notification_Mask[appl->Id-1] & SMASK_MWI) /* MWI active? */
+            {
+              if((i=get_plci(a)))
+              {
+                rplci = &a->plci[i-1];
+                rplci->appl = appl;
+                add_p(rplci,CAI,"\x01\x80");
+                add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+                sig_req(rplci,ASSIGN,DSIG_ID);
+                send_req(rplci);
+              }
+              else
+              {
+                break;
+              }
+              rplci->internal_command = GET_MWI_STATE;
+              rplci->number = Number;
+              sig_req(rplci,MWI_POLL,0);
+              send_req(rplci);
+            }
+            break;
+
+          case S_HOLD:
+            api_parse(&parms->info[1],(word)parms->length,"ws",ss_parms);
+            if(plci && plci->State && plci->SuppState==IDLE)
+            {
+              plci->SuppState = HOLD_REQUEST;
+              plci->command = C_HOLD_REQ;
+              add_s(plci,CAI,&ss_parms[1]);
+              sig_req(plci,CALL_HOLD,0);
+              send_req(plci);
+              return FALSE;
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+          case S_RETRIEVE:
+            if(plci && plci->State && plci->SuppState==CALL_HELD)
+            {
+              if(Id & EXT_CONTROLLER)
+              {
+                if(AdvCodecSupport(a, plci, appl, 0))
+                {
+                  Info = 0x3010;                    /* wrong state           */
+                  break;
+                }
+              }
+              else plci->tel = 0;
+
+              plci->SuppState = RETRIEVE_REQUEST;
+              plci->command = C_RETRIEVE_REQ;
+              if(plci->spoofed_msg==SPOOFING_REQUIRED)
+              {
+                plci->spoofed_msg = CALL_RETRIEVE;
+                plci->internal_command = BLOCK_PLCI;
+                plci->command = 0;
+                dbug(1,dprintf("Spoof"));
+                return FALSE;
+              }
+              else
+              {
+                sig_req(plci,CALL_RETRIEVE,0);
+                send_req(plci);
+                return FALSE;
+              }
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+          case S_SUSPEND:
+            if(parms->length)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbs",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            if(plci && plci->State)
+            {
+              add_s(plci,CAI,&ss_parms[2]);
+              plci->command = SUSPEND_REQ;
+              sig_req(plci,SUSPEND,0);
+              plci->State = SUSPENDING;
+              send_req(plci);
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+
+          case S_RESUME:
+            if(!(i=get_plci(a)) )
+            {
+              Info = _OUT_OF_PLCI;
+              break;
+            }
+            rplci = &a->plci[i-1];
+            rplci->appl = appl;
+            rplci->number = Number;
+            rplci->tel = 0;
+            rplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+            /* check 'external controller' bit for codec support */
+            if(Id & EXT_CONTROLLER)
+            {
+              if(AdvCodecSupport(a, rplci, appl, 0) )
+              {
+                rplci->Id = 0;
+                Info = 0x300A;
+                break;
+              }
+            }
+            if(parms->length)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbs",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                rplci->Id = 0;
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            dummy.length = 0;
+            dummy.info = "\x00";
+            add_b1(rplci, &dummy, 0, 0);
+            if (a->Info_Mask[appl->Id-1] & 0x200)
+            {
+              /* early B3 connect (CIP mask bit 9) no release after a disc */
+              add_p(rplci,LLI,"\x01\x01");
+            }
+            add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            sig_req(rplci,ASSIGN,DSIG_ID);
+            send_req(rplci);
+            add_s(rplci,CAI,&ss_parms[2]);
+            rplci->command = RESUME_REQ;
+            sig_req(rplci,RESUME,0);
+            rplci->State = RESUMING;
+            send_req(rplci);
+            break;
+
+          case S_CONF_BEGIN: /* Request */
+          case S_CONF_DROP:
+          case S_CONF_ISOLATE:
+          case S_CONF_REATTACH:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(plci && plci->State && ((plci->SuppState==IDLE)||(plci->SuppState==CALL_HELD)))
+            {
+              d = READ_DWORD(ss_parms[2].info);     
+              if(d>=0x80)
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+              plci->ptyState = (byte)SSreq;
+              plci->command = 0;
+              cai[0] = 2;
+              switch(SSreq)
+              {
+              case S_CONF_BEGIN:
+                  cai[1] = CONF_BEGIN;
+                  plci->internal_command = CONF_BEGIN_REQ_PEND;
+                  break;
+              case S_CONF_DROP:
+                  cai[1] = CONF_DROP;
+                  plci->internal_command = CONF_DROP_REQ_PEND;
+                  break;
+              case S_CONF_ISOLATE:
+                  cai[1] = CONF_ISOLATE;
+                  plci->internal_command = CONF_ISOLATE_REQ_PEND;
+                  break;
+              case S_CONF_REATTACH:
+                  cai[1] = CONF_REATTACH;
+                  plci->internal_command = CONF_REATTACH_REQ_PEND;
+                  break;
+              }
+              cai[2] = (byte)d; /* Conference Size resp. PartyId */
+              add_p(plci,CAI,cai);
+              sig_req(plci,S_SERVICE,0);
+              send_req(plci);
+              return FALSE;
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+
+          case S_ECT:
+          case S_3PTY_BEGIN:
+          case S_3PTY_END:
+          case S_CONF_ADD:
+            if(parms->length==7)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            else if(parms->length==8) /* workaround for the T-View-S */
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbdb",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            else
+            {
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(!msg[1].length)
+            {
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if (!plci)
+            {
+              Info = _WRONG_IDENTIFIER;
+              break;
+            }
+            relatedPLCIvalue = READ_DWORD(ss_parms[2].info);
+            relatedPLCIvalue &= 0x0000FFFF;
+            dbug(1,dprintf("PTY/ECT/addCONF,relPLCI=%lx",relatedPLCIvalue));
+            /* controller starts with 0 up to (max_adapter - 1) */
+            if (((relatedPLCIvalue & 0x7f) == 0)
+             || (MapController ((byte)(relatedPLCIvalue & 0x7f)) == 0)
+             || (MapController ((byte)(relatedPLCIvalue & 0x7f)) > max_adapter))
+            {
+              if(SSreq==S_3PTY_END)
+              {
+                dbug(1, dprintf("wrong Controller use 2nd PLCI=PLCI"));
+                rplci = plci;
+              }
+              else
+              {
+                Info = 0x3010;                    /* wrong state           */
+                break;
+              }
+            }
+            else
+            {  
+              relatedadapter = &adapter[MapController ((byte)(relatedPLCIvalue & 0x7f))-1];
+              relatedPLCIvalue >>=8;
+              /* find PLCI PTR*/
+              for(i=0,rplci=0;i<relatedadapter->max_plci;i++)
+              {
+                if(relatedadapter->plci[i].Id == (byte)relatedPLCIvalue)
+                {
+                  rplci = &relatedadapter->plci[i];
+                }
+              }
+              if(!rplci || !relatedPLCIvalue)
+              {
+                if(SSreq==S_3PTY_END)
+                {
+                  dbug(1, dprintf("use 2nd PLCI=PLCI"));
+                  rplci = plci;
+                }
+                else
+                {
+                  Info = 0x3010;                    /* wrong state           */
+                  break;
+                }
+              }
+            }
+/*
+            dbug(1,dprintf("rplci:%x",rplci));
+            dbug(1,dprintf("plci:%x",plci));
+            dbug(1,dprintf("rplci->ptyState:%x",rplci->ptyState));
+            dbug(1,dprintf("plci->ptyState:%x",plci->ptyState));
+            dbug(1,dprintf("SSreq:%x",SSreq));
+            dbug(1,dprintf("rplci->internal_command:%x",rplci->internal_command));
+            dbug(1,dprintf("rplci->appl:%x",rplci->appl));
+            dbug(1,dprintf("rplci->Id:%x",rplci->Id));
+*/
+            /* send PTY/ECT req, cannot check all states because of US stuff */
+            if( !rplci->internal_command && rplci->appl )
+            {
+              plci->command = 0;
+              rplci->relatedPTYPLCI = plci;
+              plci->relatedPTYPLCI = rplci;
+              rplci->ptyState = (byte)SSreq;
+              if(SSreq==S_ECT)
+              {
+                rplci->internal_command = ECT_REQ_PEND;
+                cai[1] = ECT_EXECUTE;
+
+                rplci->vswitchstate=0;
+                rplci->vsprot=0;
+                rplci->vsprotdialect=0;
+                plci->vswitchstate=0;
+                plci->vsprot=0;
+                plci->vsprotdialect=0;
+
+              }
+              else if(SSreq==S_CONF_ADD)
+              {
+                rplci->internal_command = CONF_ADD_REQ_PEND;
+                cai[1] = CONF_ADD;
+              }
+              else
+              {
+                rplci->internal_command = PTY_REQ_PEND;
+                cai[1] = (byte)(SSreq-3);
+              }
+              rplci->number = Number;
+              if(plci!=rplci) /* explicit invocation */
+              {
+                cai[0] = 2;
+                cai[2] = plci->Sig.Id;
+                dbug(1,dprintf("explicit invocation"));
+              }
+              else
+              {
+                dbug(1,dprintf("implicit invocation"));
+                cai[0] = 1;
+              }
+              add_p(rplci,CAI,cai);
+              sig_req(rplci,S_SERVICE,0);
+              send_req(rplci);
+              return FALSE;
+            }
+            else
+            {
+              dbug(0,dprintf("Wrong line"));
+              Info = 0x3010;                    /* wrong state           */
+              break;
+            }
+            break;
+
+          case S_CALL_DEFLECTION:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbwss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if (!plci)
+            {
+              Info = _WRONG_IDENTIFIER;
+              break;
+            }
+            /* reuse unused screening indicator */
+            ss_parms[3].info[3] = (byte)READ_WORD(&(ss_parms[2].info[0]));
+            plci->command = 0;
+            plci->internal_command = CD_REQ_PEND;
+            appl->CDEnable = TRUE;
+            cai[0] = 1;
+            cai[1] = CALL_DEFLECTION;
+            add_p(plci,CAI,cai);
+            add_p(plci,CPN,ss_parms[3].info);
+            sig_req(plci,S_SERVICE,0);
+            send_req(plci);
+            return FALSE;
+            break;
+
+          case S_CALL_FORWARDING_START:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbdwwsss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+
+            if((i=get_plci(a)))
+            {
+              rplci = &a->plci[i-1];
+              rplci->appl = appl;
+              add_p(rplci,CAI,"\x01\x80");
+              add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(rplci,ASSIGN,DSIG_ID);
+              send_req(rplci);
+            }
+            else
+            {
+              Info = _OUT_OF_PLCI;
+              break;
+            }
+
+            /* reuse unused screening indicator */
+            rplci->internal_command = CF_START_PEND;
+            rplci->appl = appl;
+            rplci->number = Number;
+            appl->S_Handle = READ_DWORD(&(ss_parms[2].info[0]));
+            cai[0] = 2;
+            cai[1] = 0x70|(byte)READ_WORD(&(ss_parms[3].info[0])); /* Function */
+            cai[2] = (byte)READ_WORD(&(ss_parms[4].info[0])); /* Basic Service */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,OAD,ss_parms[5].info);
+            add_p(rplci,CPN,ss_parms[6].info);
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+            break;
+
+          case S_INTERROGATE_DIVERSION:
+          case S_INTERROGATE_NUMBERS:
+          case S_CALL_FORWARDING_STOP:
+          case S_CCBS_REQUEST:
+          case S_CCBS_DEACTIVATE:
+          case S_CCBS_INTERROGATE:
+            switch(SSreq)
+            {
+            case S_INTERROGATE_NUMBERS:
+                if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+                {
+                  dbug(0,dprintf("format wrong"));
+                  Info = _WRONG_MESSAGE_FORMAT;
+                }
+                break;
+            case S_CCBS_REQUEST:
+            case S_CCBS_DEACTIVATE:
+                if(api_parse(&parms->info[1],(word)parms->length,"wbdw",ss_parms))
+                {
+                  dbug(0,dprintf("format wrong"));
+                  Info = _WRONG_MESSAGE_FORMAT;
+                }
+                break;
+            case S_CCBS_INTERROGATE:
+                if(api_parse(&parms->info[1],(word)parms->length,"wbdws",ss_parms))
+                {
+                  dbug(0,dprintf("format wrong"));
+                  Info = _WRONG_MESSAGE_FORMAT;
+                }
+                break;
+            default:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbdwws",ss_parms))
+            {
+              dbug(0,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+                break;
+            }
+
+            if(Info) break;
+            if((i=get_plci(a)))
+            {
+              rplci = &a->plci[i-1];
+              switch(SSreq)
+              {
+                case S_INTERROGATE_DIVERSION: /* use cai with S_SERVICE below */
+                  cai[1] = 0x60|(byte)READ_WORD(&(ss_parms[3].info[0])); /* Function */
+                  rplci->internal_command = INTERR_DIVERSION_REQ_PEND; /* move to rplci if assigned */
+                  break;
+                case S_INTERROGATE_NUMBERS: /* use cai with S_SERVICE below */
+                  cai[1] = DIVERSION_INTERROGATE_NUM; /* Function */
+                  rplci->internal_command = INTERR_NUMBERS_REQ_PEND; /* move to rplci if assigned */
+                  break;
+                case S_CALL_FORWARDING_STOP:
+                  rplci->internal_command = CF_STOP_PEND;
+                  cai[1] = 0x80|(byte)READ_WORD(&(ss_parms[3].info[0])); /* Function */
+                  break;
+                case S_CCBS_REQUEST:
+                  cai[1] = CCBS_REQUEST;
+                  rplci->internal_command = CCBS_REQUEST_REQ_PEND;
+                  break;
+                case S_CCBS_DEACTIVATE:
+                  cai[1] = CCBS_DEACTIVATE;
+                  rplci->internal_command = CCBS_DEACTIVATE_REQ_PEND;
+                  break;
+                case S_CCBS_INTERROGATE:
+                  cai[1] = CCBS_INTERROGATE;
+                  rplci->internal_command = CCBS_INTERROGATE_REQ_PEND;
+                  break;
+                default:
+                  cai[1] = 0;
+                break;
+              }
+              rplci->appl = appl;
+              rplci->number = Number;
+              add_p(rplci,CAI,"\x01\x80");
+              add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(rplci,ASSIGN,DSIG_ID);
+              send_req(rplci);
+            }
+            else
+            {
+              Info = _OUT_OF_PLCI;
+              break;
+            }
+
+            appl->S_Handle = READ_DWORD(&(ss_parms[2].info[0]));
+            switch(SSreq)
+            {
+            case S_INTERROGATE_NUMBERS:
+                cai[0] = 1;
+                add_p(rplci,CAI,cai);
+                break;
+            case S_CCBS_REQUEST:
+            case S_CCBS_DEACTIVATE:
+                cai[0] = 3;
+                WRITE_WORD(&cai[2],READ_WORD(&(ss_parms[3].info[0])));
+                add_p(rplci,CAI,cai);
+                break;
+            case S_CCBS_INTERROGATE:
+                cai[0] = 3;
+                WRITE_WORD(&cai[2],READ_WORD(&(ss_parms[3].info[0])));
+                add_p(rplci,CAI,cai);
+                add_p(rplci,OAD,ss_parms[4].info);
+                break;
+            default:
+            cai[0] = 2;
+            cai[2] = (byte)READ_WORD(&(ss_parms[4].info[0])); /* Basic Service */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,OAD,ss_parms[5].info);
+                break;
+            }
+                        
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+            break;
+
+          case S_MWI_ACTIVATE:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbwdwwwssss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(!plci)
+            {                               
+              if((i=get_plci(a)))
+              {
+                rplci = &a->plci[i-1];
+                rplci->appl = appl;
+                rplci->cr_enquiry=TRUE;
+                add_p(rplci,CAI,"\x01\x80");
+                add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+                sig_req(rplci,ASSIGN,DSIG_ID);
+                send_req(rplci);
+              }
+              else
+              {
+                Info = _OUT_OF_PLCI;
+                break;
+              }
+            }
+            else
+            {
+              rplci = plci;
+              rplci->cr_enquiry=FALSE;
+            }
+
+            rplci->command = 0;
+            rplci->internal_command = MWI_ACTIVATE_REQ_PEND;
+            rplci->appl = appl;
+            rplci->number = Number;
+
+            cai[0] = 13;
+            cai[1] = ACTIVATION_MWI; /* Function */
+            WRITE_WORD(&cai[2],READ_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
+            WRITE_DWORD(&cai[4],READ_DWORD(&(ss_parms[3].info[0]))); /* Number of Messages */
+            WRITE_WORD(&cai[8],READ_WORD(&(ss_parms[4].info[0]))); /* Message Status */
+            WRITE_WORD(&cai[10],READ_WORD(&(ss_parms[5].info[0]))); /* Message Reference */
+            WRITE_WORD(&cai[12],READ_WORD(&(ss_parms[6].info[0]))); /* Invocation Mode */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,CPN,ss_parms[7].info); /* Receiving User Number */
+            add_p(rplci,OAD,ss_parms[8].info); /* Controlling User Number */
+            add_p(rplci,OSA,ss_parms[9].info); /* Controlling User Provided Number */
+            add_p(rplci,UID,ss_parms[10].info); /* Time */
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+
+          case S_MWI_DEACTIVATE:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbwwss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(!plci)
+            {                               
+              if((i=get_plci(a)))
+              {
+                rplci = &a->plci[i-1];
+                rplci->appl = appl;
+                rplci->cr_enquiry=TRUE;
+                add_p(rplci,CAI,"\x01\x80");
+                add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+                sig_req(rplci,ASSIGN,DSIG_ID);
+                send_req(rplci);
+              }
+              else
+              {
+                Info = _OUT_OF_PLCI;
+                break;
+              }
+            }
+            else
+            {
+              rplci = plci;
+              rplci->cr_enquiry=FALSE;
+            }
+
+            rplci->command = 0;
+            rplci->internal_command = MWI_DEACTIVATE_REQ_PEND;
+            rplci->appl = appl;
+            rplci->number = Number;
+
+            cai[0] = 5;
+            cai[1] = DEACTIVATION_MWI; /* Function */
+            WRITE_WORD(&cai[2],READ_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
+            WRITE_WORD(&cai[4],READ_WORD(&(ss_parms[3].info[0]))); /* Invocation Mode */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,CPN,ss_parms[4].info); /* Receiving User Number */
+            add_p(rplci,OAD,ss_parms[5].info); /* Controlling User Number */
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+
+          default:
+            Info = 0x300E;  /* not supported */
+            break;
+        }
+        break; /* case SELECTOR_SU_SERV: end */
+
+
+      case SELECTOR_DTMF:
+        return (dtmf_request (Id, Number, a, plci, appl, msg));
+
+
+
+      case SELECTOR_LINE_INTERCONNECT:
+        return (mixer_request (Id, Number, a, plci, appl, msg));
+
+
+
+      case PRIV_SELECTOR_ECHO_CANCELLER:
+        appl->appl_flags |= APPL_FLAG_PRIV_EC_SPEC;
+        return (ec_request (Id, Number, a, plci, appl, msg));
+
+      case SELECTOR_ECHO_CANCELLER:
+        appl->appl_flags &= ~APPL_FLAG_PRIV_EC_SPEC;
+        return (ec_request (Id, Number, a, plci, appl, msg));
+
+
+      case SELECTOR_V42BIS:
+      default:
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+    } /* end of switch(selector) */
+  }
+
+  dbug(1,dprintf("SendFacRc"));
+  sendf(appl,
+        _FACILITY_R|CONFIRM,
+        Id,
+        Number,
+        "wws",Info,selector,SSparms);
+  return FALSE;
+}
+
+byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("facility_res"));
+  return FALSE;
+}
+
+byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info = 0;
+  byte req;
+  byte len;
+  word w;
+  word fax_control_bits, fax_feature_bits, fax_info_change;
+  API_PARSE * ncpi;
+    byte pvc[2];
+
+    API_PARSE fax_parms[9];
+  word i;
+
+
+  dbug(1,dprintf("connect_b3_req"));
+  if(plci)
+  {
+    if ((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING)
+     || (plci->State == INC_DIS_PENDING) || (plci->SuppState != IDLE))
+    {
+      Info = _WRONG_STATE;
+    }
+    else
+    {
+      /* local reply if assign unsuccessfull
+         or B3 protocol allows only one layer 3 connection
+           and already connected
+             or B2 protocol not any LAPD
+               and connect_b3_req contradicts originate/answer direction */
+      if (!plci->NL.Id
+       || (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
+        && ((plci->channels != 0)
+         || (((plci->B2_prot != B2_SDLC) && (plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL))
+          && ((plci->call_dir & CALL_DIR_ANSWER) && !(plci->call_dir & CALL_DIR_FORCE_OUTG_NL))))))
+      {
+        dbug(1,dprintf("B3 already connected=%d or no NL.Id=0x%x, dir=%d sstate=0x%x",
+                       plci->channels,plci->NL.Id,plci->call_dir,plci->SuppState));
+        Info = _WRONG_STATE;
+        sendf(appl,                                                        
+              _CONNECT_B3_R|CONFIRM,
+              Id,
+              Number,
+              "w",Info);
+        return FALSE;
+      }
+      plci->requested_options_conn = 0;
+
+      req = N_CONNECT;
+      ncpi = &parms[0];
+      if(plci->B3_prot==2 || plci->B3_prot==3)
+      {
+        if(ncpi->length>2)
+        {
+          /* check for PVC */
+          if(ncpi->info[2] || ncpi->info[3])
+          {
+            pvc[0] = ncpi->info[3];
+            pvc[1] = ncpi->info[2];
+            add_d(plci,2,pvc);
+            req = N_RESET;
+          }
+          else
+          {
+            if(ncpi->info[1] &1) req = N_CONNECT | N_D_BIT;
+            add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
+          }
+        }
+      }
+      else if(plci->B3_prot==5)
+      {
+        if (plci->NL.Id && !plci->nl_remove_id)
+        {
+          fax_control_bits = READ_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low);
+          fax_feature_bits = READ_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->feature_bits_low);
+          if (!(fax_control_bits & T30_CONTROL_BIT_MORE_DOCUMENTS)
+           || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS))
+          {
+            len = (byte)(&(((T30_INFO *) 0)->universal_6));
+            fax_info_change = FALSE;
+            if (ncpi->length >= 4)
+            {
+              w = READ_WORD(&ncpi->info[3]);
+              if ((w & 0x0001) != ((word)(((T30_INFO   *)(plci->fax_connect_info_buffer))->resolution & 0x0001)))
+              {
+                ((T30_INFO   *)(plci->fax_connect_info_buffer))->resolution =
+                  (byte)((((T30_INFO   *)(plci->fax_connect_info_buffer))->resolution & ~T30_RESOLUTION_R8_0770_OR_200) |
+                  ((w & 0x0001) ? T30_RESOLUTION_R8_0770_OR_200 : 0));
+                fax_info_change = TRUE;
+              }
+              fax_control_bits &= ~(T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
+              if (w & 0x0002)  /* Fax-polling request */
+                fax_control_bits |= T30_CONTROL_BIT_REQUEST_POLLING;
+              if ((w & 0x0004) /* Request to send / poll another document */
+               && (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS))
+              {
+                fax_control_bits |= T30_CONTROL_BIT_MORE_DOCUMENTS;
+              }
+              if (ncpi->length >= 6)
+              {
+                w = READ_WORD(&ncpi->info[5]);
+                if (((byte) w) != ((T30_INFO   *)(plci->fax_connect_info_buffer))->data_format)
+                {
+                  ((T30_INFO   *)(plci->fax_connect_info_buffer))->data_format = (byte) w;
+                  fax_info_change = TRUE;
+                }
+
+                if ((a->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+                 && (READ_WORD(&ncpi->info[5]) & 0x8000)) /* Private SEP/SUB/PWD enable */
+                {
+                  plci->requested_options_conn |= (1L << PRIVATE_FAX_SUB_SEP_PWD);
+                }
+                if ((a->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
+                 && (READ_WORD(&ncpi->info[5]) & 0x4000)) /* Private non-standard facilities enable */
+                {
+                  plci->requested_options_conn |= (1L << PRIVATE_FAX_NONSTANDARD);
+                }
+                fax_control_bits &= ~(T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_SEL_POLLING |
+                  T30_CONTROL_BIT_ACCEPT_PASSWORD);
+                if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
+                  & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+                {
+                  if (api_parse (&ncpi->info[1], ncpi->length, "wwwwsss", fax_parms))
+                    Info = _WRONG_MESSAGE_FORMAT;
+                  else
+                  {
+                    if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
+                      & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+      {
+                    fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
+                    if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
+                      fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
+      }
+                    w = fax_parms[4].length;
+                    if (w > 20)
+                      w = 20;
+                    ((T30_INFO   *)(plci->fax_connect_info_buffer))->station_id_len = (byte) w;
+                    for (i = 0; i < w; i++)
+                      ((T30_INFO   *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1+i];
+                    ((T30_INFO   *)(plci->fax_connect_info_buffer))->head_line_len = 0;
+                    len = (byte)(((T30_INFO *) 0)->station_id + 20);
+                    w = fax_parms[5].length;
+                    if (w > 20)
+                      w = 20;
+                    plci->fax_connect_info_buffer[len++] = (byte) w;
+                    for (i = 0; i < w; i++)
+                      plci->fax_connect_info_buffer[len++] = fax_parms[5].info[1+i];
+                    w = fax_parms[6].length;
+                    if (w > 20)
+                      w = 20;
+                    plci->fax_connect_info_buffer[len++] = (byte) w;
+                    for (i = 0; i < w; i++)
+                      plci->fax_connect_info_buffer[len++] = fax_parms[6].info[1+i];
+                    if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
+                      & (1L << PRIVATE_FAX_NONSTANDARD))
+      {
+                      if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
+        {
+                        dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+                        plci->fax_connect_info_buffer[len++] = 0;
+        }
+                      else
+                      {
+          if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
+            plci->nsf_control_bits = READ_WORD(&fax_parms[7].info[2]);
+   plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
+          for (i = 0; i < fax_parms[7].length; i++)
+     plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
+                      }
+                    }
+                  }
+                }
+                else
+                {
+                  len = (byte)(&(((T30_INFO *) 0)->universal_6));
+                }
+                fax_info_change = TRUE;
+
+              }
+              if (fax_control_bits != READ_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low))
+              {
+                WRITE_WORD (&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low, fax_control_bits);
+                fax_info_change = TRUE;
+              }
+            }
+            if (Info == GOOD)
+            {
+              plci->fax_connect_info_length = len;
+              if (fax_info_change)
+              {
+                if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
+                {
+                  start_internal_command (Id, plci, fax_connect_info_command);
+                  return FALSE;
+                }
+                else
+                {
+                  start_internal_command (Id, plci, fax_adjust_b23_command);
+                  return FALSE;
+                }
+              }
+            }
+          }
+          else  Info = _WRONG_STATE;
+        }
+        else  Info = _WRONG_STATE;
+      }
+
+      else if (plci->B3_prot == B3_RTP)
+      {
+        plci->internal_req_buffer[0] = ncpi->length + 1;
+        plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
+        for (w = 0; w < ncpi->length; w++)
+          plci->internal_req_buffer[2+w] = ncpi->info[1+w];
+        start_internal_command (Id, plci, rtp_connect_b3_req_command);
+        return FALSE;
+      }
+
+      if(!Info)
+      {
+        nl_req_ncci(plci,req,0);
+        return 1;
+      }
+    }
+  }
+  else Info = _WRONG_IDENTIFIER;
+
+  sendf(appl,
+        _CONNECT_B3_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return FALSE;
+}
+
+byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+  API_PARSE * ncpi;
+  byte req;
+
+  word w;
+
+
+    API_PARSE fax_parms[9];
+  word i;
+  byte len;
+
+
+  dbug(1,dprintf("connect_b3_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    if(a->ncci_state[ncci]==INC_CON_PENDING) {
+      if (READ_WORD (&parms[0].info[0]) != 0)
+      {
+        a->ncci_state[ncci] = OUTG_REJ_PENDING;
+        channel_request_xon (plci, a->ncci_ch[ncci]);
+        channel_xmit_xon (plci);
+        cleanup_ncci_data (plci, ncci);
+        nl_req_ncci(plci,N_DISC,(byte)ncci);
+        return 1;
+      }
+      a->ncci_state[ncci] = INC_ACT_PENDING;
+
+      req = N_CONNECT_ACK;
+      ncpi = &parms[1];
+      if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
+      {
+
+        if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
+          & (1L << PRIVATE_FAX_NONSTANDARD))
+ {
+   if (((plci->B3_prot == 4) || (plci->B3_prot == 5))
+    && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
+    && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
+   {
+            len = ((byte)(((T30_INFO *) 0)->station_id + 20));
+            if (plci->fax_connect_info_length < len)
+            {
+              ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
+              ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
+            }
+            if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
+            {
+              dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+            }
+            else
+            {
+              if (plci->fax_connect_info_length <= len)
+                plci->fax_connect_info_buffer[len] = 0;
+              len += 1 + plci->fax_connect_info_buffer[len];
+              if (plci->fax_connect_info_length <= len)
+                plci->fax_connect_info_buffer[len] = 0;
+              len += 1 + plci->fax_connect_info_buffer[len];
+              if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
+                plci->nsf_control_bits = READ_WORD(&fax_parms[7].info[2]);
+              plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
+              for (i = 0; i < fax_parms[7].length; i++)
+                plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
+            }
+            plci->fax_connect_info_length = len;
+            ((T30_INFO *)(plci->fax_connect_info_buffer))->code = 0;
+            start_internal_command (Id, plci, fax_connect_ack_command);
+     return FALSE;
+          }
+        }
+
+        nl_req_ncci(plci,req,(byte)ncci);
+        if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+         && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+        {
+          if (plci->B3_prot == 4)
+            sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+          else
+            sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+          plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+        }
+      }
+
+      else if (plci->B3_prot == B3_RTP)
+      {
+        plci->internal_req_buffer[0] = ncpi->length + 1;
+        plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
+        for (w = 0; w < ncpi->length; w++)
+          plci->internal_req_buffer[2+w] = ncpi->info[1+w];
+        start_internal_command (Id, plci, rtp_connect_b3_res_command);
+        return FALSE;
+      }
+
+      else
+      {
+        if(ncpi->length>2) {
+          if(ncpi->info[1] &1) req = N_CONNECT_ACK | N_D_BIT;
+          add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
+        }
+        nl_req_ncci(plci,req,(byte)ncci);
+        sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+        if (plci->adjust_b_restore)
+        {
+          plci->adjust_b_restore = FALSE;
+          start_internal_command (Id, plci, adjust_b_restore);
+        }
+      }
+      return 1;
+    }
+  }
+  return FALSE;
+}
+
+byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+
+  ncci = (word)(Id>>16);
+  dbug(1,dprintf("connect_b3_a_res(ncci=0x%x)",ncci));
+
+  if (plci && ncci && (plci->State != IDLE) && (plci->State != INC_DIS_PENDING)
+   && (plci->State != OUTG_DIS_PENDING))
+  {
+    if(a->ncci_state[ncci]==INC_ACT_PENDING) {
+      a->ncci_state[ncci] = CONNECTED;
+      if(plci->State!=INC_CON_CONNECTED_ALERT) plci->State = CONNECTED;
+      channel_request_xon (plci, a->ncci_ch[ncci]);
+      channel_xmit_xon (plci);
+    }
+  }
+  return FALSE;
+}
+
+byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info;
+  word ncci;
+  API_PARSE * ncpi;
+
+  dbug(1,dprintf("disconnect_b3_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ncci = (word)(Id>>16);
+  if (plci && ncci)
+  {
+    Info = _WRONG_STATE;
+    if ((a->ncci_state[ncci] == CONNECTED)
+     || (a->ncci_state[ncci] == OUTG_CON_PENDING)
+     || (a->ncci_state[ncci] == INC_CON_PENDING)
+     || (a->ncci_state[ncci] == INC_ACT_PENDING))
+    {
+      a->ncci_state[ncci] = OUTG_DIS_PENDING;
+      channel_request_xon (plci, a->ncci_ch[ncci]);
+      channel_xmit_xon (plci);
+
+      if (a->ncci[ncci].data_pending
+       && ((plci->B3_prot == B3_TRANSPARENT)
+        || (plci->B3_prot == B3_T30)
+        || (plci->B3_prot == B3_T30_WITH_EXTENSIONS)))
+      {
+        plci->send_disc = (byte)ncci;
+        plci->command = 0;
+        return FALSE;
+      }
+      else
+      {
+        cleanup_ncci_data (plci, ncci);
+
+        if(plci->B3_prot==2 || plci->B3_prot==3)
+        {
+          ncpi = &parms[0];
+          if(ncpi->length>3)
+          {
+            add_d(plci, (word)(ncpi->length - 3) ,(byte   *)&(ncpi->info[4]));
+          }
+        }
+        nl_req_ncci(plci,N_DISC,(byte)ncci);
+      }
+      return 1;
+    }
+  }
+  sendf(appl,
+        _DISCONNECT_B3_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return FALSE;
+}
+
+byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+  word i;
+
+  ncci = (word)(Id>>16);
+  dbug(1,dprintf("disconnect_b3_res(ncci=0x%x",ncci));
+  if(plci && ncci) {
+    plci->requested_options_conn = 0;
+    plci->fax_connect_info_length = 0;
+    plci->ncpi_state = 0x00;
+    if (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
+      && ((plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL)))
+    {
+      plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
+    }
+    for(i=0; i<MAX_CHANNELS_PER_PLCI && plci->inc_dis_ncci_table[i]!=(byte)ncci; i++);
+    if(i<MAX_CHANNELS_PER_PLCI) {
+      if(plci->channels)plci->channels--;
+      for(; i<MAX_CHANNELS_PER_PLCI-1; i++) plci->inc_dis_ncci_table[i] = plci->inc_dis_ncci_table[i+1];
+      plci->inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI-1] = 0;
+
+      ncci_free_receive_buffers (plci, ncci);
+
+      if((plci->State==IDLE || plci->State==SUSPENDING) && !plci->channels){
+        if(plci->State == SUSPENDING){
+          sendf(plci->appl,
+                _FACILITY_I,
+                Id & 0xffffL,
+                0,
+                "ws", (word)3, "\x03\x04\x00\x00");
+          sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
+        }
+        plci_remove(plci);
+        plci->State=IDLE;
+      }
+    }
+    else
+    {
+      if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+       && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
+       && (a->ncci_state[ncci] == INC_DIS_PENDING))
+      {
+        ncci_free_receive_buffers (plci, ncci);
+
+        nl_req_ncci(plci,N_EDATA,(byte)ncci);
+
+        plci->adapter->ncci_state[ncci] = IDLE;
+        start_internal_command (Id, plci, fax_disconnect_command);
+        return 1;
+      }
+    }
+  }
+  return FALSE;
+}
+
+byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  NCCI   *ncci_ptr;
+  DATA_B3_DESC   *data;
+  word Info;
+  word ncci;
+  word i;
+
+  dbug(1,dprintf("data_b3_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ncci = (word)(Id>>16);
+  dbug(1,dprintf("ncci=0x%x, plci=0x%x",ncci,plci));
+
+  if (plci && ncci)
+  {
+    Info = _WRONG_STATE;
+    if ((a->ncci_state[ncci] == CONNECTED)
+     || (a->ncci_state[ncci] == INC_ACT_PENDING))
+    {
+        /* queue data */
+      ncci_ptr = &(a->ncci[ncci]);
+      i = ncci_ptr->data_out + ncci_ptr->data_pending;
+      if (i >= MAX_DATA_B3)
+        i -= MAX_DATA_B3;
+      data = &(ncci_ptr->DBuffer[i]);
+      data->Number = Number;
+      if ((((byte   *)(parms[0].info)) >= ((byte   *)(plci->msg_in_queue)))
+       && (((byte   *)(parms[0].info)) < ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+      {
+
+        data->P = (byte   *)(*((dword   *)(parms[0].info)));
+
+      }
+      else
+        data->P = TransmitBufferSet(appl,*(dword *)parms[0].info);
+      data->Length = READ_WORD(parms[1].info);
+      data->Handle = READ_WORD(parms[2].info);
+      data->Flags = READ_WORD(parms[3].info);
+      (ncci_ptr->data_pending)++;
+
+        /* check for delivery confirmation */
+      if (data->Flags & 0x0004)
+      {
+        i = ncci_ptr->data_ack_out + ncci_ptr->data_ack_pending;
+        if (i >= MAX_DATA_ACK)
+          i -= MAX_DATA_ACK;
+        ncci_ptr->DataAck[i].Number = data->Number;
+        ncci_ptr->DataAck[i].Handle = data->Handle;
+        (ncci_ptr->data_ack_pending)++;
+      }
+
+      send_data(plci);
+      return FALSE;
+    }
+  }
+  if (appl)
+  {
+    if (plci)
+    {
+      if ((((byte   *)(parms[0].info)) >= ((byte   *)(plci->msg_in_queue)))
+       && (((byte   *)(parms[0].info)) < ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+      {
+
+        TransmitBufferFree (appl, (byte   *)(*((dword   *)(parms[0].info))));
+
+      }
+    }
+    sendf(appl,
+          _DATA_B3_R|CONFIRM,
+          Id,
+          Number,
+          "ww",READ_WORD(parms[2].info),Info);
+  }
+  return FALSE;
+}
+
+byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word n;
+  word ncci;
+  word NCCIcode;
+
+  dbug(1,dprintf("data_b3_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    n = READ_WORD(parms[0].info);
+    dbug(1,dprintf("free(%d)",n));
+    NCCIcode = ncci | (((word) a->Id) << 8);
+    if(n<appl->MaxBuffer &&
+       appl->DataNCCI[n]==NCCIcode &&
+       (byte)(appl->DataFlags[n]>>8)==plci->Id) {
+      dbug(1,dprintf("found"));
+      appl->DataNCCI[n] = 0;
+
+      if (channel_can_xon (plci, a->ncci_ch[ncci])) {
+        channel_request_xon (plci, a->ncci_ch[ncci]);
+      }
+      channel_xmit_xon (plci);
+
+      if(appl->DataFlags[n] &4) {
+        nl_req_ncci(plci,N_DATA_ACK,(byte)ncci);
+        return 1;
+      }
+    }
+  }
+  return FALSE;
+}
+
+byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info;
+  word ncci;
+
+  dbug(1,dprintf("reset_b3_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ncci = (word)(Id>>16);
+  if(plci && ncci)
+  {
+    Info = _WRONG_STATE;
+    switch (plci->B3_prot)
+    {
+    case B3_ISO8208:
+    case B3_X25_DCE:
+      if(a->ncci_state[ncci]==CONNECTED)
+      {
+        nl_req_ncci(plci,N_RESET,(byte)ncci);
+        send_req(plci);
+        Info = GOOD;
+      }
+      break;
+    case B3_TRANSPARENT:
+      if(a->ncci_state[ncci]==CONNECTED)
+      {
+        start_internal_command (Id, plci, reset_b3_command);
+        Info = GOOD;
+      }
+      break;
+    }
+  }
+  /* reset_b3 must result in a reset_b3_con & reset_b3_Ind */
+  sendf(appl,
+        _RESET_B3_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return FALSE;
+}
+
+byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+
+  dbug(1,dprintf("reset_b3_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    switch (plci->B3_prot)
+    {
+    case B3_ISO8208:
+    case B3_X25_DCE:
+      if(a->ncci_state[ncci]==INC_RES_PENDING)
+      {
+        a->ncci_state[ncci] = CONNECTED;
+        nl_req_ncci(plci,N_RESET_ACK,(byte)ncci);
+        return TRUE;
+      }
+    break;
+    }
+  }
+  return FALSE;
+}
+
+byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+  API_PARSE * ncpi;
+  byte req;
+
+  dbug(1,dprintf("connect_b3_t90_a_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    if(a->ncci_state[ncci]==INC_ACT_PENDING) {
+      a->ncci_state[ncci] = CONNECTED;
+    }
+    else if(a->ncci_state[ncci]==INC_CON_PENDING) {
+      a->ncci_state[ncci] = CONNECTED;
+
+      req = N_CONNECT_ACK;
+
+        /* parms[0]==0 for CAPI original message definition! */
+      if(parms[0].info) {
+        ncpi = &parms[1];
+        if(ncpi->length>2) {
+          if(ncpi->info[1] &1) req = N_CONNECT_ACK | N_D_BIT;
+          add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
+        }
+      }
+      nl_req_ncci(plci,req,(byte)ncci);
+      return 1;
+    }
+  }
+  return FALSE;
+}
+
+
+byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info=0;
+  word i;
+  byte tel;
+    API_PARSE bp_parms[7];
+
+  if(!plci || !msg)
+  {
+    Info = _WRONG_IDENTIFIER;
+  }
+  else
+  {
+    dbug(1,dprintf("select_b_req[%d],PLCI=0x%x,Tel=0x%x,NL=0x%x,appl=0x%x,sstate=0x%x",
+                   msg->length,plci->Id,plci->tel,plci->NL.Id,plci->appl,plci->SuppState));
+    dbug(1,dprintf("PlciState=0x%x",plci->State));
+    for(i=0;i<7;i++) bp_parms[i].length = 0;
+
+    /* check if no channel is open, no B3 connected only */
+    if((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING) || (plci->State == INC_DIS_PENDING)
+     || (plci->SuppState != IDLE) || plci->channels || plci->nl_remove_id)
+    {
+      Info = _WRONG_STATE;
+    }
+    /* check message format and fill bp_parms pointer */
+    else if(msg->length && api_parse(&msg->info[1], (word)msg->length, "wwwsss", bp_parms))
+    {
+      Info = _WRONG_MESSAGE_FORMAT;
+    }
+    else
+    {
+      if((plci->State==INC_CON_PENDING) || (plci->State==INC_CON_ALERT)) /* send alert tone inband to the network, */
+      {                                                                  /* e.g. Qsig or RBS or Cornet-N or xess PRI */
+        if(Id & EXT_CONTROLLER)
+        {
+          sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", 0x2002); /* wrong controller */
+          return 0;
+        }
+        plci->State=INC_CON_CONNECTED_ALERT;
+        plci->appl = appl;
+        clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+        dump_c_ind_mask (plci);
+        for(i=0; i<max_appl; i++) /* disconnect the other appls */
+        {                         /* its quasi a connect        */
+          if(test_c_ind_mask_bit (plci, i))
+            sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
+        }
+      }
+
+      api_save_msg(msg, "s", &plci->saved_msg);
+      tel = plci->tel;
+      if(Id & EXT_CONTROLLER)
+      {
+        if(tel) /* external controller in use by this PLCI */
+        {
+          if(a->AdvSignalAppl && a->AdvSignalAppl!=appl)
+          {
+            dbug(1,dprintf("Ext_Ctrl in use 1"));
+            Info = _WRONG_STATE;
+          }
+        }
+        else  /* external controller NOT in use by this PLCI ? */
+        {
+          if(a->AdvSignalPLCI)
+          {
+            dbug(1,dprintf("Ext_Ctrl in use 2"));
+            Info = _WRONG_STATE;
+          }
+          else /* activate the codec */
+          {
+            dbug(1,dprintf("Ext_Ctrl start"));
+            if(AdvCodecSupport(a, plci, appl, 0) )
+            {
+              dbug(1,dprintf("Error in codec procedures"));
+              Info = _WRONG_STATE;
+            }
+            else if(plci->spoofed_msg==SPOOFING_REQUIRED) /* wait until codec is active */
+            {
+              plci->spoofed_msg = AWAITING_SELECT_B;
+              plci->internal_command = BLOCK_PLCI; /* lock other commands */
+              plci->command = 0;
+              dbug(1,dprintf("continue if codec loaded"));
+              return FALSE;
+            }
+          }
+        }
+      }
+      else /* external controller bit is OFF */
+      {
+        if(tel) /* external controller in use, need to switch off */
+        {
+          if(a->AdvSignalAppl==appl)
+          {
+            CodecIdCheck(a, plci);
+            plci->tel = 0;
+            plci->adv_nl = 0;
+            dbug(1,dprintf("Ext_Ctrl disable"));
+          }
+          else
+          {
+            dbug(1,dprintf("Ext_Ctrl not requested"));
+          }
+        }
+      }
+      if (!Info)
+      {
+        if (plci->call_dir & CALL_DIR_OUT)
+          plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+        else if (plci->call_dir & CALL_DIR_IN)
+          plci->call_dir = CALL_DIR_IN | CALL_DIR_ANSWER;
+        start_internal_command (Id, plci, select_b_command);
+        return FALSE;
+      }
+    }
+  }
+  sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", Info);
+  return FALSE;
+}
+
+byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word command;
+  word i;
+  word ncci;
+  API_PARSE * m;
+    API_PARSE m_parms[5];
+  word codec;
+  byte req;
+  byte ch;
+  byte dir;
+  static byte chi[2] = {0x01,0x00};
+  static byte lli[2] = {0x01,0x00};
+  static byte codec_cai[2] = {0x01,0x01};
+  static byte null_msg = {0};
+  static API_PARSE null_parms = { 0, &null_msg };
+  PLCI   * v_plci;
+  word Info=0;
+
+  dbug(1,dprintf("manufacturer_req"));
+  for(i=0;i<5;i++) m_parms[i].length = 0;
+
+  if(READ_DWORD(parms[0].info)!=_DI_MANU_ID) {
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+  command = READ_WORD(parms[1].info);
+  m = &parms[2];
+  if (!Info)
+  {
+    switch(command) {
+    case _DI_ASSIGN_PLCI:
+      if(api_parse(&m->info[1],(word)m->length,"wbbs",m_parms)) {
+        Info = _WRONG_MESSAGE_FORMAT;
+        break;
+      }
+      codec = READ_WORD(m_parms[0].info);
+      ch = m_parms[1].info[0];
+      dir = m_parms[2].info[0];
+      if((i=get_plci(a))) {
+        plci = &a->plci[i-1];
+        plci->appl = appl;
+        plci->command = _MANUFACTURER_R;
+        plci->m_command = command;
+        plci->number = Number;
+        plci->State = LOCAL_CONNECT;
+        Id = ( ((word)plci->Id<<8)|plci->adapter->Id|0x80);
+        dbug(1,dprintf("ManCMD,plci=0x%x",Id));
+
+        if((ch==1 || ch==2) && (dir<=2)) {
+          chi[1] = (byte)(0x80|ch);
+          lli[1] = 0;
+          plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+          switch(codec)
+          {
+          case 0:
+            Info = add_b1(plci,&m_parms[3],0,0);
+            break;
+          case 1:
+            add_p(plci,CAI,codec_cai);
+            break;
+          /* manual 'swich on' to the codec support without signalling */
+          /* first 'assign plci' with this function, then use */
+          case 2:
+            if(AdvCodecSupport(a, plci, appl, 0) ) {
+              Info = _RESOURCE_ERROR;
+            }
+            else {
+              Info = add_b1(plci,&null_parms,0,B1_FACILITY_LOCAL);
+              lli[1] = 0x10; /* local call codec stream */
+            }
+            break;
+          }
+
+          plci->State = LOCAL_CONNECT;
+          plci->manufacturer = TRUE;
+          plci->command = _MANUFACTURER_R;
+          plci->m_command = command;
+          plci->number = Number;
+
+          if(!Info)
+          {
+            add_p(plci,LLI,lli);
+            add_p(plci,CHI,chi);
+            add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            sig_req(plci,ASSIGN,DSIG_ID);
+
+            if(!codec)
+            {
+              Info = add_b23(plci,&m_parms[3]);
+              if(!Info)
+              {
+                nl_req_ncci(plci,ASSIGN,0);
+                send_req(plci);
+              }
+            }
+            if(!Info)
+            {
+              dbug(1,dprintf("dir=0x%x,spoof=0x%x",dir,plci->spoofed_msg));
+              if (plci->spoofed_msg==SPOOFING_REQUIRED)
+              {
+                api_save_msg (m_parms, "wbbs", &plci->saved_msg);
+                plci->spoofed_msg = AWAITING_MANUF_CON;
+                plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
+                plci->command = 0;
+                send_req(plci);
+                return FALSE;
+              }
+              if(dir==1) {
+                sig_req(plci,CALL_REQ,0);
+              }
+              else if(!dir){
+                sig_req(plci,LISTEN_REQ,0);
+              }
+              send_req(plci);
+            }
+            else
+            {
+              sendf(appl,
+                    _MANUFACTURER_R|CONFIRM,
+                    Id,
+                    Number,
+                    "dww",_DI_MANU_ID,command,Info);
+              return 2;
+            }
+          }
+        }
+      }
+      else  Info = _OUT_OF_PLCI;
+      break;
+
+    case _DI_IDI_CTRL:
+      if(!plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(api_parse(&m->info[1],(word)m->length,"bs",m_parms)) {
+        Info = _WRONG_MESSAGE_FORMAT;
+        break;
+      }
+      req = m_parms[0].info[0];
+      plci->command = _MANUFACTURER_R;
+      plci->m_command = command;
+      plci->number = Number;
+      if(req==CALL_REQ)
+      {
+        plci->b_channel = getChannel(&m_parms[1]);
+        mixer_set_bchannel_id_esc (plci, plci->b_channel);
+        if(plci->spoofed_msg==SPOOFING_REQUIRED)
+        {
+          plci->spoofed_msg = CALL_REQ | AWAITING_MANUF_CON;
+          plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
+          plci->command = 0;
+          break;
+        }
+      }
+      else if(req==LAW_REQ)
+      {
+        plci->cr_enquiry = TRUE;
+      }
+      add_ss(plci,FTY,&m_parms[1]);
+      sig_req(plci,req,0);
+      send_req(plci);
+      if(req==HANGUP)
+      {      
+        if (plci->NL.Id && !plci->nl_remove_id)
+        {
+          if (plci->channels)
+          {
+            for (ncci = 1; ncci < MAX_NCCI+1; i++)
+            {
+              if ((a->ncci_plci[ncci] == plci->Id) && (a->ncci_state[ncci] == CONNECTED))
+              {
+                a->ncci_state[ncci] = OUTG_DIS_PENDING;
+                cleanup_ncci_data (plci, ncci);
+                nl_req_ncci(plci,N_DISC,(byte)ncci);
+              }
+            }
+          }
+          mixer_remove (plci);
+          nl_req_ncci(plci,REMOVE,0);
+          send_req(plci);
+        }  
+      }
+      break;
+
+    case _DI_SIG_CTRL:
+    /* signalling control for loop activation B-channel */
+      if(!plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(m->length){
+        plci->command = _MANUFACTURER_R;
+        plci->number = Number;
+        add_ss(plci,FTY,m);
+        sig_req(plci,SIG_CTRL,0);
+        send_req(plci);
+      }
+      else Info = _WRONG_MESSAGE_FORMAT;
+      break;
+
+    case _DI_RXT_CTRL:
+    /* activation control for receiver/transmitter B-channel */
+      if(!plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(m->length){
+        plci->command = _MANUFACTURER_R;
+        plci->number = Number;
+        add_ss(plci,FTY,m);
+        sig_req(plci,DSP_CTRL,0);
+        send_req(plci);
+      }
+      else Info = _WRONG_MESSAGE_FORMAT;
+      break;
+
+    case _DI_ADV_CODEC:
+    case _DI_DSP_CTRL:
+      /* TEL_CTRL commands to support non standard adjustments: */
+      /* Ring on/off, Handset micro volume, external micro vol. */
+      /* handset+external speaker volume, receiver+transm. gain,*/
+      /* handsfree on (hookinfo off), set mixer command         */
+
+      if(command == _DI_ADV_CODEC)
+      {
+        if(!a->AdvCodecPLCI) {
+          Info = _WRONG_STATE;
+          break;
+        }
+        v_plci = a->AdvCodecPLCI;
+      }
+      else
+      {
+        if (plci
+         && (m->length >= 3)
+         && (m->info[1] == 0x1c)
+         && (m->info[2] >= 1))
+        {
+          if (m->info[3] == DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS)
+          {
+            if ((plci->tel != ADV_VOICE) || (plci != a->AdvSignalPLCI))
+            {
+              Info = _WRONG_STATE;
+              break;
+            }
+            a->adv_voice_coef_length = m->info[2] - 1;
+            if (a->adv_voice_coef_length > m->length - 3)
+              a->adv_voice_coef_length = (byte)(m->length - 3);
+            if (a->adv_voice_coef_length > ADV_VOICE_COEF_BUFFER_SIZE)
+              a->adv_voice_coef_length = ADV_VOICE_COEF_BUFFER_SIZE;
+            for (i = 0; i < a->adv_voice_coef_length; i++)
+              a->adv_voice_coef_buffer[i] = m->info[4 + i];
+            if (plci->B1_facilities & B1_FACILITY_VOICE)
+              adv_voice_write_coefs (plci, ADV_VOICE_WRITE_UPDATE);
+            break;
+          }
+          else if (m->info[3] == DSP_CTRL_SET_DTMF_PARAMETERS)
+          {
+            if (!(a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_PARAMETERS))
+            {
+              Info = _FACILITY_NOT_SUPPORTED;
+              break;
+            }
+
+            plci->dtmf_parameter_length = m->info[2] - 1;
+            if (plci->dtmf_parameter_length > m->length - 3)
+              plci->dtmf_parameter_length = (byte)(m->length - 3);
+            if (plci->dtmf_parameter_length > DTMF_PARAMETER_BUFFER_SIZE)
+              plci->dtmf_parameter_length = DTMF_PARAMETER_BUFFER_SIZE;
+            for (i = 0; i < plci->dtmf_parameter_length; i++)
+              plci->dtmf_parameter_buffer[i] = m->info[4+i];
+            if (plci->B1_facilities & B1_FACILITY_DTMFR)
+              dtmf_parameter_write (plci);
+            break;
+
+          }
+        }
+        v_plci = plci;
+      }
+
+      if(!v_plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(m->length){
+        add_ss(v_plci,FTY,m);
+        sig_req(v_plci,TEL_CTRL,0);
+        send_req(v_plci);
+      }
+      else Info = _WRONG_MESSAGE_FORMAT;
+
+      break;
+
+    case _DI_OPTIONS_REQUEST:
+      if(api_parse(&m->info[1],(word)m->length,"d",m_parms)) {
+        Info = _WRONG_MESSAGE_FORMAT;
+        break;
+      }
+      if (READ_DWORD (m_parms[0].info) & ~a->man_profile.private_options)
+      {
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      a->requested_options_table[appl->Id-1] = READ_DWORD (m_parms[0].info);
+      break;
+
+
+
+    default:
+      Info = _WRONG_MESSAGE_FORMAT;
+      break;
+    }
+  }
+
+  sendf(appl,
+        _MANUFACTURER_R|CONFIRM,
+        Id,
+        Number,
+        "dww",_DI_MANU_ID,command,Info);
+  return FALSE;
+}
+
+
+byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word indication;
+
+    API_PARSE m_parms[3];
+  API_PARSE *ncpi;
+    API_PARSE fax_parms[9];
+  word i;
+  byte len;
+
+
+  dbug(1,dprintf("manufacturer_res"));
+
+  if ((msg[0].length == 0)
+   || (msg[1].length == 0)
+   || (READ_DWORD(msg[0].info)!=_DI_MANU_ID))
+  {
+    return FALSE;
+  }
+  indication = READ_WORD(msg[1].info);
+  switch (indication)
+  {
+
+  case _DI_NEGOTIATE_B3:
+    if(!plci)
+      break;
+    if (((plci->B3_prot != 4) && (plci->B3_prot != 5))
+     || !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
+    {
+      dbug(1,dprintf("wrong state for NEGOTIATE_B3 parameters"));
+      break;
+    }
+    if (api_parse (&msg[2].info[1], msg[2].length, "ws", m_parms))
+    {
+      dbug(1,dprintf("wrong format in NEGOTIATE_B3 parameters"));
+      break;
+    }
+    ncpi = &m_parms[1];
+    len = ((byte)(((T30_INFO *) 0)->station_id + 20));
+    if (plci->fax_connect_info_length < len)
+    {
+      ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
+      ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
+    }
+    if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
+    {
+      dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+    }
+    else
+    {
+      if (plci->fax_connect_info_length <= len)
+        plci->fax_connect_info_buffer[len] = 0;
+      len += 1 + plci->fax_connect_info_buffer[len];
+      if (plci->fax_connect_info_length <= len)
+        plci->fax_connect_info_buffer[len] = 0;
+      len += 1 + plci->fax_connect_info_buffer[len];
+      if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
+        plci->nsf_control_bits = READ_WORD(&fax_parms[7].info[2]);
+      plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
+      for (i = 0; i < fax_parms[7].length; i++)
+        plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
+    }
+    plci->fax_connect_info_length = len;
+    plci->fax_edata_ack_length = plci->fax_connect_info_length;
+    start_internal_command (Id, plci, fax_edata_ack_command);
+    break;
+
+  }
+  return FALSE;
+}
+
+/*------------------------------------------------------------------*/
+/* IDI callback function                                            */
+/*------------------------------------------------------------------*/
+
+void   callback(ENTITY   * e)
+{
+  DIVA_CAPI_ADAPTER   * a;
+  APPL   * appl;
+  PLCI   * plci;
+  CAPI_MSG   *m;
+  word i, j;
+  byte rc;
+  byte ch;
+  byte req;
+  byte global_req;
+  int no_cancel_rc;
+
+  dbug(1,dprintf("%x:CB(%x:Req=%x,Rc=%x,Ind=%x)",
+                 (e->user[0]+1)&0x7fff,e->Id,e->Req,e->Rc,e->Ind));
+
+  a = &(adapter[(byte)e->user[0]]);
+  plci = &(a->plci[e->user[1]]);
+  no_cancel_rc = DIVA_CAPI_SUPPORTS_NO_CANCEL(a);
+
+  /*
+     If new protocol code and new XDI is used then CAPI should work
+     fully in accordance with IDI cpec an look on callback field instead
+     of Rc field for return codes.
+   */
+  if (((e->complete == 0xff) && no_cancel_rc) ||
+      (e->Rc && !no_cancel_rc)) {
+    rc = e->Rc;
+    ch = e->RcCh;
+    req = e->Req;
+    e->Rc = 0;
+
+    if (e->user[0] & 0x8000)
+    {
+      /*
+         If REMOVE request was sent then we have to wait until
+         return code with Id set to zero arrives.
+         All other return codes should be ignored.
+         */
+      if (req == REMOVE)
+      {
+        if (e->Id)
+        {
+          dbug(1,dprintf("cancel RC in REMOVE state"));
+          return;
+        }
+        channel_flow_control_remove (plci);
+        for (i = 0; i < 256; i++)
+        {
+          if (a->FlowControlIdTable[i] == plci->nl_remove_id)
+            a->FlowControlIdTable[i] = 0;
+        }
+        plci->nl_remove_id = 0;
+        if (plci->rx_dma_descriptor > 0) {
+          diva_free_dma_descriptor (plci, plci->rx_dma_descriptor - 1);
+          plci->rx_dma_descriptor = 0;
+        }
+      }
+      if (rc == OK_FC)
+      {
+        a->FlowControlIdTable[ch] = e->Id;
+        a->FlowControlSkipTable[ch] = 0;
+
+        a->ch_flow_control[ch] |= N_OK_FC_PENDING;
+        a->ch_flow_plci[ch] = plci->Id;
+        plci->nl_req = 0;
+      }
+      else
+      {
+        /*
+          Cancel return codes self, if feature was requested
+          */
+        if (no_cancel_rc && (a->FlowControlIdTable[ch] == e->Id) && e->Id) {
+          a->FlowControlIdTable[ch] = 0;
+          if ((rc == OK) && a->FlowControlSkipTable[ch]) {
+            dbug(3,dprintf ("XDI CAPI: RC cancelled Id:0x02, Ch:%02x",                              e->Id, ch));
+            return;
+          }
+        }
+
+        if (a->ch_flow_control[ch] & N_OK_FC_PENDING)
+        {
+          a->ch_flow_control[ch] &= ~N_OK_FC_PENDING;
+          if (ch == e->ReqCh)
+            plci->nl_req = 0;
+        }
+        else
+          plci->nl_req = 0;
+      }
+      if (plci->nl_req)
+        control_rc (plci, 0, rc, ch, 0, TRUE);
+      else
+      {
+        if (req == N_XON)
+        {
+          channel_x_on (plci, ch);
+          if (plci->internal_command)
+            control_rc (plci, req, rc, ch, 0, TRUE);
+        }
+        else
+        {
+          if (plci->nl_global_req)
+          {
+            global_req = plci->nl_global_req;
+            plci->nl_global_req = 0;
+            if (rc != ASSIGN_OK) {
+              e->Id = 0;
+              if (plci->rx_dma_descriptor > 0) {
+                diva_free_dma_descriptor (plci, plci->rx_dma_descriptor - 1);
+                plci->rx_dma_descriptor = 0;
+              }
+            }
+            channel_xmit_xon (plci);
+            control_rc (plci, 0, rc, ch, global_req, TRUE);
+          }
+          else if (plci->data_sent)
+          {
+            channel_xmit_xon (plci);
+            plci->data_sent = FALSE;
+            plci->NL.XNum = 1;
+            data_rc (plci, ch);
+            if (plci->internal_command)
+              control_rc (plci, req, rc, ch, 0, TRUE);
+          }
+          else
+          {
+            channel_xmit_xon (plci);
+            control_rc (plci, req, rc, ch, 0, TRUE);
+          }
+        }
+      }
+    }
+    else
+    {
+      /*
+         If REMOVE request was sent then we have to wait until
+         return code with Id set to zero arrives.
+         All other return codes should be ignored.
+         */
+      if (req == REMOVE)
+      {
+        if (e->Id)
+        {
+          dbug(1,dprintf("cancel RC in REMOVE state"));
+          return;
+        }
+        plci->sig_remove_id = 0;
+      }
+      plci->sig_req = 0;
+      if (plci->sig_global_req)
+      {
+        global_req = plci->sig_global_req;
+        plci->sig_global_req = 0;
+        if (rc != ASSIGN_OK)
+          e->Id = 0;
+        channel_xmit_xon (plci);
+        control_rc (plci, 0, rc, ch, global_req, FALSE);
+      }
+      else
+      {
+        channel_xmit_xon (plci);
+        control_rc (plci, req, rc, ch, 0, FALSE);
+      }
+    }
+    /*
+      Again: in accordance with IDI spec Rc and Ind can't be delivered in the
+      same callback. Also if new XDI and protocol code used then jump
+      direct to finish.
+      */
+    if (no_cancel_rc) {
+      channel_xmit_xon(plci);
+      goto capi_callback_suffix;
+    }
+  }
+
+  channel_xmit_xon(plci);
+
+  if (e->Ind) {
+    if (e->user[0] &0x8000) {
+      byte Ind = e->Ind & 0x0f;
+      byte Ch = e->IndCh;
+      if (((Ind==N_DISC) || (Ind==N_DISC_ACK)) &&
+          (a->ch_flow_plci[Ch] == plci->Id)) {
+        if (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK) {
+          dbug(3,dprintf ("XDI CAPI: I: pending N-XON Ch:%02x", Ch));
+        }
+        a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
+      }
+      nl_ind(plci);
+      if ((e->RNR != 1) &&
+          (a->ch_flow_plci[Ch] == plci->Id) &&
+          (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK)) {
+        a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
+        dbug(3,dprintf ("XDI CAPI: I: remove faked N-XON Ch:%02x", Ch));
+      }
+    } else {
+      sig_ind(plci);
+    }
+    e->Ind = 0;
+  }
+
+capi_callback_suffix:
+
+  while (!plci->req_in
+   && !plci->internal_command
+   && (plci->msg_in_write_pos != plci->msg_in_read_pos))
+  {
+    j = (plci->msg_in_read_pos == plci->msg_in_wrap_pos) ? 0 : plci->msg_in_read_pos;
+
+    i = (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[j]))->header.length + 3) & 0xfffc;
+
+    m = (CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[j]);
+    appl = *((APPL   *   *)(&((byte   *)(plci->msg_in_queue))[j+i]));
+    dbug(1,dprintf("dequeue msg(0x%04x) - write=%d read=%d wrap=%d",
+      m->header.command, plci->msg_in_write_pos, plci->msg_in_read_pos, plci->msg_in_wrap_pos));
+    if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
+    {
+      plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+      plci->msg_in_read_pos = i + MSG_IN_OVERHEAD;
+    }
+    else
+    {
+      plci->msg_in_read_pos = j + i + MSG_IN_OVERHEAD;
+    }
+    if (plci->msg_in_read_pos == plci->msg_in_write_pos)
+    {
+      plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
+      plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+    }
+    else if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
+    {
+      plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+      plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+    }
+    i = api_put (appl, m);
+    if (i != 0)
+    {
+      if (m->header.command == _DATA_B3_R)
+
+        TransmitBufferFree (appl, (byte   *)(m->info.data_b3_req.Data));
+
+      dbug(1,dprintf("Error 0x%04x from msg(0x%04x)", i, m->header.command));
+      break;
+    }
+
+    if (plci->li_notify_update)
+    {
+      plci->li_notify_update = FALSE;
+      mixer_notify_update (plci, FALSE);
+    }
+
+  }
+  send_data(plci);
+  send_req(plci);
+}
+
+
+void control_rc(PLCI   * plci, byte req, byte rc, byte ch, byte global_req, byte nl_rc)
+{
+  dword Id;
+  dword rId;
+  word Number;
+  word Info=0;
+  word i;
+  word ncci;
+  DIVA_CAPI_ADAPTER   * a;
+  APPL   * appl;
+  PLCI   * rplci;
+    byte SSparms[]  = "\x05\x00\x00\x02\x00\x00";
+    byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
+
+  if (!plci) {
+    dbug(0,dprintf("A: control_rc, no plci %02x:%02x:%02x:%02x:%02x", req, rc, ch, global_req, nl_rc));
+    return;
+  }
+  dbug(1,dprintf("req0_in/out=%d/%d",plci->req_in,plci->req_out));
+  if(plci->req_in!=plci->req_out)
+  {
+    if (nl_rc || (global_req != ASSIGN) || (rc == ASSIGN_OK))
+    {
+      dbug(1,dprintf("req_1return"));
+      return;
+    }
+    /* cancel outstanding request on the PLCI after SIG ASSIGN failure */
+  }
+  plci->req_in = plci->req_in_start = plci->req_out = 0;
+  dbug(1,dprintf("control_rc"));
+
+  appl = plci->appl;
+  a = plci->adapter;
+  ncci = a->ch_ncci[ch];
+  if(appl)
+  {
+    Id = (((dword)(ncci ? ncci : ch)) << 16) | ((word)plci->Id << 8) | a->Id;
+    if(plci->tel && plci->SuppState!=CALL_HELD) Id|=EXT_CONTROLLER;
+    Number = plci->number;
+    dbug(1,dprintf("Contr_RC-Id=%08lx,plci=%x,tel=%x, entity=0x%x, command=0x%x, int_command=0x%x",Id,plci->Id,plci->tel,plci->Sig.Id,plci->command,plci->internal_command));
+    dbug(1,dprintf("channels=0x%x",plci->channels));
+    if (plci_remove_check(plci))
+      return;
+    if(req==REMOVE && rc==ASSIGN_OK)
+    {
+      sig_req(plci,HANGUP,0);
+      sig_req(plci,REMOVE,0);
+      send_req(plci);
+    }
+    if(plci->command)
+    {
+      switch(plci->command)
+      {
+      case C_HOLD_REQ:
+        dbug(1,dprintf("HoldRC=0x%x",rc));
+        SSparms[1] = (byte)S_HOLD;
+        if(rc!=OK)
+        {
+          plci->SuppState = IDLE;
+          Info = 0x2001;
+        }
+        sendf(appl,_FACILITY_R|CONFIRM,Id,Number,"wws",Info,3,SSparms);
+        break;
+
+      case C_RETRIEVE_REQ:
+        dbug(1,dprintf("RetrieveRC=0x%x",rc));
+        SSparms[1] = (byte)S_RETRIEVE;
+        if(rc!=OK)
+        {
+          plci->SuppState = CALL_HELD;
+          Info = 0x2001;
+        }
+        sendf(appl,_FACILITY_R|CONFIRM,Id,Number,"wws",Info,3,SSparms);
+        break;
+
+      case _INFO_R:
+        dbug(1,dprintf("InfoRC=0x%x",rc));
+        if(rc!=OK) Info=_WRONG_STATE;
+        sendf(appl,_INFO_R|CONFIRM,Id,Number,"w",Info);
+        break;
+
+      case _CONNECT_R:
+        dbug(1,dprintf("Connect_R=0x%x/0x%x/0x%x/0x%x",req,rc,global_req,nl_rc));
+        if (plci->State == INC_DIS_PENDING)
+          break;
+        if(plci->Sig.Id!=0xff)
+        {
+          if (((global_req == ASSIGN) && (rc != ASSIGN_OK))
+           || (!nl_rc && (req == CALL_REQ) && (rc != OK)))
+          {
+            dbug(1,dprintf("No more IDs/Call_Req failed"));
+            sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
+            plci_remove(plci);
+            plci->State = IDLE;
+            break;
+          }
+          if(plci->State!=LOCAL_CONNECT)plci->State = OUTG_CON_PENDING;
+          sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
+        }
+        else /* D-ch activation */
+        {
+          if (rc != ASSIGN_OK)
+          {
+            dbug(1,dprintf("No more IDs/X.25 Call_Req failed"));
+            sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
+            plci_remove(plci);
+            plci->State = IDLE;
+            break;
+          }
+          sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
+          sendf(plci->appl,_CONNECT_ACTIVE_I,Id,0,"sss","","","");
+          plci->State = INC_ACT_PENDING;
+        }
+        break;
+
+      case _CONNECT_I|RESPONSE:
+        if (plci->State != INC_DIS_PENDING)
+          plci->State = INC_CON_ACCEPT;
+        break;
+
+      case _DISCONNECT_R:
+        if (plci->State == INC_DIS_PENDING)
+          break;
+        if(plci->Sig.Id!=0xff)
+        {
+          plci->State = OUTG_DIS_PENDING;
+          sendf(appl,_DISCONNECT_R|CONFIRM,Id,Number,"w",0);
+        }
+        break;
+
+      case SUSPEND_REQ:
+        break;
+
+      case RESUME_REQ:
+        break;
+
+      case _CONNECT_B3_R:
+        if(rc!=OK)
+        {
+          sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",_WRONG_IDENTIFIER);
+          break;
+        }
+        ncci = get_ncci (plci, ch, 0);
+        Id = (Id & 0xffff) | (((dword) ncci) << 16);
+        plci->channels++;
+        if(req==N_RESET)
+        {
+          a->ncci_state[ncci] = INC_ACT_PENDING;
+          sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",0);
+          sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+        }
+        else
+        {
+          a->ncci_state[ncci] = OUTG_CON_PENDING;
+          sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",0);
+        }
+        break;
+
+      case _CONNECT_B3_I|RESPONSE:
+        break;
+
+      case _RESET_B3_R:
+/*        sendf(appl,_RESET_B3_R|CONFIRM,Id,Number,"w",0);*/
+        break;
+
+      case _DISCONNECT_B3_R:
+        sendf(appl,_DISCONNECT_B3_R|CONFIRM,Id,Number,"w",0);
+        break;
+
+      case _MANUFACTURER_R:
+        break;
+
+      case PERM_LIST_REQ:
+        if(rc!=OK)
+        {
+          Info = _WRONG_IDENTIFIER;
+          sendf(plci->appl,_CONNECT_R|CONFIRM,Id,Number,"w",Info);
+          plci_remove(plci);
+        }
+        else
+          sendf(plci->appl,_CONNECT_R|CONFIRM,Id,Number,"w",Info);
+        break;
+
+      default:
+        break;
+      }
+      plci->command = 0;
+    }
+    else if (plci->internal_command)
+    {
+      switch(plci->internal_command)
+      {
+      case BLOCK_PLCI:
+        return;
+
+      case GET_MWI_STATE:
+        if(rc==OK) /* command supported, wait for indication */
+        {
+          return;
+        }
+        plci_remove(plci);
+        break;
+
+        /* Get Supported Services */
+      case GETSERV_REQ_PEND:
+        if(rc==OK) /* command supported, wait for indication */
+        {
+          break;
+        }
+        WRITE_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
+        sendf(appl, _FACILITY_R|CONFIRM, Id, Number, "wws",0,3,SSstruct);
+        plci_remove(plci);
+        break;
+
+      case INTERR_DIVERSION_REQ_PEND:      /* Interrogate Parameters        */
+      case INTERR_NUMBERS_REQ_PEND:
+      case CF_START_PEND:                  /* Call Forwarding Start pending */
+      case CF_STOP_PEND:                   /* Call Forwarding Stop pending  */
+      case CCBS_REQUEST_REQ_PEND:
+      case CCBS_DEACTIVATE_REQ_PEND:
+      case CCBS_INTERROGATE_REQ_PEND:
+        switch(plci->internal_command)
+        {
+          case INTERR_DIVERSION_REQ_PEND:
+            SSparms[1] = S_INTERROGATE_DIVERSION;
+            break;
+          case INTERR_NUMBERS_REQ_PEND:
+            SSparms[1] = S_INTERROGATE_NUMBERS;
+            break;
+          case CF_START_PEND:
+            SSparms[1] = S_CALL_FORWARDING_START;
+            break;
+          case CF_STOP_PEND:
+            SSparms[1] = S_CALL_FORWARDING_STOP;
+            break;
+          case CCBS_REQUEST_REQ_PEND:
+            SSparms[1] = S_CCBS_REQUEST;
+            break;
+          case CCBS_DEACTIVATE_REQ_PEND:
+            SSparms[1] = S_CCBS_DEACTIVATE;
+            break;
+          case CCBS_INTERROGATE_REQ_PEND:
+            SSparms[1] = S_CCBS_INTERROGATE;
+            break;
+        }
+        if(global_req==ASSIGN)
+        {
+          dbug(1,dprintf("AssignDiversion_RC=0x%x/0x%x",req,rc));
+          return;
+        }
+        if(!plci->appl) break;
+        if(rc==ISDN_GUARD_REJ)
+        {
+          Info = _CAPI_GUARD_ERROR;
+        }
+        else if(rc!=OK)
+        {
+          Info = _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED;
+        }
+        sendf(plci->appl,_FACILITY_R|CONFIRM,Id&0x7,
+              plci->number,"wws",Info,(word)3,SSparms);
+        if(Info) plci_remove(plci);
+        break;
+
+        /* 3pty conference pending */
+      case PTY_REQ_PEND:
+        if(!plci->relatedPTYPLCI) break;
+        rplci = plci->relatedPTYPLCI;
+        SSparms[1] = plci->ptyState;
+        rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
+        if(rplci->tel) rId|=EXT_CONTROLLER;
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->relatedPTYPLCI = 0;
+          plci->ptyState = 0;
+        }
+        sendf(rplci->appl,
+              _FACILITY_R|CONFIRM,
+              rId,
+              plci->number,
+              "wws",Info,(word)3,SSparms);
+        break;
+
+        /* Explicit Call Transfer pending */
+      case ECT_REQ_PEND:
+        dbug(1,dprintf("ECT_RC=0x%x/0x%x",req,rc));
+        if(!plci->relatedPTYPLCI) break;
+        rplci = plci->relatedPTYPLCI;
+        SSparms[1] = S_ECT;
+        rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
+        if(rplci->tel) rId|=EXT_CONTROLLER;
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->relatedPTYPLCI = 0;
+          plci->ptyState = 0;
+        }
+        sendf(rplci->appl,
+              _FACILITY_R|CONFIRM,
+              rId,
+              plci->number,
+              "wws",Info,(word)3,SSparms);
+        break;
+
+      case _MANUFACTURER_R:
+        dbug(1,dprintf("_Manufacturer_R=0x%x/0x%x",req,rc));
+        if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
+        {
+          dbug(1,dprintf("No more IDs"));
+          sendf(appl,_MANUFACTURER_R|CONFIRM,Id,Number,"dww",_DI_MANU_ID,_MANUFACTURER_R,_OUT_OF_PLCI);
+          plci_remove(plci);  /* after codec init, internal codec commands pending */
+        }
+        break;
+
+      case _CONNECT_R:
+        dbug(1,dprintf("_Connect_R=0x%x/0x%x",req,rc));
+        if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
+        {
+          dbug(1,dprintf("No more IDs"));
+          sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
+          plci_remove(plci);  /* after codec init, internal codec commands pending */
+        }
+        break;
+
+      case PERM_COD_HOOK:                     /* finished with Hook_Ind */
+        return;
+
+      case PERM_COD_CALL:
+        dbug(1,dprintf("***Codec Connect_Pending A, Rc = 0x%x",rc));
+        plci->internal_command = PERM_COD_CONN_PEND;
+        return;
+
+      case PERM_COD_ASSIGN:
+        dbug(1,dprintf("***Codec Assign A, Rc = 0x%x",rc));
+        if(rc!=ASSIGN_OK) break;
+        sig_req(plci,CALL_REQ,0);
+        send_req(plci);
+        plci->internal_command = PERM_COD_CALL;
+        return;
+
+        /* Null Call Reference Request pending */
+      case C_NCR_FAC_REQ:
+        dbug(1,dprintf("NCR_FAC=0x%x/0x%x",req,rc));
+        if(global_req==ASSIGN)
+        {
+          if(rc==ASSIGN_OK)
+          {
+            return;
+          }
+          else
+          {
+            sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
+            appl->NullCREnable = FALSE;
+            plci_remove(plci);
+          }
+        }
+        else if(req==NCR_FACILITY)
+        {
+          if(rc==OK)
+          {
+            sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",0);
+          }
+          else
+          {
+            sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
+            appl->NullCREnable = FALSE;
+          }
+          plci_remove(plci);
+        }
+        break;
+
+      case HOOK_ON_REQ:
+        if(plci->channels)
+        {
+          if(a->ncci_state[ncci]==CONNECTED)
+          {
+            a->ncci_state[ncci] = OUTG_DIS_PENDING;
+            cleanup_ncci_data (plci, ncci);
+            nl_req_ncci(plci,N_DISC,(byte)ncci);
+          }
+          break;
+        }
+        break;
+
+      case HOOK_OFF_REQ:
+        if (plci->State == INC_DIS_PENDING)
+          break;
+        sig_req(plci,CALL_REQ,0);
+        send_req(plci);
+        plci->State=OUTG_CON_PENDING;
+        break;
+
+
+      case MWI_ACTIVATE_REQ_PEND:
+      case MWI_DEACTIVATE_REQ_PEND:
+        if(global_req == ASSIGN && rc==ASSIGN_OK)
+        {
+          dbug(1,dprintf("MWI_REQ assigned"));
+          return;
+        }
+        else if(rc!=OK)
+        {                 
+          if(rc==WRONG_IE)
+          {
+            Info = 0x2007; /* Illegal message parameter coding */
+            dbug(1,dprintf("MWI_REQ illegal parameter"));
+          }
+          else
+          {
+            Info = 0x300B; /* not supported */                      
+            dbug(1,dprintf("MWI_REQ not supported"));
+          }
+          /* 0x3010: Request not allowed in this state */
+          WRITE_WORD(&SSparms[4],0x300E); /* SS not supported */
+                    
+        }
+        if(plci->internal_command==MWI_ACTIVATE_REQ_PEND)
+        {
+          WRITE_WORD(&SSparms[1],S_MWI_ACTIVATE);
+        }
+        else WRITE_WORD(&SSparms[1],S_MWI_DEACTIVATE);
+
+        if(plci->cr_enquiry)
+        {
+          sendf(plci->appl,
+                _FACILITY_R|CONFIRM,
+                Id&0xf,
+                plci->number,
+                "wws",Info,(word)3,SSparms);
+          if(rc!=OK) plci_remove(plci);
+        }
+        else
+        {
+          sendf(plci->appl,
+                _FACILITY_R|CONFIRM,
+                Id,
+                plci->number,
+                "wws",Info,(word)3,SSparms);
+        }
+        break;
+
+      case CONF_BEGIN_REQ_PEND:
+      case CONF_ADD_REQ_PEND:
+      case CONF_SPLIT_REQ_PEND:
+      case CONF_DROP_REQ_PEND:
+      case CONF_ISOLATE_REQ_PEND:
+      case CONF_REATTACH_REQ_PEND:
+        dbug(1,dprintf("CONF_RC=0x%x/0x%x",req,rc));
+        if((plci->internal_command==CONF_ADD_REQ_PEND)&&(!plci->relatedPTYPLCI)) break;
+        rplci = plci;
+        rId = Id;
+        switch(plci->internal_command)
+        {
+          case CONF_BEGIN_REQ_PEND:
+            SSparms[1] = S_CONF_BEGIN;
+            break;
+          case CONF_ADD_REQ_PEND:
+            SSparms[1] = S_CONF_ADD;
+            rplci = plci->relatedPTYPLCI;
+            rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
+            break;
+          case CONF_SPLIT_REQ_PEND:
+            SSparms[1] = S_CONF_SPLIT;
+            break;
+          case CONF_DROP_REQ_PEND:
+            SSparms[1] = S_CONF_DROP;
+            break;
+          case CONF_ISOLATE_REQ_PEND:
+            SSparms[1] = S_CONF_ISOLATE;
+            break;
+          case CONF_REATTACH_REQ_PEND:
+            SSparms[1] = S_CONF_REATTACH;
+            break;
+        }
+        
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->relatedPTYPLCI = 0;
+          plci->ptyState = 0;
+        }
+        sendf(rplci->appl,
+              _FACILITY_R|CONFIRM,
+              rId,
+              plci->number,
+              "wws",Info,(word)3,SSparms);
+        break;
+
+      case VSWITCH_REQ_PEND:
+        if(rc!=OK)
+        {
+          if(plci->relatedPTYPLCI)
+          {
+            plci->relatedPTYPLCI->vswitchstate=0;
+            plci->relatedPTYPLCI->vsprot=0;
+            plci->relatedPTYPLCI->vsprotdialect=0;    
+          }
+          plci->vswitchstate=0;
+          plci->vsprot=0;
+          plci->vsprotdialect=0;
+        }
+        else
+        {
+          if(plci->relatedPTYPLCI &&
+             plci->vswitchstate==1 &&
+             plci->relatedPTYPLCI->vswitchstate==3) /* join complete */
+            plci->vswitchstate=3;
+        }
+        break;
+
+  /* Call Deflection Request pending (SSCT) */
+      case CD_REQ_PEND:
+        SSparms[1] = S_CALL_DEFLECTION;
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->appl->CDEnable = 0;
+        }  
+        sendf(plci->appl,_FACILITY_R|CONFIRM,Id,
+          plci->number,"wws",Info,(word)3,SSparms);
+        break;
+
+      case RTP_CONNECT_B3_REQ_COMMAND_2:
+        if (rc == OK)
+        {
+          ncci = get_ncci (plci, ch, 0);
+          Id = (Id & 0xffff) | (((dword) ncci) << 16);
+          plci->channels++;
+          a->ncci_state[ncci] = OUTG_CON_PENDING;
+        }
+
+      default:
+        if (plci->internal_command_queue[0])
+        {
+          (*(plci->internal_command_queue[0]))(Id, plci, rc);
+          if (plci->internal_command)
+            return;
+        }
+        break;
+      }
+      next_internal_command (Id, plci);
+    }
+  }
+  else /* appl==0 */
+  {
+    Id = ((word)plci->Id<<8)|plci->adapter->Id;
+    if(plci->tel) Id|=EXT_CONTROLLER;
+
+    switch(plci->internal_command)
+    {
+    case BLOCK_PLCI:
+      return;
+
+    case START_L1_SIG_ASSIGN_PEND:
+    case REM_L1_SIG_ASSIGN_PEND:
+      if(global_req == ASSIGN)
+      {
+        break;
+      }
+      else
+      {
+        dbug(1,dprintf("***L1 Req rem PLCI"));
+        plci->internal_command = 0;
+        sig_req(plci,REMOVE,0);
+        send_req(plci);
+      }
+      break;
+
+      /* Call Deflection Request pending, just no appl ptr assigned */
+    case CD_REQ_PEND:
+      SSparms[1] = S_CALL_DEFLECTION;
+      if(rc!=OK)
+      {
+        Info = 0x300E; /* not supported */
+      }
+      for(i=0; i<max_appl; i++)
+      {
+        if(application[i].CDEnable)
+        {
+          if(!application[i].Id) application[i].CDEnable = 0;
+          else
+          {
+            sendf(&application[i],_FACILITY_R|CONFIRM,Id,
+                  plci->number,"wws",Info,(word)3,SSparms);
+            if(Info) application[i].CDEnable = 0;
+          }
+        }
+      }
+      plci->internal_command = 0;
+      break;
+
+    case PERM_COD_HOOK:                   /* finished with Hook_Ind */
+      return;
+
+    case PERM_COD_CALL:
+      plci->internal_command = PERM_COD_CONN_PEND;
+      dbug(1,dprintf("***Codec Connect_Pending, Rc = 0x%x",rc));
+      return;
+
+    case PERM_COD_ASSIGN:
+      dbug(1,dprintf("***Codec Assign, Rc = 0x%x",rc));
+      plci->internal_command = 0;
+      if(rc!=ASSIGN_OK) break;
+      plci->internal_command = PERM_COD_CALL;
+      sig_req(plci,CALL_REQ,0);
+      send_req(plci);
+      return;
+
+    case LISTEN_SIG_ASSIGN_PEND:
+      if(rc == ASSIGN_OK)
+      {
+        plci->internal_command = 0;
+        dbug(1,dprintf("ListenCheck, new SIG_ID = 0x%x",plci->Sig.Id));
+        add_p(plci,ESC,"\x02\x18\x00");             /* support call waiting */
+        sig_req(plci,INDICATE_REQ,0);
+        send_req(plci);
+      }
+      else
+      {
+        dbug(1,dprintf("ListenCheck failed (assignRc=0x%x)",rc));
+        a->listen_active--;
+        plci_remove(plci);
+        plci->State = IDLE;
+      }
+      break;
+
+    case USELAW_REQ:
+      if(global_req == ASSIGN)
+      {
+        if (rc==ASSIGN_OK)
+      {
+        sig_req(plci,LAW_REQ,0);
+        send_req(plci);
+        dbug(1,dprintf("Auto-Law assigned"));
+        }
+        else
+        {
+          dbug(1,dprintf("Auto-Law assign failed"));
+          a->automatic_law = 3;
+          plci->internal_command = 0;
+          a->automatic_lawPLCI = 0;
+        }
+        break;
+      }
+      else if(req == LAW_REQ && rc==OK)
+      {
+        dbug(1,dprintf("Auto-Law initiated"));
+        a->automatic_law = 2;
+        plci->internal_command = 0;
+      }
+      else
+      {
+        dbug(1,dprintf("Auto-Law not supported"));
+        a->automatic_law = 3;
+        plci->internal_command = 0;
+        sig_req(plci,REMOVE,0);
+        send_req(plci);
+        a->automatic_lawPLCI = 0;
+      }
+      break;
+    }
+    plci_remove_check(plci);
+  }
+}
+
+void data_rc(PLCI   * plci, byte ch)
+{
+  dword Id;
+  DIVA_CAPI_ADAPTER   * a;
+  NCCI   *ncci_ptr;
+  DATA_B3_DESC   *data;
+  word ncci;
+
+  if (plci->appl)
+  {
+    TransmitBufferFree (plci->appl, plci->data_sent_ptr);
+    a = plci->adapter;
+    ncci = a->ch_ncci[ch];
+    if (ncci && (a->ncci_plci[ncci] == plci->Id))
+    {
+      ncci_ptr = &(a->ncci[ncci]);
+      dbug(1,dprintf("data_out=%d, data_pending=%d",ncci_ptr->data_out,ncci_ptr->data_pending));
+      if (ncci_ptr->data_pending)
+      {
+        data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
+        if (!(data->Flags &4) && a->ncci_state[ncci])
+        {
+          Id = (((dword)ncci)<<16)|((word)plci->Id<<8)|a->Id;
+          if(plci->tel) Id|=EXT_CONTROLLER;
+          sendf(plci->appl,_DATA_B3_R|CONFIRM,Id,data->Number,
+                "ww",data->Handle,0);
+        }
+        (ncci_ptr->data_out)++;
+        if (ncci_ptr->data_out == MAX_DATA_B3)
+          ncci_ptr->data_out = 0;
+        (ncci_ptr->data_pending)--;
+      }
+    }
+  }
+}
+
+void data_ack(PLCI   * plci, byte ch)
+{
+  dword Id;
+  DIVA_CAPI_ADAPTER   * a;
+  NCCI   *ncci_ptr;
+  word ncci;
+
+  a = plci->adapter;
+  ncci = a->ch_ncci[ch];
+  ncci_ptr = &(a->ncci[ncci]);
+  if (ncci_ptr->data_ack_pending)
+  {
+    if (a->ncci_state[ncci] && (a->ncci_plci[ncci] == plci->Id))
+    {
+      Id = (((dword)ncci)<<16)|((word)plci->Id<<8)|a->Id;
+      if(plci->tel) Id|=EXT_CONTROLLER;
+      sendf(plci->appl,_DATA_B3_R|CONFIRM,Id,ncci_ptr->DataAck[ncci_ptr->data_ack_out].Number,
+            "ww",ncci_ptr->DataAck[ncci_ptr->data_ack_out].Handle,0);
+    }
+    (ncci_ptr->data_ack_out)++;
+    if (ncci_ptr->data_ack_out == MAX_DATA_ACK)
+      ncci_ptr->data_ack_out = 0;
+    (ncci_ptr->data_ack_pending)--;
+  }
+}
+
+void sig_ind(PLCI   * plci)
+{
+  dword x_Id;
+  dword Id;
+  dword rId;
+  word Number = 0;
+  word i;
+  word cip;
+  dword cip_mask;
+  byte   *ie;
+  DIVA_CAPI_ADAPTER   * a;
+    API_PARSE saved_parms[MAX_MSG_PARMS+1];
+#define MAXPARMSIDS 31
+    byte   * parms[MAXPARMSIDS];
+    byte   * add_i[4];
+    byte   * multi_fac_parms[MAX_MULTI_IE];
+    byte   * multi_pi_parms [MAX_MULTI_IE];
+    byte   * multi_ssext_parms [MAX_MULTI_IE];
+    byte   * multi_CiPN_parms [MAX_MULTI_IE];
+
+    byte   * multi_vswitch_parms [MAX_MULTI_IE];
+
+  byte ai_len;
+    byte   *esc_chi = "";
+    byte   *esc_law = "";
+    byte   *pty_cai = "";
+    byte   *esc_cr  = "";
+    byte   *esc_profile = "";
+
+    byte facility[256];
+  PLCI   * tplci = 0;
+  byte chi[] = "\x02\x18\x01";
+  byte voice_cai[]  = "\x06\x14\x00\x00\x00\x00\x08";
+    byte resume_cau[] = "\x05\x05\x00\x02\x00\x00";
+  /* ESC_MSGTYPE must be the last but one message, a new IE has to be */
+  /* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */
+  /* SMSG is situated at the end because its 0 (for compatibility reasons */
+  /* (see Info_Mask Bit 4, first IE. then the message type)           */
+    word parms_id[] =
+         {MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA,
+          UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW,
+          RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR,
+          CST, ESC_PROFILE, 0xff, ESC_MSGTYPE, SMSG};
+          /* 14 FTY repl by ESC_CHI */
+          /* 18 PI  repl by ESC_LAW */
+         /* removed OAD changed to 0xff for future use, OAD is multiIE now */
+     word multi_fac_id[] = {1, FTY};
+     word multi_pi_id[]  = {1, PI};
+     word multi_CiPN_id[]  = {1, OAD};
+     word multi_ssext_id[]  = {1, ESC_SSEXT};
+
+     word multi_vswitch_id[]  = {1, ESC_VSWITCH};
+
+  byte   * cau;
+  word ncci;
+    byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
+    byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00";
+    byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+    byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\0x00\0x00\0x00\0x00";
+  byte force_mt_info = FALSE;
+  byte dir;
+  dword d;
+  word w;
+
+  a = plci->adapter;
+  Id = ((word)plci->Id<<8)|a->Id;
+  WRITE_WORD(&SS_Ind[4],0x0000);
+
+  if (plci->sig_remove_id)
+  {
+    plci->Sig.RNR = 2; /* discard */
+    dbug(1,dprintf("SIG discard while remove pending"));
+    return;
+  }
+  if(plci->tel && plci->SuppState!=CALL_HELD) Id|=EXT_CONTROLLER;
+  dbug(1,dprintf("SigInd-Id=%08lx,plci=%x,tel=%x,state=0x%x,channels=%d,Discflowcl=%d",
+    Id,plci->Id,plci->tel,plci->State,plci->channels,plci->hangup_flow_ctrl_timer));
+  if(plci->Sig.Ind==CALL_HOLD_ACK && plci->channels)
+  {
+    plci->Sig.RNR = 1;
+    return;
+  }
+  if(plci->Sig.Ind==HANGUP && plci->channels)
+  {
+    plci->Sig.RNR = 1;
+    plci->hangup_flow_ctrl_timer++;
+    /* recover the network layer after timeout */
+    if(plci->hangup_flow_ctrl_timer==100)
+    {
+      dbug(1,dprintf("Exceptional disc"));
+      plci->Sig.RNR = 0;
+      plci->hangup_flow_ctrl_timer = 0;
+      for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+      {
+        if (a->ncci_plci[ncci] == plci->Id)
+        {
+          cleanup_ncci_data (plci, ncci);
+          if(plci->channels)plci->channels--;
+          if (plci->appl)
+            sendf(plci->appl,_DISCONNECT_B3_I, (((dword) ncci) << 16) | Id,0,"ws",0,"");
+        }
+      }
+      if (plci->appl)
+        sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
+      plci_remove(plci);
+      plci->State=IDLE;
+    }
+    return;
+  }
+
+  /* do first parse the info with no OAD in, because OAD will be converted */
+  /* first the multiple facility IE, then mult. progress ind.              */
+  /* then the parameters for the info_ind + conn_ind                       */
+  IndParse(plci,multi_fac_id,multi_fac_parms,MAX_MULTI_IE);
+  IndParse(plci,multi_pi_id,multi_pi_parms,MAX_MULTI_IE);
+  IndParse(plci,multi_ssext_id,multi_ssext_parms,MAX_MULTI_IE);
+
+  IndParse(plci,multi_vswitch_id,multi_vswitch_parms,MAX_MULTI_IE);
+
+  IndParse(plci,parms_id,parms,0);
+  IndParse(plci,multi_CiPN_id,multi_CiPN_parms,MAX_MULTI_IE);
+  esc_chi  = parms[14];
+  esc_law  = parms[18];
+  pty_cai  = parms[24];
+  esc_cr   = parms[25];
+  esc_profile = parms[27];
+  if(esc_cr[0] && plci)
+  {
+    if(plci->cr_enquiry && plci->appl)
+    {
+      plci->cr_enquiry = FALSE;
+      /* d = MANU_ID            */
+      /* w = m_command          */
+      /* b = total length       */
+      /* b = indication type    */
+      /* b = length of all IEs  */
+      /* b = IE1                */
+      /* S = IE1 length + cont. */
+      /* b = IE2                */
+      /* S = IE2 lenght + cont. */
+      sendf(plci->appl,
+        _MANUFACTURER_I,
+        Id,
+        0,
+        "dwbbbbSbS",_DI_MANU_ID,plci->m_command,
+        2+1+1+esc_cr[0]+1+1+esc_law[0],plci->Sig.Ind,1+1+esc_cr[0]+1+1+esc_law[0],ESC,esc_cr,ESC,esc_law);
+    }
+  }
+  /* create the additional info structure                                  */
+  add_i[1] = parms[15]; /* KEY of additional info */
+  add_i[2] = parms[11]; /* UUI of additional info */
+  ai_len = AddInfo(add_i,multi_fac_parms, esc_chi, facility);
+
+  /* the ESC_LAW indicates if u-Law or a-Law is actually used by the card  */
+  /* indication returns by the card if requested by the function           */
+  /* AutomaticLaw() after driver init                                      */
+  if (a->automatic_law<4)
+  {
+    if(esc_law[0]){
+      if(esc_law[2]){
+        dbug(0,dprintf("u-Law selected"));
+        a->u_law = 1;
+      }
+      else {
+        dbug(0,dprintf("a-Law selected"));
+        a->u_law = 0;
+      }
+      a->automatic_law = 4;
+      if(plci==a->automatic_lawPLCI) {
+        plci->internal_command = 0;
+        sig_req(plci,REMOVE,0);
+        send_req(plci);
+        a->automatic_lawPLCI = 0;
+      }
+    }
+    if (esc_profile[0])
+    {
+      dbug (1, dprintf ("[%06x] CardProfile: %lx %lx %lx %lx %lx",
+        UnMapController (a->Id), READ_DWORD (&esc_profile[6]),
+        READ_DWORD (&esc_profile[10]), READ_DWORD (&esc_profile[14]),
+        READ_DWORD (&esc_profile[18]), READ_DWORD (&esc_profile[46])));
+
+      a->profile.Global_Options &= 0x000000ffL;
+      a->profile.B1_Protocols &= 0x000003ffL;
+      a->profile.B2_Protocols &= 0x00001fdfL;
+      a->profile.B3_Protocols &= 0x000000b7L;
+
+      a->profile.Global_Options &= READ_DWORD (&esc_profile[6]) |
+        GL_BCHANNEL_OPERATION_SUPPORTED;
+      a->profile.B1_Protocols &= READ_DWORD (&esc_profile[10]);
+      a->profile.B2_Protocols &= READ_DWORD (&esc_profile[14]);
+      a->profile.B3_Protocols &= READ_DWORD (&esc_profile[18]);
+      a->manufacturer_features = READ_DWORD (&esc_profile[46]);
+      a->man_profile.private_options = 0;
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_ECHO_CANCELLER)
+      {
+        a->man_profile.private_options |= 1L << PRIVATE_ECHO_CANCELLER;
+        a->profile.Global_Options |= GL_ECHO_CANCELLER_SUPPORTED;
+      }
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_RTP)
+        a->man_profile.private_options |= 1L << PRIVATE_RTP;
+      a->man_profile.rtp_primary_payloads = READ_DWORD (&esc_profile[50]);
+      a->man_profile.rtp_additional_payloads = READ_DWORD (&esc_profile[54]);
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_T38)
+        a->man_profile.private_options |= 1L << PRIVATE_T38;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD)
+        a->man_profile.private_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_V18)
+        a->man_profile.private_options |= 1L << PRIVATE_V18;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_TONE)
+        a->man_profile.private_options |= 1L << PRIVATE_DTMF_TONE;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_PIAFS)
+        a->man_profile.private_options |= 1L << PRIVATE_PIAFS;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+        a->man_profile.private_options |= 1L << PRIVATE_FAX_PAPER_FORMATS;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_VOWN)
+        a->man_profile.private_options |= 1L << PRIVATE_VOWN;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_NONSTANDARD)
+        a->man_profile.private_options |= 1L << PRIVATE_FAX_NONSTANDARD;
+
+    }
+    else
+    {
+      a->profile.Global_Options &= 0x0000007fL;
+      a->profile.B1_Protocols &= 0x000003dfL;
+      a->profile.B2_Protocols &= 0x00001adfL;
+      a->profile.B3_Protocols &= 0x000000b7L;
+      a->manufacturer_features &= MANUFACTURER_FEATURE_HARDDTMF;
+    }
+    if (a->manufacturer_features & (MANUFACTURER_FEATURE_HARDDTMF |
+      MANUFACTURER_FEATURE_SOFTDTMF_SEND | MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
+    {
+      a->profile.Global_Options |= GL_DTMF_SUPPORTED;
+    }
+    a->manufacturer_features &= ~MANUFACTURER_FEATURE_OOB_CHANNEL;
+    dbug (1, dprintf ("[%06x] Profile: %lx %lx %lx %lx %lx",
+      UnMapController (a->Id), a->profile.Global_Options,
+      a->profile.B1_Protocols, a->profile.B2_Protocols,
+      a->profile.B3_Protocols, a->manufacturer_features));
+  }
+  /* codec plci for the handset/hook state support is just an internal id  */
+  if(plci!=a->AdvCodecPLCI)
+  {
+    force_mt_info =  SendMultiIE(plci,Id,multi_fac_parms, FTY, 0x20, 0);
+    force_mt_info |= SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, 0);
+    SendSSExtInd(0,plci,Id,multi_ssext_parms);
+    SendInfo(plci,Id, parms, force_mt_info);
+
+    VSwitchReqInd(plci,Id,multi_vswitch_parms);
+
+  }
+
+  /* switch the codec to the b-channel                                     */
+  if(esc_chi[0] && plci && !plci->SuppState){
+    plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
+    mixer_set_bchannel_id_esc (plci, plci->b_channel);
+    dbug(1,dprintf("storeChannel=0x%x",plci->b_channel));
+    if(plci->tel==ADV_VOICE && plci->appl) {
+      SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
+    }
+  }
+
+  if(plci->appl) Number = plci->appl->Number++;
+
+  switch(plci->Sig.Ind) {
+  /* Response to Get_Supported_Services request */
+  case S_SUPPORTED:
+    dbug(1,dprintf("S_Supported"));
+    if(!plci->appl) break;
+    if(pty_cai[0]==4)
+    {
+      WRITE_DWORD(&CF_Ind[6],READ_DWORD(&pty_cai[1]) );
+    }
+    else
+    {
+      WRITE_DWORD(&CF_Ind[6],MASK_TERMINAL_PORTABILITY | MASK_HOLD_RETRIEVE);
+    }
+    WRITE_WORD (&CF_Ind[1], 0);
+    WRITE_WORD (&CF_Ind[4], 0);
+    sendf(plci->appl,_FACILITY_R|CONFIRM,Id&0x7,plci->number, "wws",0,3,CF_Ind);
+    plci_remove(plci);
+    break;
+                    
+  /* Supplementary Service rejected */
+  case S_SERVICE_REJ:
+    dbug(1,dprintf("S_Reject=0x%x",pty_cai[5]));
+    if(!pty_cai[0]) break;
+    switch (pty_cai[5])
+    {
+    case ECT_EXECUTE:
+    case THREE_PTY_END:
+    case THREE_PTY_BEGIN:
+      if(!plci->relatedPTYPLCI) break;
+      tplci = plci->relatedPTYPLCI;
+      rId = ( (word)tplci->Id<<8)|tplci->adapter->Id;
+      if(tplci->tel) rId|=EXT_CONTROLLER;
+      if(pty_cai[5]==ECT_EXECUTE)
+      {
+        WRITE_WORD(&SS_Ind[1],S_ECT);
+
+        plci->vswitchstate=0;
+        plci->relatedPTYPLCI->vswitchstate=0;
+
+      }
+      else
+      {
+        WRITE_WORD(&SS_Ind[1],pty_cai[5]+3);
+      }
+      if(pty_cai[2]!=0xff)
+      {
+        WRITE_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        WRITE_WORD(&SS_Ind[4],0x300E);
+      }
+      plci->relatedPTYPLCI = 0;
+      plci->ptyState = 0;
+      sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
+      break;
+
+    case CALL_DEFLECTION:
+      if(pty_cai[2]!=0xff)
+      {
+        WRITE_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        WRITE_WORD(&SS_Ind[4],0x300E);
+      }
+      WRITE_WORD(&SS_Ind[1],pty_cai[5]);
+      for(i=0; i<max_appl; i++)
+      {
+        if(application[i].CDEnable)
+        {
+          if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
+          application[i].CDEnable = FALSE;
+        }
+      }
+      break;
+
+    case DEACTIVATION_DIVERSION:
+    case ACTIVATION_DIVERSION:
+    case DIVERSION_INTERROGATE_CFU:
+    case DIVERSION_INTERROGATE_CFB:
+    case DIVERSION_INTERROGATE_CFNR:
+    case DIVERSION_INTERROGATE_NUM:
+    case CCBS_REQUEST:
+    case CCBS_DEACTIVATE:
+    case CCBS_INTERROGATE:
+      if(!plci->appl) break;
+      if(pty_cai[2]!=0xff)
+      {
+        WRITE_WORD(&Interr_Err_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        WRITE_WORD(&Interr_Err_Ind[4],0x300E);
+      }
+      switch (pty_cai[5])
+      {
+        case DEACTIVATION_DIVERSION:
+          dbug(1,dprintf("Deact_Div"));
+          Interr_Err_Ind[0]=0x9;
+          Interr_Err_Ind[3]=0x6;
+          WRITE_WORD(&Interr_Err_Ind[1],S_CALL_FORWARDING_STOP);
+          break;
+        case ACTIVATION_DIVERSION:
+          dbug(1,dprintf("Act_Div"));
+          Interr_Err_Ind[0]=0x9;
+          Interr_Err_Ind[3]=0x6;
+          WRITE_WORD(&Interr_Err_Ind[1],S_CALL_FORWARDING_START);
+          break;
+        case DIVERSION_INTERROGATE_CFU:
+        case DIVERSION_INTERROGATE_CFB:
+        case DIVERSION_INTERROGATE_CFNR:
+          dbug(1,dprintf("Interr_Div"));
+          Interr_Err_Ind[0]=0xa;
+          Interr_Err_Ind[3]=0x7;
+          WRITE_WORD(&Interr_Err_Ind[1],S_INTERROGATE_DIVERSION);
+          break;
+        case DIVERSION_INTERROGATE_NUM:
+          dbug(1,dprintf("Interr_Num"));
+          Interr_Err_Ind[0]=0xa;
+          Interr_Err_Ind[3]=0x7;
+          WRITE_WORD(&Interr_Err_Ind[1],S_INTERROGATE_NUMBERS);
+          break;
+        case CCBS_REQUEST:
+          dbug(1,dprintf("CCBS Request"));
+          Interr_Err_Ind[0]=0xd;
+          Interr_Err_Ind[3]=0xa;
+          WRITE_WORD(&Interr_Err_Ind[1],S_CCBS_REQUEST);
+          break;
+        case CCBS_DEACTIVATE:
+          dbug(1,dprintf("CCBS Deactivate"));
+          Interr_Err_Ind[0]=0x9;
+          Interr_Err_Ind[3]=0x6;
+          WRITE_WORD(&Interr_Err_Ind[1],S_CCBS_DEACTIVATE);
+          break;
+        case CCBS_INTERROGATE:
+          dbug(1,dprintf("CCBS Interrogate"));
+          Interr_Err_Ind[0]=0xb;
+          Interr_Err_Ind[3]=0x8;
+          WRITE_WORD(&Interr_Err_Ind[1],S_CCBS_INTERROGATE);
+          break;
+      }
+      WRITE_DWORD(&Interr_Err_Ind[6],plci->appl->S_Handle);
+      sendf(plci->appl,_FACILITY_I,Id&0x7,0,"ws",3, Interr_Err_Ind);
+      plci_remove(plci);
+      break;
+    case ACTIVATION_MWI:      
+    case DEACTIVATION_MWI:
+      if(pty_cai[5]==ACTIVATION_MWI)
+      {
+        WRITE_WORD(&SS_Ind[1],S_MWI_ACTIVATE);
+      }
+      else WRITE_WORD(&SS_Ind[1],S_MWI_DEACTIVATE);
+      
+      if(pty_cai[2]!=0xff)
+      {
+        WRITE_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        WRITE_WORD(&SS_Ind[4],0x300E);
+      }
+
+      if(plci->cr_enquiry)
+      {
+        sendf(plci->appl,_FACILITY_I,Id&0xf,0,"ws",3, SS_Ind);
+        plci_remove(plci);
+      }
+      else
+      {
+        sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+      }
+      break;
+    case CONF_ADD: /* ERROR */
+    case CONF_BEGIN:
+    case CONF_DROP:
+    case CONF_ISOLATE:
+    case CONF_REATTACH:
+      CONF_Ind[0]=9;
+      CONF_Ind[3]=6;   
+      switch(pty_cai[5])
+      {
+      case CONF_BEGIN:
+          WRITE_WORD(&CONF_Ind[1],S_CONF_BEGIN);
+          plci->ptyState = 0;
+          break;
+      case CONF_DROP:
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          WRITE_WORD(&CONF_Ind[1],S_CONF_DROP);
+          plci->ptyState = CONNECTED;
+          break;
+      case CONF_ISOLATE:
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          WRITE_WORD(&CONF_Ind[1],S_CONF_ISOLATE);
+          plci->ptyState = CONNECTED;
+          break;
+      case CONF_REATTACH:
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          WRITE_WORD(&CONF_Ind[1],S_CONF_REATTACH);
+          plci->ptyState = CONNECTED;
+          break;
+      case CONF_ADD:
+          WRITE_WORD(&CONF_Ind[1],S_CONF_ADD);
+          plci->relatedPTYPLCI = 0;
+          tplci=plci->relatedPTYPLCI;
+          if(tplci) tplci->ptyState = CONNECTED;
+          plci->ptyState = CONNECTED;
+          break;
+      }
+          
+      if(pty_cai[2]!=0xff)
+      {
+        WRITE_WORD(&CONF_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        WRITE_WORD(&CONF_Ind[4],0x3303); /* Time-out: network did not respond
+                                            within the required time */
+      }
+
+      WRITE_DWORD(&CONF_Ind[6],0x0);
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
+      break;
+    }
+    break;
+
+  /* Supplementary Service indicates success */
+  case S_SERVICE:
+    dbug(1,dprintf("Service_Ind"));
+    WRITE_WORD (&CF_Ind[4], 0);
+    switch (pty_cai[5])
+    {
+    case THREE_PTY_END:
+    case THREE_PTY_BEGIN:
+    case ECT_EXECUTE:
+      if(!plci->relatedPTYPLCI) break;
+      tplci = plci->relatedPTYPLCI;
+      rId = ( (word)tplci->Id<<8)|tplci->adapter->Id;
+      if(tplci->tel) rId|=EXT_CONTROLLER;
+      if(pty_cai[5]==ECT_EXECUTE)
+      {
+        WRITE_WORD(&SS_Ind[1],S_ECT);
+
+        if(plci->vswitchstate!=3)
+        {
+
+        plci->ptyState = IDLE;
+        plci->relatedPTYPLCI = 0;
+        plci->ptyState = 0;
+
+        }
+
+        dbug(1,dprintf("ECT OK"));
+        sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
+
+
+
+      }
+      else
+      {
+        switch (plci->ptyState)
+        {
+        case S_3PTY_BEGIN:
+          plci->ptyState = CONNECTED;
+          dbug(1,dprintf("3PTY ON"));
+          break;
+
+        case S_3PTY_END:
+          plci->ptyState = IDLE;
+          plci->relatedPTYPLCI = 0;
+          plci->ptyState = 0;
+          dbug(1,dprintf("3PTY OFF"));
+          break;
+        }
+        WRITE_WORD(&SS_Ind[1],pty_cai[5]+3);
+        sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
+      }
+      break;
+
+    case CALL_DEFLECTION:
+      WRITE_WORD(&SS_Ind[1],pty_cai[5]);
+      for(i=0; i<max_appl; i++)
+      {
+        if(application[i].CDEnable)
+        {
+          if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
+          application[i].CDEnable = FALSE;
+        }
+      }
+      break;
+
+    case DEACTIVATION_DIVERSION:
+    case ACTIVATION_DIVERSION:
+      if(!plci->appl) break;
+      WRITE_WORD(&CF_Ind[1],pty_cai[5]+2);
+      WRITE_DWORD(&CF_Ind[6],plci->appl->S_Handle);
+      sendf(plci->appl,_FACILITY_I,Id&0x7,0,"ws",3, CF_Ind);
+      plci_remove(plci);
+      break;
+
+    case DIVERSION_INTERROGATE_CFU:
+    case DIVERSION_INTERROGATE_CFB:
+    case DIVERSION_INTERROGATE_CFNR:
+    case DIVERSION_INTERROGATE_NUM:
+    case CCBS_REQUEST:
+    case CCBS_DEACTIVATE:
+    case CCBS_INTERROGATE:
+      if(!plci->appl) break;
+      switch (pty_cai[5])
+      {
+        case DIVERSION_INTERROGATE_CFU:
+        case DIVERSION_INTERROGATE_CFB:
+        case DIVERSION_INTERROGATE_CFNR:
+          dbug(1,dprintf("Interr_Div"));
+          WRITE_WORD(&pty_cai[1],S_INTERROGATE_DIVERSION);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case DIVERSION_INTERROGATE_NUM:
+          dbug(1,dprintf("Interr_Num"));
+          WRITE_WORD(&pty_cai[1],S_INTERROGATE_NUMBERS);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case CCBS_REQUEST:
+          dbug(1,dprintf("CCBS Request"));
+          WRITE_WORD(&pty_cai[1],S_CCBS_REQUEST);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case CCBS_DEACTIVATE:
+          dbug(1,dprintf("CCBS Deactivate"));
+          WRITE_WORD(&pty_cai[1],S_CCBS_DEACTIVATE);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case CCBS_INTERROGATE:
+          dbug(1,dprintf("CCBS Interrogate"));
+          WRITE_WORD(&pty_cai[1],S_CCBS_INTERROGATE);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+      }
+      WRITE_WORD(&pty_cai[4],0); /* Supplementary Service Reason */
+      WRITE_DWORD(&pty_cai[6],plci->appl->S_Handle);
+      sendf(plci->appl,_FACILITY_I,Id&0x7,0,"wS",3, pty_cai);
+      plci_remove(plci);
+      break;
+
+    case ACTIVATION_MWI:
+    case DEACTIVATION_MWI:
+      if(pty_cai[5]==ACTIVATION_MWI)
+      {
+        WRITE_WORD(&SS_Ind[1],S_MWI_ACTIVATE);
+      }
+      else WRITE_WORD(&SS_Ind[1],S_MWI_DEACTIVATE);
+      if(plci->cr_enquiry)
+      {
+        sendf(plci->appl,_FACILITY_I,Id&0xf,0,"ws",3, SS_Ind);
+        plci_remove(plci);
+      }
+      else
+      {
+        sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+      }
+      break;
+    case MWI_INDICATION:
+      if(pty_cai[0]>=0x12)
+      {
+        WRITE_WORD(&pty_cai[3],S_MWI_INDICATE);
+        pty_cai[2]=pty_cai[0]-2; /* len Parameter */
+        pty_cai[5]=pty_cai[0]-5; /* Supplementary Service-specific parameter len */
+        if(plci->appl && (a->Notification_Mask[plci->appl->Id-1]&SMASK_MWI))
+        {
+          if(plci->internal_command==GET_MWI_STATE) /* result on Message Waiting Listen */
+          {
+            sendf(plci->appl,_FACILITY_I,Id&0xf,0,"wS",3, &pty_cai[2]);
+            plci_remove(plci);
+            return;
+          }
+          else  sendf(plci->appl,_FACILITY_I,Id,0,"wS",3, &pty_cai[2]);
+          pty_cai[0]=0;
+        }
+        else
+        {
+          for(i=0; i<max_appl; i++)
+          {                     
+            if(a->Notification_Mask[i]&SMASK_MWI)
+            {
+              sendf(&application[i],_FACILITY_I,Id&0x7,0,"wS",3, &pty_cai[2]);
+              pty_cai[0]=0;
+            }
+          }
+        }
+
+        if(!pty_cai[0])
+        { /* acknowledge */
+          facility[2]= 0; /* returncode */
+        }
+        else facility[2]= 0xff;
+      }
+      else
+      {
+        /* reject */
+        facility[2]= 0xff; /* returncode */
+      }
+      facility[0]= 2;
+      facility[1]= MWI_RESPONSE; /* Function */
+      add_p(plci,CAI,facility);
+      add_p(plci,ESC,multi_ssext_parms[0]); /* remembered parameter -> only one possible */
+      sig_req(plci,S_SERVICE,0);
+      send_req(plci);
+      plci->command = 0;
+      next_internal_command (Id, plci);
+      break;
+    case CONF_ADD: /* OK */
+    case CONF_BEGIN:
+    case CONF_DROP:
+    case CONF_ISOLATE:
+    case CONF_REATTACH:
+    case CONF_PARTYDISC:
+      CONF_Ind[0]=9;
+      CONF_Ind[3]=6;
+      switch(pty_cai[5])
+      {
+      case CONF_BEGIN:
+          WRITE_WORD(&CONF_Ind[1],S_CONF_BEGIN);
+          if(pty_cai[0]==6)
+          {
+              d=pty_cai[6];
+              WRITE_DWORD(&CONF_Ind[6],d); /* PartyID */
+          }
+          else
+          {
+              WRITE_DWORD(&CONF_Ind[6],0x0);
+          }
+          break;
+      case CONF_ISOLATE:
+          WRITE_WORD(&CONF_Ind[1],S_CONF_ISOLATE);
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          break;
+      case CONF_REATTACH:
+          WRITE_WORD(&CONF_Ind[1],S_CONF_REATTACH);
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          break;
+      case CONF_DROP:
+          WRITE_WORD(&CONF_Ind[1],S_CONF_DROP);
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          break;
+      case CONF_ADD:
+          WRITE_WORD(&CONF_Ind[1],S_CONF_ADD);
+          d=pty_cai[6];
+          WRITE_DWORD(&CONF_Ind[6],d); /* PartyID */
+          tplci=plci->relatedPTYPLCI;
+          if(tplci) tplci->ptyState = CONNECTED;
+          break;
+      case CONF_PARTYDISC:
+          CONF_Ind[0]=7;
+          CONF_Ind[3]=4;          
+          WRITE_WORD(&CONF_Ind[1],S_CONF_PARTYDISC);
+          d=pty_cai[6];
+          WRITE_DWORD(&CONF_Ind[4],d); /* PartyID */
+          break;
+      }
+      plci->ptyState = CONNECTED;
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
+      break;
+    case CCBS_INFO_RETAIN:
+    case CCBS_ERASECALLLINKAGEID:
+    case CCBS_STOP_ALERTING:
+      CONF_Ind[0]=5;
+      CONF_Ind[3]=2;
+      switch(pty_cai[5])
+      {
+      case CCBS_INFO_RETAIN:
+        WRITE_WORD(&CONF_Ind[1],S_CCBS_INFO_RETAIN);
+        break;
+      case CCBS_STOP_ALERTING:
+        WRITE_WORD(&CONF_Ind[1],S_CCBS_STOP_ALERTING);
+    break;
+      case CCBS_ERASECALLLINKAGEID:
+        WRITE_WORD(&CONF_Ind[1],S_CCBS_ERASECALLLINKAGEID);
+        CONF_Ind[0]=7;
+        CONF_Ind[3]=4;
+        CONF_Ind[6]=0;
+        CONF_Ind[7]=0;
+        break;
+      }      
+      w=pty_cai[6];
+      WRITE_WORD(&CONF_Ind[4],w); /* PartyID */
+
+      if(plci->appl && (a->Notification_Mask[plci->appl->Id-1]&SMASK_CCBS))
+      {
+        sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
+      }
+      else
+      {
+        for(i=0; i<max_appl; i++)
+            if(a->Notification_Mask[i]&SMASK_CCBS)
+                sendf(&application[i],_FACILITY_I,Id&0x7,0,"ws",3, CONF_Ind);
+      }
+      break;
+    }
+    break;
+  case CALL_HOLD_REJ:
+    cau = parms[7];
+    if(cau)
+    {
+      i = _L3_CAUSE | cau[2];
+      if(cau[2]==0) i = 0x3603;
+    }
+    else
+    {
+      i = 0x3603;
+    }
+    WRITE_WORD(&SS_Ind[1],S_HOLD);
+    WRITE_WORD(&SS_Ind[4],i);
+    if(plci->SuppState == HOLD_REQUEST)
+    {
+      plci->SuppState = IDLE;
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+    }
+    break;
+
+  case CALL_HOLD_ACK:
+    if(plci->SuppState == HOLD_REQUEST)
+    {
+      plci->SuppState = CALL_HELD;
+      CodecIdCheck(a, plci);
+      start_internal_command (Id, plci, hold_save_command);
+    }
+    break;
+
+  case CALL_RETRIEVE_REJ:
+    cau = parms[7];
+    if(cau)
+    {
+      i = _L3_CAUSE | cau[2];
+      if(cau[2]==0) i = 0x3603;
+    }
+    else
+    {
+      i = 0x3603;
+    }
+    WRITE_WORD(&SS_Ind[1],S_RETRIEVE);
+    WRITE_WORD(&SS_Ind[4],i);
+    if(plci->SuppState == RETRIEVE_REQUEST)
+    {
+      plci->SuppState = CALL_HELD;
+      CodecIdCheck(a, plci);
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+    }
+    break;
+
+  case CALL_RETRIEVE_ACK:
+    WRITE_WORD(&SS_Ind[1],S_RETRIEVE);
+    if(plci->SuppState == RETRIEVE_REQUEST)
+    {
+      plci->SuppState = IDLE;
+      plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
+      plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
+      if(plci->tel)
+      {
+        mixer_set_bchannel_id_esc (plci, plci->b_channel);
+        dbug(1,dprintf("RetrChannel=0x%x",plci->b_channel));
+        SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
+        if(plci->B2_prot==B2_TRANSPARENT && plci->B3_prot==B3_TRANSPARENT)
+        {
+          dbug(1,dprintf("Get B-ch"));
+          start_internal_command (Id, plci, retrieve_restore_command);
+        }
+        else
+          sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+      }
+      else
+        start_internal_command (Id, plci, retrieve_restore_command);
+    }
+    break;
+
+  case INDICATE_IND:
+    if(plci->State != LISTENING) {
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+      break;
+    }
+    cip = find_cip(a,parms[4],parms[6]);
+    cip_mask = 1L<<cip;
+    dbug(1,dprintf("cip=%d,cip_mask=%lx",cip,cip_mask));
+    clear_c_ind_mask (plci);
+    if (!remove_started && !a->adapter_disabled)
+    {
+      set_c_ind_mask_bit (plci, MAX_APPL);
+      group_optimization(a, plci);
+      for(i=0; i<max_appl; i++) {
+        if(application[i].Id
+        && (a->CIP_Mask[i]&1 || a->CIP_Mask[i]&cip_mask)
+        && CPN_filter_ok(parms[0],a,i)
+        && test_group_ind_mask_bit (plci, i) ) {
+          dbug(1,dprintf("storedcip_mask[%d]=0x%lx",i,a->CIP_Mask[i] ));
+          set_c_ind_mask_bit (plci, i);
+          dump_c_ind_mask (plci);
+          plci->State = INC_CON_PENDING;
+          plci->call_dir = (plci->call_dir & ~(CALL_DIR_OUT | CALL_DIR_ORIGINATE)) |
+            CALL_DIR_IN | CALL_DIR_ANSWER;
+          if(esc_chi[0]) {
+            plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
+            mixer_set_bchannel_id_esc (plci, plci->b_channel);
+          }
+          /* if a listen on the ext controller is done, check if hook states */
+          /* are supported or if just a on board codec must be activated     */
+          if(a->codec_listen[i] && !a->AdvSignalPLCI) {
+            if(a->profile.Global_Options & HANDSET)
+              plci->tel = ADV_VOICE;
+            else if(a->profile.Global_Options & ON_BOARD_CODEC)
+              plci->tel = CODEC;
+            if(plci->tel) Id|=EXT_CONTROLLER;
+            a->codec_listen[i] = plci;
+          }
+
+          sendf(&application[i],_CONNECT_I,Id,0,
+                "wSSSSSSSbSSSSS", cip,    /* CIP                 */
+                             parms[0],    /* CalledPartyNumber   */
+                             multi_CiPN_parms[0],    /* CallingPartyNumber  */
+                             parms[2],    /* CalledPartySubad    */
+                             parms[3],    /* CallingPartySubad   */
+                             parms[4],    /* BearerCapability    */
+                             parms[5],    /* LowLC               */
+                             parms[6],    /* HighLC              */
+                             ai_len,      /* nested struct add_i */
+                             add_i[0],    /* B channel info    */
+                             add_i[1],    /* keypad facility   */
+                             add_i[2],    /* user user data    */
+                             add_i[3],    /* nested facility   */
+                             multi_CiPN_parms[1]    /* second CiPN(SCR)   */
+                             );
+          SendSSExtInd(&application[i],
+                        plci,
+                        Id,
+                        multi_ssext_parms);
+          SendSetupInfo(&application[i],
+                        plci,
+                        Id,
+                        parms,
+                        SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, TRUE));
+        }
+      }
+      clear_c_ind_mask_bit (plci, MAX_APPL);
+      dump_c_ind_mask (plci);
+    }
+    if(c_ind_mask_empty (plci)) {
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+      plci->State = IDLE;
+    }
+    plci->notifiedcall = 0;
+    a->listen_active--;
+    listen_check(a);
+    break;
+
+  case CALL_PEND_NOTIFY:
+    plci->notifiedcall = 1;
+    listen_check(a);
+    break;
+
+  case CALL_IND:
+  case CALL_CON:
+    if(plci->State==ADVANCED_VOICE_SIG || plci->State==ADVANCED_VOICE_NOSIG)
+    {
+      if(plci->internal_command==PERM_COD_CONN_PEND)
+      {
+        if(plci->State==ADVANCED_VOICE_NOSIG)
+        {
+          dbug(1,dprintf("***Codec OK"));
+          if(a->AdvSignalPLCI)
+          {
+            tplci = a->AdvSignalPLCI;
+            if(tplci->spoofed_msg)
+            {
+              dbug(1,dprintf("***Spoofed Msg(0x%x)",tplci->spoofed_msg));
+              tplci->command = 0;
+              tplci->internal_command = 0;
+              x_Id = ((word)tplci->Id<<8)|tplci->adapter->Id | 0x80;
+              switch (tplci->spoofed_msg)
+              {
+              case CALL_RES:
+                tplci->command = _CONNECT_I|RESPONSE;
+                api_load_msg (&tplci->saved_msg, saved_parms);
+                add_b1(tplci,&saved_parms[1],0,tplci->B1_facilities);
+                if (tplci->adapter->Info_Mask[tplci->appl->Id-1] & 0x200)
+                {
+                  /* early B3 connect (CIP mask bit 9) no release after a disc */
+                  add_p(tplci,LLI,"\x01\x01");
+                }
+                add_s(tplci, CONN_NR, &saved_parms[2]);
+                add_s(tplci, LLC, &saved_parms[4]);
+                add_ai(tplci, &saved_parms[5]);
+                tplci->State = INC_CON_ACCEPT;
+                sig_req(tplci, CALL_RES,0);
+                send_req(tplci);
+                break;
+
+              case AWAITING_SELECT_B:
+                dbug(1,dprintf("Select_B continue"));
+                start_internal_command (x_Id, tplci, select_b_command);
+                break;
+
+              case AWAITING_MANUF_CON: /* Get_Plci per Manufacturer_Req to ext controller */
+                if(!tplci->Sig.Id)
+                {
+                  dbug(1,dprintf("No SigID!"));
+                  sendf(tplci->appl, _MANUFACTURER_R|CONFIRM,x_Id,tplci->number, "dww",_DI_MANU_ID,_MANUFACTURER_R,_OUT_OF_PLCI);
+                  plci_remove(tplci);
+                  break;
+                }
+                tplci->command = _MANUFACTURER_R;
+                api_load_msg (&tplci->saved_msg, saved_parms);
+                dir = saved_parms[2].info[0];
+                if(dir==1) {
+                  sig_req(tplci,CALL_REQ,0);
+                }
+                else if(!dir){
+                  sig_req(tplci,LISTEN_REQ,0);
+                }
+                send_req(tplci);
+                sendf(tplci->appl, _MANUFACTURER_R|CONFIRM,x_Id,tplci->number, "dww",_DI_MANU_ID,_MANUFACTURER_R,0);
+                break;
+
+              case (CALL_REQ|AWAITING_MANUF_CON):
+                sig_req(tplci,CALL_REQ,0);
+                send_req(tplci);
+                break;
+
+              case CALL_REQ:
+                if(!tplci->Sig.Id)
+                {
+                  dbug(1,dprintf("No SigID!"));
+                  sendf(tplci->appl,_CONNECT_R|CONFIRM,tplci->adapter->Id,0,"w",_OUT_OF_PLCI);
+                  plci_remove(tplci);
+                  break;
+                }
+                tplci->command = _CONNECT_R;
+                api_load_msg (&tplci->saved_msg, saved_parms);
+                add_s(tplci,CPN,&saved_parms[1]);
+                add_s(tplci,DSA,&saved_parms[3]);
+                add_ai(tplci,&saved_parms[9]);
+                sig_req(tplci,CALL_REQ,0);
+                send_req(tplci);
+                break;
+
+              case CALL_RETRIEVE:
+                tplci->command = C_RETRIEVE_REQ;
+                sig_req(tplci,CALL_RETRIEVE,0);
+                send_req(tplci);
+                break;
+              }
+              tplci->spoofed_msg = 0;
+              if (tplci->internal_command == 0)
+                next_internal_command (x_Id, tplci);
+            }
+          }
+          next_internal_command (Id, plci);
+          break;
+        }
+        dbug(1,dprintf("***Codec Hook Init Req"));
+        plci->internal_command = PERM_COD_HOOK;
+        add_p(plci,FTY,"\x01\x09");             /* Get Hook State*/
+        sig_req(plci,TEL_CTRL,0);
+        send_req(plci);
+      }
+    }
+    else if(plci->command != _MANUFACTURER_R  /* old style permanent connect */
+    && plci->State!=INC_ACT_PENDING)
+    {
+      mixer_set_bchannel_id_esc (plci, plci->b_channel);
+      if(plci->tel == ADV_VOICE && plci->SuppState == IDLE) /* with permanent codec switch on immediately */
+      {
+        chi[2] = plci->b_channel;
+        SetVoiceChannel(a->AdvCodecPLCI, chi, a);
+      }
+      sendf(plci->appl,_CONNECT_ACTIVE_I,Id,0,"Sss",parms[21],"","");
+      plci->State = INC_ACT_PENDING;
+    }
+    break;
+
+  case TEL_CTRL:
+    Number = 0;
+    ie = multi_fac_parms[0]; /* inspect the facility hook indications */
+    if(plci->State==ADVANCED_VOICE_SIG && ie[0]){
+      switch (ie[1]&0x91) {
+        case 0x80:   /* hook off */
+        case 0x81:
+          if(plci->internal_command==PERM_COD_HOOK)
+          {
+            dbug(1,dprintf("init:hook_off"));
+            plci->hook_state = ie[1];
+            next_internal_command (Id, plci);
+            break;
+          }
+          else /* ignore doubled hook indications */
+          {
+            if( ((plci->hook_state)&0xf0)==0x80)
+            {
+              dbug(1,dprintf("ignore hook"));
+              break;
+            }
+            plci->hook_state = ie[1]&0x91;
+          }
+          /* check for incoming call pending */
+          /* and signal '+'.Appl must decide */
+          /* with connect_res if call must   */
+          /* accepted or not                 */
+          for(i=0, tplci=0;i<max_appl;i++){
+            if(a->codec_listen[i]
+            && (a->codec_listen[i]->State==INC_CON_PENDING
+              ||a->codec_listen[i]->State==INC_CON_ALERT) ){
+              tplci = a->codec_listen[i];
+              tplci->appl = &application[i];
+            }
+          }
+          /* no incoming call, do outgoing call */
+          /* and signal '+' if outg. setup   */
+          if(!a->AdvSignalPLCI && !tplci){
+            if((i=get_plci(a))) {
+              a->AdvSignalPLCI = &a->plci[i-1];
+              tplci = a->AdvSignalPLCI;
+              tplci->tel  = ADV_VOICE;
+              WRITE_WORD(&voice_cai[5],a->AdvSignalAppl->MaxDataLength);
+              if (a->Info_Mask[a->AdvSignalAppl->Id-1] & 0x200){
+                /* early B3 connect (CIP mask bit 9) no release after a disc */
+                add_p(tplci,LLI,"\x01\x01");
+              }
+              add_p(tplci, CAI, voice_cai);
+              add_p(tplci, OAD, a->TelOAD);
+              add_p(tplci, OSA, a->TelOSA);
+              add_p(tplci,SHIFT|6,0);
+              add_p(tplci,SIN,"\x02\x01\x00");
+              add_p(tplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(tplci,ASSIGN,DSIG_ID);
+              a->AdvSignalPLCI->internal_command = HOOK_OFF_REQ;
+              a->AdvSignalPLCI->command = 0;
+              tplci->appl = a->AdvSignalAppl;
+              tplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+              send_req(tplci);
+            }
+
+          }
+
+          if(!tplci) break;
+          Id = ((word)tplci->Id<<8)|a->Id;
+          Id|=EXT_CONTROLLER;
+          sendf(tplci->appl,
+                _FACILITY_I,
+                Id,
+                0,
+                "ws", (word)0, "\x01+");
+          break;
+
+        case 0x90:   /* hook on  */
+        case 0x91:
+          if(plci->internal_command==PERM_COD_HOOK)
+          {
+            dbug(1,dprintf("init:hook_on"));
+            plci->hook_state = ie[1]&0x91;
+            next_internal_command (Id, plci);
+            break;
+          }
+          else /* ignore doubled hook indications */
+          {
+            if( ((plci->hook_state)&0xf0)==0x90) break;
+            plci->hook_state = ie[1]&0x91;
+          }
+          /* hangup the adv. voice call and signal '-' to the appl */
+          if(a->AdvSignalPLCI) {
+            Id = ((word)a->AdvSignalPLCI->Id<<8)|a->Id;
+            if(plci->tel) Id|=EXT_CONTROLLER;
+            sendf(a->AdvSignalAppl,
+                  _FACILITY_I,
+                  Id,
+                  0,
+                  "ws", (word)0, "\x01-");
+            a->AdvSignalPLCI->internal_command = HOOK_ON_REQ;
+            a->AdvSignalPLCI->command = 0;
+            sig_req(a->AdvSignalPLCI,HANGUP,0);
+            send_req(a->AdvSignalPLCI);
+          }
+          break;
+      }
+    }
+    break;
+
+  case RESUME:
+    clear_c_ind_mask_bit (plci, (word)(plci->appl->Id-1));
+    WRITE_WORD(&resume_cau[4],GOOD);
+    sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, resume_cau);
+    break;
+
+  case SUSPEND:
+    clear_c_ind_mask (plci);
+
+    if (plci->NL.Id && !plci->nl_remove_id) {
+      mixer_remove (plci);
+      nl_req_ncci(plci,REMOVE,0);
+    }
+    if (!plci->sig_remove_id) {
+      plci->internal_command = 0;
+      sig_req(plci,REMOVE,0);
+    }
+    send_req(plci);
+    if(!plci->channels) {
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, "\x05\x04\x00\x02\x00\x00");
+      sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
+    }
+    break;
+
+  case SUSPEND_REJ:
+    break;
+
+  case HANGUP:
+    plci->hangup_flow_ctrl_timer=0;
+    if(plci->manufacturer && plci->State==LOCAL_CONNECT) break;
+    cau = parms[7];
+    if(cau) {
+      i = _L3_CAUSE | cau[2];
+      if(cau[2]==0) i = 0;
+      else if(cau[2]==8) i = _L1_ERROR;
+      else if(cau[2]==9 || cau[2]==10) i = _L2_ERROR;
+      else if(cau[2]==5) i = _CAPI_GUARD_ERROR;
+    }
+    else {
+      i = _L3_ERROR;
+    }
+
+    if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT)
+    {
+      for(i=0; i<max_appl; i++)
+      {
+        if(test_c_ind_mask_bit (plci, i))
+          sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
+      }
+    }
+    else
+    {
+      clear_c_ind_mask (plci);
+    }
+    if(!plci->appl)
+    {
+      if (plci->State == LISTENING)
+      {
+        plci->notifiedcall=0;
+        a->listen_active--;
+      }
+      plci->State = INC_DIS_PENDING;
+      if(c_ind_mask_empty (plci))
+      {
+        plci->State = IDLE;
+        if (plci->NL.Id && !plci->nl_remove_id)
+        {
+          mixer_remove (plci);
+          nl_req_ncci(plci,REMOVE,0);
+        }
+        if (!plci->sig_remove_id)
+        {
+          plci->internal_command = 0;
+          sig_req(plci,REMOVE,0);
+        }
+        send_req(plci);
+      }
+    }
+    else
+    {
+        /* collision of DISCONNECT or CONNECT_RES with HANGUP can   */
+        /* result in a second HANGUP! Don't generate another        */
+        /* DISCONNECT                                               */
+      if(plci->State!=IDLE && plci->State!=INC_DIS_PENDING)
+      {
+        if(plci->State==RESUMING)
+        {
+          WRITE_WORD(&resume_cau[4],i);
+          sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, resume_cau);
+        }
+        plci->State = INC_DIS_PENDING;
+        sendf(plci->appl,_DISCONNECT_I,Id,0,"w",i);
+      }
+    }
+    break;
+
+  case SSEXT_IND:
+    SendSSExtInd(0,plci,Id,multi_ssext_parms);
+    break;
+
+  case VSWITCH_REQ:
+    VSwitchReqInd(plci,Id,multi_vswitch_parms);
+    break;
+  case VSWITCH_IND:
+ if(plci->relatedPTYPLCI &&
+  plci->vswitchstate==3 &&
+  plci->relatedPTYPLCI->vswitchstate==3 &&
+  parms[MAXPARMSIDS-1][0])
+ {
+  add_p(plci->relatedPTYPLCI,SMSG,parms[MAXPARMSIDS-1]);
+  sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
+  send_req(plci->relatedPTYPLCI);
+ }
+    else VSwitchReqInd(plci,Id,multi_vswitch_parms);
+    break;
+
+  }
+}
+
+
+static void SendSetupInfo(APPL   * appl, PLCI   * plci, dword Id, byte   * * parms, byte Info_Sent_Flag)
+{
+  word i;
+  byte   * ie;
+  word Info_Number;
+  byte   * Info_Element;
+  word Info_Mask = 0;
+
+  dbug(1,dprintf("SetupInfo"));
+
+  for(i=0; i<MAXPARMSIDS; i++) {
+    ie = parms[i];
+    Info_Number = 0;
+    Info_Element = ie;
+    if(ie[0]) {
+      switch(i) {
+      case 0:
+        dbug(1,dprintf("CPN "));
+        Info_Number = 0x0070;
+        Info_Mask   = 0x80;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 8:  /* display      */
+        dbug(1,dprintf("display(%d)",i));
+        Info_Number = 0x0028;
+        Info_Mask = 0x04;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 16: /* Channel Id */
+        dbug(1,dprintf("CHI"));
+        Info_Number = 0x0018;
+        Info_Mask = 0x100;
+        Info_Sent_Flag = TRUE;
+        mixer_set_bchannel_id (plci, Info_Element);
+        break;
+      case 19: /* Redirected Number */
+        dbug(1,dprintf("RDN"));
+        Info_Number = 0x0074;
+        Info_Mask = 0x400;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 20: /* Redirected Number extended */
+        dbug(1,dprintf("RDX"));
+        Info_Number = 0x0073;
+        Info_Mask = 0x400;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 22: /* Redirecing Number  */
+        dbug(1,dprintf("RIN"));
+        Info_Number = 0x0076;
+        Info_Mask = 0x400;
+        Info_Sent_Flag = TRUE;
+        break;
+      default:
+        Info_Number = 0;
+        break;
+      }
+    }
+
+    if(i==MAXPARMSIDS-2){ /* to indicate the message type "Setup" */
+      Info_Number = 0x8000 |5;
+      Info_Mask = 0x10;
+      Info_Element = "";
+    }
+
+    if(Info_Sent_Flag && Info_Number){
+      if(plci->adapter->Info_Mask[appl->Id-1] & Info_Mask) {
+        sendf(appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+      }
+    }
+  }
+}
+
+
+void SendInfo(PLCI   * plci, dword Id, byte   * * parms, byte iesent)
+{
+  word i;
+  word j;
+  word k;
+  byte   * ie;
+  word Info_Number;
+  byte   * Info_Element;
+  word Info_Mask = 0;
+  static byte charges[5] = {4,0,0,0,0};
+  static byte cause[] = {0x02,0x80,0x00};
+  APPL   *appl;
+
+  dbug(1,dprintf("InfoParse "));
+
+  if(
+        !plci->appl
+        && !plci->State
+        && plci->Sig.Ind!=NCR_FACILITY
+      )
+  {
+    dbug(1,dprintf("NoParse "));
+    return;
+  }
+  cause[2] = 0;
+  for(i=0; i<MAXPARMSIDS; i++) {
+    ie = parms[i];
+    Info_Number = 0;
+    Info_Element = ie;
+    if(ie[0]) {
+      switch(i) {
+      case 0:
+        dbug(1,dprintf("CPN "));
+        Info_Number = 0x0070;
+        Info_Mask   = 0x80;
+        break;
+      case 7: /* ESC_CAU */
+        dbug(1,dprintf("cau(0x%x)",ie[2]));
+        Info_Number = 0x0008;
+        Info_Mask = 0x00;
+        cause[2] = ie[2];
+        Info_Element = 0;
+        break;
+      case 8:  /* display      */
+        dbug(1,dprintf("display(%d)",i));
+        Info_Number = 0x0028;
+        Info_Mask = 0x04;
+        break;
+      case 9:  /* Date display */
+        dbug(1,dprintf("date(%d)",i));
+        Info_Number = 0x0029;
+        Info_Mask = 0x02;
+        break;
+      case 10: /* charges */
+        for(j=0;j<4;j++) charges[1+j] = 0;
+        for(j=0; j<ie[0] && !(ie[1+j]&0x80); j++);
+        for(k=1,j++; j<ie[0] && k<=4; j++,k++) charges[k] = ie[1+j];
+        Info_Number = 0x4000;
+        Info_Mask = 0x40;
+        Info_Element = charges;
+        break;
+      case 11: /* user user info */
+        dbug(1,dprintf("uui"));
+        Info_Number = 0x007E;
+        Info_Mask = 0x08;
+        break;
+      case 12: /* congestion receiver ready */
+        dbug(1,dprintf("clRDY"));
+        Info_Number = 0x00B0;
+        Info_Mask = 0x08;
+        Info_Element = "";
+        break;
+      case 13: /* congestion receiver not ready */
+        dbug(1,dprintf("clNRDY"));
+        Info_Number = 0x00BF;
+        Info_Mask = 0x08;
+        Info_Element = "";
+        break;
+      case 15: /* Keypad Facility */
+        dbug(1,dprintf("KEY"));
+        Info_Number = 0x002C;
+        Info_Mask = 0x20;
+        break;
+      case 16: /* Channel Id */
+        dbug(1,dprintf("CHI"));
+        Info_Number = 0x0018;
+        Info_Mask = 0x100;
+        mixer_set_bchannel_id (plci, Info_Element);
+        break;
+      case 17: /* if no 1tr6 cause, send full cause, else esc_cause */
+        dbug(1,dprintf("q9cau(0x%x)",ie[2]));
+        if(!cause[2] || cause[2]<0x80) break;  /* eg. layer 1 error */
+        Info_Number = 0x0008;
+        Info_Mask = 0x01;
+        if(cause[2] != ie[2]) Info_Element = cause;
+        break;
+      case 19: /* Redirected Number */
+        dbug(1,dprintf("RDN"));
+        Info_Number = 0x0074;
+        Info_Mask = 0x400;
+        break;
+      case 22: /* Redirecing Number  */
+        dbug(1,dprintf("RIN"));
+        Info_Number = 0x0076;
+        Info_Mask = 0x400;
+        break;
+      case 23: /* Notification Indicator  */
+        dbug(1,dprintf("NI"));
+        Info_Number = (word)NI;
+        Info_Mask = 0x210;
+        break;
+      case 26: /* Call State  */
+        dbug(1,dprintf("CST"));
+        Info_Number = (word)CST;
+        Info_Mask = 0x01; /* do with cause i.e. for now */
+        break;
+      case MAXPARMSIDS-2:  /* Escape Message Type, must be the last indication */
+        dbug(1,dprintf("ESC/MT[0x%x]",ie[3]));
+        Info_Number = 0x8000 |ie[3];
+        if(iesent) Info_Mask = 0xffff;
+        else  Info_Mask = 0x10;
+        Info_Element = "";
+        break;
+      default:
+        Info_Number  = 0;
+        Info_Mask    = 0;
+        Info_Element = "";
+        break;
+      }
+    }
+
+    if(plci->Sig.Ind==NCR_FACILITY)           /* check controller broadcast */
+    {
+      for(j=0; j<max_appl; j++)
+      {
+        appl = &application[j];
+        if(Info_Number
+        && appl->Id
+        && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
+        {
+          dbug(1,dprintf("NCR_Ind"));
+          iesent=TRUE;
+          sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
+        }
+      }
+    }
+    else if(!plci->appl)
+    { /* overlap receiving broadcast */
+      if(Info_Number==CPN
+      || Info_Number==KEY
+      || Info_Number==NI
+      || Info_Number==DSP
+      || Info_Number==UUI )
+      {
+        for(j=0; j<max_appl; j++)
+        {
+          if(test_c_ind_mask_bit (plci, j))
+          {
+            dbug(1,dprintf("Ovl_Ind"));
+            iesent=TRUE;
+            sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+          }
+        }
+      }
+    }               /* all other signalling states */
+    else if(Info_Number
+    && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
+    {
+      dbug(1,dprintf("Std_Ind"));
+      iesent=TRUE;
+      sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+    }
+  }
+}
+
+
+byte SendMultiIE(PLCI   * plci, dword Id, byte   * * parms, byte ie_type, dword info_mask, byte setupParse)
+{
+  word i;
+  word j;
+  byte   * ie;
+  word Info_Number;
+  byte   * Info_Element;
+  APPL   *appl;
+  word Info_Mask = 0;
+  byte iesent=0;
+
+  if(
+      !plci->appl
+      && !plci->State
+      && plci->Sig.Ind!=NCR_FACILITY
+      && !setupParse
+      )
+  {
+    dbug(1,dprintf("NoM-IEParse "));
+    return 0;
+  }
+  dbug(1,dprintf("M-IEParse "));
+
+  for(i=0; i<MAX_MULTI_IE; i++)
+  {
+    ie = parms[i];
+    Info_Number = 0;
+    Info_Element = ie;
+    if(ie[0])
+    {
+      dbug(1,dprintf("[Ind0x%x]:IE=0x%x",plci->Sig.Ind,ie_type));
+      Info_Number = (word)ie_type;
+      Info_Mask = (word)info_mask;
+    }
+
+    if(plci->Sig.Ind==NCR_FACILITY)           /* check controller broadcast */
+    {
+      for(j=0; j<max_appl; j++)
+      {
+        appl = &application[j];
+        if(Info_Number
+        && appl->Id
+        && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
+        {
+          iesent = TRUE;
+          dbug(1,dprintf("Mlt_NCR_Ind"));
+          sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
+        }
+      }
+    }
+    else if(!plci->appl && Info_Number)
+    {                                        /* overlap receiving broadcast */
+      for(j=0; j<max_appl; j++)
+      {
+        if(test_c_ind_mask_bit (plci, j))
+        {
+          iesent = TRUE;
+          dbug(1,dprintf("Mlt_Ovl_Ind"));
+          sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+        }
+      }
+    }                                        /* all other signalling states */
+    else if(Info_Number
+    && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
+    {
+      iesent = TRUE;
+      dbug(1,dprintf("Mlt_Std_Ind"));
+      sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+    }
+  }
+  return iesent;
+}
+
+void SendSSExtInd(APPL   * appl, PLCI   * plci, dword Id, byte   * * parms)
+{
+  word i;
+   /* Format of multi_ssext_parms[i][]:
+   0 byte length
+   1 byte SSEXTIE
+   2 byte SSEXT_REQ/SSEXT_IND
+   3 byte length
+   4 word SSExtCommand
+   6... Params
+   */
+  if(
+   plci
+   && plci->State
+   && plci->Sig.Ind!=NCR_FACILITY
+    )
+ for(i=0;i<MAX_MULTI_IE;i++)
+    {
+      if(parms[i][0]<6) continue;
+   if(parms[i][2]==SSEXT_REQ) continue;
+
+   if(appl)
+   {
+    parms[i][0]=0; /* kill it */
+    sendf(appl,_MANUFACTURER_I,
+    Id,
+    0,
+    "dwS",
+    _DI_MANU_ID,
+    _DI_SSEXT_CTRL,
+    &parms[i][3]);
+   }
+   else if(plci->appl)
+   {
+    parms[i][0]=0; /* kill it */
+    sendf(plci->appl,_MANUFACTURER_I,
+    Id,
+    0,
+    "dwS",
+    _DI_MANU_ID,
+    _DI_SSEXT_CTRL,
+    &parms[i][3]);
+   }
+    }
+};
+
+void nl_ind(PLCI   * plci)
+{
+  byte ch;
+  word ncci;
+  dword Id;
+  DIVA_CAPI_ADAPTER   * a;
+  word NCCIcode;
+  APPL   * APPLptr;
+  word count;
+  word Num;
+  word i, ncpi_state;
+  byte len, ncci_state;
+  word msg;
+  word info = 0;
+  word fax_feature_bits;
+  byte fax_send_edata_ack;
+  static byte v120_header_buffer[2 + 3];
+  static word fax_info[] = {
+    0,                     /* T30_SUCCESS                        */
+    _FAX_NO_CONNECTION,    /* T30_ERR_NO_DIS_RECEIVED            */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_NO_RESPONSE        */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_RESPONSE          */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TOO_MANY_REPEATS           */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_UNEXPECTED_MESSAGE         */
+    _FAX_REMOTE_ABORT,     /* T30_ERR_UNEXPECTED_DCN             */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_DTC_UNSUPPORTED            */
+    _FAX_TRAINING_ERROR,   /* T30_ERR_ALL_RATES_FAILED           */
+    _FAX_TRAINING_ERROR,   /* T30_ERR_TOO_MANY_TRAINS            */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_RECEIVE_CORRUPTED          */
+    _FAX_REMOTE_ABORT,     /* T30_ERR_UNEXPECTED_DISC            */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_APPLICATION_DISC           */
+    _FAX_REMOTE_REJECT,    /* T30_ERR_INCOMPATIBLE_DIS           */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_INCOMPATIBLE_DCS           */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_NO_COMMAND         */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_COMMAND           */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_COMMAND_TOO_LONG   */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_RESPONSE_TOO_LONG  */
+    _FAX_NO_CONNECTION,    /* T30_ERR_NOT_IDENTIFIED             */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_SUPERVISORY_TIMEOUT        */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_TOO_LONG_SCAN_LINE         */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_PAGE_AFTER_MPS    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_PAGE_AFTER_CFR    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCS_AFTER_FTT     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCS_AFTER_EOM     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCS_AFTER_MPS     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCN_AFTER_MCF     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCN_AFTER_RTN     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_CFR               */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_MCF_AFTER_EOP     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_MCF_AFTER_EOM     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_MCF_AFTER_MPS     */
+    0x331d,                /* T30_ERR_SUB_SEP_UNSUPPORTED        */
+    0x331e,                /* T30_ERR_PWD_UNSUPPORTED            */
+    0x331f,                /* T30_ERR_SUB_SEP_PWD_UNSUPPORTED    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_INVALID_COMMAND_FRAME      */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_UNSUPPORTED_PAGE_CODING    */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_INVALID_PAGE_CODING        */
+    _FAX_REMOTE_REJECT,    /* T30_ERR_INCOMPATIBLE_PAGE_CONFIG   */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_TIMEOUT_FROM_APPLICATION   */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_NO_REACTION_ON_MARK */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_TRAINING_TIMEOUT    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_UNEXPECTED_V21      */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_PRIMARY_CTS_ON      */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_V34FAX_TURNAROUND_POLLING  */
+    _FAX_LOCAL_ABORT       /* T30_ERR_V34FAX_V8_INCOMPATIBILITY  */
+  };
+
+    byte dtmf_code_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE + 1];
+
+
+  static word rtp_info[] = {
+    GOOD,                  /* RTP_SUCCESS                       */
+    0x3600                 /* RTP_ERR_SSRC_OR_PAYLOAD_CHANGE    */
+  };
+
+  static dword udata_forwarding_table[0x100 / sizeof(dword)] =
+  {
+    0x0020301e, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000
+  };
+
+  ch = plci->NL.IndCh;
+  a = plci->adapter;
+  ncci = a->ch_ncci[ch];
+  Id = (((dword)(ncci ? ncci : ch)) << 16) | (((word) plci->Id) << 8) | a->Id;
+  if(plci->tel) Id|=EXT_CONTROLLER;
+  APPLptr = plci->appl;
+  dbug(1,dprintf("NL_IND-Id(NL:0x%x)=0x%08lx,plci=%x,tel=%x,state=0x%x,ch=0x%x,chs=%d,Ind=%x",
+    plci->NL.Id,Id,plci->Id,plci->tel,plci->State,ch,plci->channels,plci->NL.Ind &0x0f));
+
+  /* in the case if no connect_active_Ind was sent to the appl we wait for */
+
+  if (plci->nl_remove_id)
+  {
+    plci->NL.RNR = 2; /* discard */
+    dbug(1,dprintf("NL discard while remove pending"));
+    return;
+  }
+  if((plci->NL.Ind &0x0f)==N_CONNECT)
+  {
+    if(plci->State==INC_DIS_PENDING
+    || plci->State==OUTG_DIS_PENDING
+    || plci->State==IDLE)
+    {
+      plci->NL.RNR = 2; /* discard */
+      dbug(1,dprintf("discard n_connect"));
+      return;
+    }
+    if(plci->State < INC_ACT_PENDING)
+    {
+      plci->NL.RNR = 1; /* flow control */
+      channel_x_off (plci, ch, N_XON_CONNECT_IND);
+      return;
+    }
+  }
+
+  if(!APPLptr)                         /* no application or invalid data */
+  {                                    /* while reloading the DSP        */
+    dbug(1,dprintf("discard1"));
+    plci->NL.RNR = 2;
+    return;
+  }
+
+  if (((plci->NL.Ind &0x0f) == N_UDATA)
+     && (((plci->B2_prot != B2_SDLC) && ((plci->B1_resource == 17) || (plci->B1_resource == 18)))
+        || (plci->B2_prot == 7)
+        || (plci->B3_prot == 7)) )
+  {
+    plci->ncpi_buffer[0] = 0;
+
+    ncpi_state = plci->ncpi_state;
+    if (plci->NL.complete == 1)
+    {
+      byte  * data = &plci->NL.RBuffer->P[0];
+
+      if ((plci->NL.RBuffer->length >= 12)
+        &&( (*data == DSP_UDATA_INDICATION_DCD_ON)
+          ||(*data == DSP_UDATA_INDICATION_CTS_ON)) )
+      {
+        word conn_opt, ncpi_opt = 0x00;
+//      HexDump ("MDM N_UDATA:", plci->NL.RBuffer->length, data);
+
+        if (*data == DSP_UDATA_INDICATION_DCD_ON)
+          plci->ncpi_state |= NCPI_MDM_DCD_ON_RECEIVED;
+        if (*data == DSP_UDATA_INDICATION_CTS_ON)
+          plci->ncpi_state |= NCPI_MDM_CTS_ON_RECEIVED;
+
+        data++;    /* indication code */
+        data += 2; /* timestamp */
+        if ((*data == DSP_CONNECTED_NORM_V18) || (*data == DSP_CONNECTED_NORM_VOWN))
+          ncpi_state &= ~(NCPI_MDM_DCD_ON_RECEIVED | NCPI_MDM_CTS_ON_RECEIVED);
+        data++;    /* connected norm */
+        conn_opt = READ_WORD(data);
+        data += 2; /* connected options */
+
+        WRITE_WORD (&(plci->ncpi_buffer[1]), (word)(READ_DWORD(data) & 0x0000FFFF));
+
+        if (conn_opt & DSP_CONNECTED_OPTION_MASK_V42)
+        {
+          ncpi_opt |= MDM_NCPI_ECM_V42;
+        }
+        else if (conn_opt & DSP_CONNECTED_OPTION_MASK_MNP)
+        {
+          ncpi_opt |= MDM_NCPI_ECM_MNP;
+        }
+        else
+        {
+          ncpi_opt |= MDM_NCPI_TRANSPARENT;
+        }
+        if (conn_opt & DSP_CONNECTED_OPTION_MASK_COMPRESSION)
+        {
+          ncpi_opt |= MDM_NCPI_COMPRESSED;
+        }
+        WRITE_WORD (&(plci->ncpi_buffer[3]), ncpi_opt);
+        plci->ncpi_buffer[0] = 4;
+
+        plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND | NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
+      }
+    }
+    if (plci->B3_prot == 7)
+    {
+      if (((a->ncci_state[ncci] == INC_ACT_PENDING) || (a->ncci_state[ncci] == OUTG_CON_PENDING))
+       && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+       && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+      {
+        a->ncci_state[ncci] = INC_ACT_PENDING;
+        sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+        plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+      }
+    }
+
+    if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+        & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
+     || !(ncpi_state & NCPI_MDM_DCD_ON_RECEIVED)
+     || !(ncpi_state & NCPI_MDM_CTS_ON_RECEIVED))
+
+    {
+      plci->NL.RNR = 2;
+      return;
+    }
+  }
+
+  if(plci->NL.complete == 2)
+    {
+    if (((plci->NL.Ind &0x0f) == N_UDATA)
+     && !(udata_forwarding_table[plci->RData[0].P[0] >> 5] & (1L << (plci->RData[0].P[0] & 0x1f))))
+    {
+      switch(plci->RData[0].P[0])
+      {
+
+      case DTMF_UDATA_INDICATION_FAX_CALLING_TONE:
+        if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
+          sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0,"ws", SELECTOR_DTMF, "\x01X");
+        break;
+      case DTMF_UDATA_INDICATION_ANSWER_TONE:
+        if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
+          sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0,"ws", SELECTOR_DTMF, "\x01Y");
+        break;
+      case DTMF_UDATA_INDICATION_DIGITS_RECEIVED:
+        dtmf_indication (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+      case DTMF_UDATA_INDICATION_DIGITS_SENT:
+        dtmf_confirmation (Id, plci);
+        break;
+
+
+      case UDATA_INDICATION_MIXER_TAP_DATA:
+        capidtmf_recv_process_block (&(plci->capidtmf_state), plci->RData[0].P + 1, (word)(plci->RData[0].PLength - 1));
+ i = capidtmf_indication (&(plci->capidtmf_state), dtmf_code_buffer + 1);
+ if (i != 0)
+ {
+   dtmf_code_buffer[0] = DTMF_UDATA_INDICATION_DIGITS_RECEIVED;
+          dtmf_indication (Id, plci, dtmf_code_buffer, (word)(i + 1));
+ }
+        break;
+
+
+      case UDATA_INDICATION_MIXER_COEFS_SET:
+        mixer_indication_coefs_set (Id, plci);
+        break;
+      case UDATA_INDICATION_XCONNECT_FROM:
+        mixer_indication_xconnect_from (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+      case UDATA_INDICATION_XCONNECT_TO:
+        mixer_indication_xconnect_to (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+
+
+      case LEC_UDATA_INDICATION_DISABLE_DETECT:
+        ec_indication (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+
+
+
+      default:
+        break;
+      }
+    }
+    else
+  {
+      if ((plci->RData[0].PLength != 0)
+     && ((plci->B2_prot == B2_V120_ASYNC)
+      || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
+      || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
+    {
+
+      sendf(plci->appl,_DATA_B3_I,Id,0,
+            "dwww",
+            plci->RData[1].P,
+              (plci->NL.RNum < 2) ? 0 : plci->RData[1].PLength,
+            plci->RNum,
+            plci->RFlags);
+
+    }
+    else
+    {
+
+      sendf(plci->appl,_DATA_B3_I,Id,0,
+            "dwww",
+            plci->RData[0].P,
+            plci->RData[0].PLength,
+            plci->RNum,
+            plci->RFlags);
+
+    }
+    }
+    return;
+  }
+
+  fax_feature_bits = 0;
+  if((plci->NL.Ind &0x0f)==N_CONNECT ||
+     (plci->NL.Ind &0x0f)==N_CONNECT_ACK ||
+     (plci->NL.Ind &0x0f)==N_DISC ||
+     (plci->NL.Ind &0x0f)==N_EDATA ||
+     (plci->NL.Ind &0x0f)==N_DISC_ACK)
+  {
+    info = 0;
+    plci->ncpi_buffer[0] = 0;
+    switch (plci->B3_prot) {
+    case  0: /*XPARENT*/
+    case  1: /*T.90 NL*/
+      break;    /* no network control protocol info - jfr */
+    case  2: /*ISO8202*/
+    case  3: /*X25 DCE*/
+      for(i=0; i<plci->NL.RLength; i++) plci->ncpi_buffer[4+i] = plci->NL.RBuffer->P[i];
+      plci->ncpi_buffer[0] = (byte)(i+3);
+      plci->ncpi_buffer[1] = (byte)(plci->NL.Ind &N_D_BIT? 1:0);
+      plci->ncpi_buffer[2] = 0;
+      plci->ncpi_buffer[3] = 0;
+      break;
+    case  4: /*T.30 - FAX*/
+    case  5: /*T.30 - FAX*/
+      if(plci->NL.RLength>=sizeof(T30_INFO))
+      {
+        dbug(1,dprintf("FaxStatus %04x", ((T30_INFO   *)plci->NL.RBuffer->P)->code));
+        len = 9;
+        WRITE_WORD(&(plci->ncpi_buffer[1]),((T30_INFO   *)plci->NL.RBuffer->P)->rate_div_2400 * 2400);
+        fax_feature_bits = READ_WORD(&((T30_INFO   *)plci->NL.RBuffer->P)->feature_bits_low);
+        i = (((T30_INFO   *)plci->NL.RBuffer->P)->resolution & T30_RESOLUTION_R8_0770_OR_200) ? 0x0001 : 0x0000;
+        if (plci->B3_prot == 5)
+        {
+          if (!(fax_feature_bits & T30_FEATURE_BIT_ECM))
+            i |= 0x8000; /* This is not an ECM connection */
+          if (fax_feature_bits & T30_FEATURE_BIT_T6_CODING)
+            i |= 0x4000; /* This is a connection with MMR compression */
+          if (fax_feature_bits & T30_FEATURE_BIT_2D_CODING)
+            i |= 0x2000; /* This is a connection with MR compression */
+          if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
+            i |= 0x0004; /* More documents */
+          if (fax_feature_bits & T30_FEATURE_BIT_POLLING)
+            i |= 0x0002; /* Fax-polling indication */
+        }
+        dbug(1,dprintf("FAX Options %04x %04x",fax_feature_bits,i));
+        WRITE_WORD(&(plci->ncpi_buffer[3]),i);
+        WRITE_WORD(&(plci->ncpi_buffer[5]),((T30_INFO   *)plci->NL.RBuffer->P)->data_format);
+        plci->ncpi_buffer[7] = ((T30_INFO   *)plci->NL.RBuffer->P)->pages_low;
+        plci->ncpi_buffer[8] = ((T30_INFO   *)plci->NL.RBuffer->P)->pages_high;
+        plci->ncpi_buffer[len] = 0;
+        if(((T30_INFO   *)plci->NL.RBuffer->P)->station_id_len)
+        {
+          plci->ncpi_buffer[len] = 20;
+          for (i = 0; i < 20; i++)
+            plci->ncpi_buffer[++len] = ((T30_INFO   *)plci->NL.RBuffer->P)->station_id[i];
+        }
+        if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
+        {
+          if (((T30_INFO   *)plci->NL.RBuffer->P)->code < sizeof(fax_info) / sizeof(fax_info[0]))
+            info = fax_info[((T30_INFO   *)plci->NL.RBuffer->P)->code];
+          else
+            info = _FAX_PROTOCOL_ERROR;
+        }
+
+        if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
+          & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+        {
+          i = ((word)(((T30_INFO *) 0)->station_id + 20)) + ((T30_INFO   *)plci->NL.RBuffer->P)->head_line_len;
+          while (i < plci->NL.RBuffer->length)
+            plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++];
+        }
+
+        plci->ncpi_buffer[0] = len;
+        fax_feature_bits = READ_WORD(&((T30_INFO   *)plci->NL.RBuffer->P)->feature_bits_low);
+        WRITE_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->feature_bits_low, fax_feature_bits);
+
+        plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND;
+ if (((plci->NL.Ind &0x0f) == N_CONNECT_ACK)
+         || (((plci->NL.Ind &0x0f) == N_CONNECT)
+          && (fax_feature_bits & T30_FEATURE_BIT_POLLING))
+         || (((plci->NL.Ind &0x0f) == N_EDATA)
+          && ((((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_TRAIN_OK)
+           || (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
+           || (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_DTC))))
+ {
+          plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT;
+ }
+ if (((plci->NL.Ind &0x0f) == N_DISC)
+  || ((plci->NL.Ind &0x0f) == N_DISC_ACK)
+  || (((plci->NL.Ind &0x0f) == N_EDATA)
+   && (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_EOP_CAPI)))
+ {
+          plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
+ }
+      }
+      break;
+
+    case B3_RTP:
+      if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
+      {
+        if (plci->NL.RLength != 0)
+        {
+          info = rtp_info[plci->NL.RBuffer->P[0]];
+          plci->ncpi_buffer[0] = plci->NL.RLength - 1;
+          for (i = 1; i < plci->NL.RLength; i++)
+            plci->ncpi_buffer[i] = plci->NL.RBuffer->P[i];
+        }
+      }
+      break;
+
+    }
+    plci->NL.RNR = 2;
+  }
+  switch(plci->NL.Ind &0x0f) {
+  case N_EDATA:
+    if ((plci->B3_prot == 4) || (plci->B3_prot == 5))
+    {
+      dbug(1,dprintf("EDATA ncci=0x%x state=%d code=%02x", ncci, a->ncci_state[ncci],
+        ((T30_INFO   *)plci->NL.RBuffer->P)->code));
+      fax_send_edata_ack = (((T30_INFO   *)(plci->fax_connect_info_buffer))->operating_mode == T30_OPERATING_MODE_CAPI_NEG);
+
+      if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
+       && (plci->nsf_control_bits & (T30_NSF_CONTROL_BIT_NEGOTIATE_IND | T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
+       && (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
+       && (a->ncci_state[ncci] == OUTG_CON_PENDING)
+       && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+       && !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
+      {
+        ((T30_INFO   *)(plci->fax_connect_info_buffer))->code = ((T30_INFO   *)plci->NL.RBuffer->P)->code;
+        sendf(plci->appl,_MANUFACTURER_I,Id,0,"dwbS",_DI_MANU_ID,_DI_NEGOTIATE_B3,
+          (byte)(plci->ncpi_buffer[0] + 1), plci->ncpi_buffer);
+        plci->ncpi_state |= NCPI_NEGOTIATE_B3_SENT;
+ if (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)
+   fax_send_edata_ack = FALSE;
+      }
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+      {
+        switch (((T30_INFO   *)plci->NL.RBuffer->P)->code)
+        {
+        case EDATA_T30_DIS:
+          if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
+           && !(READ_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low) & T30_CONTROL_BIT_REQUEST_POLLING)
+           && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+           && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+          {
+            a->ncci_state[ncci] = INC_ACT_PENDING;
+            if (plci->B3_prot == 4)
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+            else
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+            plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+          }
+          break;
+
+        case EDATA_T30_TRAIN_OK:
+          if ((a->ncci_state[ncci] == INC_ACT_PENDING)
+           && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+           && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+          {
+            if (plci->B3_prot == 4)
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+            else
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+            plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+          }
+          break;
+
+        case EDATA_T30_EOP_CAPI:
+          if (a->ncci_state[ncci] == CONNECTED)
+          {
+            sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",GOOD,plci->ncpi_buffer);
+            a->ncci_state[ncci] = INC_DIS_PENDING;
+            plci->ncpi_state = 0;
+     fax_send_edata_ack = FALSE;
+          }
+          break;
+        }
+      }
+      else
+      {
+        switch (((T30_INFO   *)plci->NL.RBuffer->P)->code)
+        {
+        case EDATA_T30_TRAIN_OK:
+          if ((a->ncci_state[ncci] == INC_ACT_PENDING)
+           && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+           && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+          {
+            if (plci->B3_prot == 4)
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+            else
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+            plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+          }
+          break;
+        }
+      }
+      if (fax_send_edata_ack)
+      {
+        ((T30_INFO   *)(plci->fax_connect_info_buffer))->code = ((T30_INFO   *)plci->NL.RBuffer->P)->code;
+ plci->fax_edata_ack_length = 1;
+        start_internal_command (Id, plci, fax_edata_ack_command);
+      }
+    }
+    else
+    {
+      dbug(1,dprintf("EDATA ncci=0x%x state=%d", ncci, a->ncci_state[ncci]));
+    }
+    break;
+  case N_CONNECT:
+    if (!a->ch_ncci[ch])
+    {
+      ncci = get_ncci (plci, ch, 0);
+      Id = (Id & 0xffff) | (((dword) ncci) << 16);
+    }
+    dbug(1,dprintf("N_CONNECT: ch=%d state=%d plci=%lx plci_Id=%lx plci_State=%d",
+      ch, a->ncci_state[ncci], a->ncci_plci[ncci], plci->Id, plci->State));
+
+    msg = _CONNECT_B3_I;
+    if (a->ncci_state[ncci] == IDLE)
+      plci->channels++;
+    else if (plci->B3_prot == 1)
+      msg = _CONNECT_B3_T90_ACTIVE_I;
+
+    a->ncci_state[ncci] = INC_CON_PENDING;
+    if(plci->B3_prot == 4)
+      sendf(plci->appl,msg,Id,0,"s","");
+    else
+      sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+    break;
+  case N_CONNECT_ACK:
+    dbug(1,dprintf("N_connect_Ack"));
+    if (plci->internal_command_queue[0]
+     && ((plci->adjust_b_state == ADJUST_B_CONNECT_2)
+      || (plci->adjust_b_state == ADJUST_B_CONNECT_3)
+      || (plci->adjust_b_state == ADJUST_B_CONNECT_4)))
+    {
+      (*(plci->internal_command_queue[0]))(Id, plci, 0);
+      if (!plci->internal_command)
+        next_internal_command (Id, plci);
+      break;
+    }
+    msg = _CONNECT_B3_ACTIVE_I;
+    if (plci->B3_prot == 1)
+    {
+      if (a->ncci_state[ncci] != OUTG_CON_PENDING)
+        msg = _CONNECT_B3_T90_ACTIVE_I;
+      a->ncci_state[ncci] = INC_ACT_PENDING;
+      sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+    }
+    else if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
+    {
+      if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
+       && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+       && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+      {
+        a->ncci_state[ncci] = INC_ACT_PENDING;
+        if (plci->B3_prot == 4)
+          sendf(plci->appl,msg,Id,0,"s","");
+        else
+          sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+        plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+      }
+    }
+    else
+    {
+      a->ncci_state[ncci] = INC_ACT_PENDING;
+      sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+    }
+    if (plci->adjust_b_restore)
+    {
+      plci->adjust_b_restore = FALSE;
+      start_internal_command (Id, plci, adjust_b_restore);
+    }
+    break;
+  case N_DISC:
+  case N_DISC_ACK:
+    if (plci->internal_command_queue[0]
+     && ((plci->internal_command == FAX_DISCONNECT_COMMAND_1)
+      || (plci->internal_command == FAX_DISCONNECT_COMMAND_2)
+      || (plci->internal_command == FAX_DISCONNECT_COMMAND_3)))
+    {
+      (*(plci->internal_command_queue[0]))(Id, plci, 0);
+      if (!plci->internal_command)
+        next_internal_command (Id, plci);
+    }
+    ncci_state = a->ncci_state[ncci];
+    ncci_remove (plci, ncci, FALSE);
+
+        /* with N_DISC or N_DISC_ACK the IDI frees the respective   */
+        /* channel, so we cannot store the state in ncci_state! The */
+        /* information which channel we received a N_DISC is thus   */
+        /* stored in the inc_dis_ncci_table buffer.                 */
+    for(i=0; plci->inc_dis_ncci_table[i]; i++);
+    plci->inc_dis_ncci_table[i] = (byte) ncci;
+
+      /* need a connect_b3_ind before a disconnect_b3_ind with FAX */
+    if (!plci->channels
+     && (plci->B1_resource == 16)
+     && (plci->State <= CONNECTED))
+    {
+      len = 9;
+      i = ((T30_INFO   *)plci->fax_connect_info_buffer)->rate_div_2400 * 2400;
+      WRITE_WORD (&plci->ncpi_buffer[1], i);
+      WRITE_WORD (&plci->ncpi_buffer[3], 0);
+      i = ((T30_INFO   *)plci->fax_connect_info_buffer)->data_format;
+      WRITE_WORD (&plci->ncpi_buffer[5], i);
+      WRITE_WORD (&plci->ncpi_buffer[7], 0);
+      plci->ncpi_buffer[len] = 0;
+      plci->ncpi_buffer[0] = len;
+      if(plci->B3_prot == 4)
+        sendf(plci->appl,_CONNECT_B3_I,Id,0,"s","");
+      else
+      {
+
+        if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
+          & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+        {
+          plci->ncpi_buffer[++len] = 0;
+          plci->ncpi_buffer[++len] = 0;
+          plci->ncpi_buffer[++len] = 0;
+          plci->ncpi_buffer[0] = len;
+        }
+
+        sendf(plci->appl,_CONNECT_B3_I,Id,0,"S",plci->ncpi_buffer);
+      }
+      sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",info,plci->ncpi_buffer);
+      plci->ncpi_state = 0;
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+      plci->State = OUTG_DIS_PENDING;
+      /* disc here */
+    }
+    else if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+     && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
+     && ((ncci_state == INC_DIS_PENDING) || (ncci_state == IDLE)))
+    {
+      if (ncci_state == IDLE)
+      {
+        if (plci->channels)
+          plci->channels--;
+        if((plci->State==IDLE || plci->State==SUSPENDING) && !plci->channels){
+          if(plci->State == SUSPENDING){
+            sendf(plci->appl,
+                  _FACILITY_I,
+                  Id & 0xffffL,
+                  0,
+                  "ws", (word)3, "\x03\x04\x00\x00");
+            sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
+          }
+          plci_remove(plci);
+          plci->State=IDLE;
+        }
+      }
+    }
+    else if (plci->channels)
+    {
+      sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",info,plci->ncpi_buffer);
+      plci->ncpi_state = 0;
+      if ((ncci_state == OUTG_REJ_PENDING)
+       && ((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE)))
+      {
+        sig_req(plci,HANGUP,0);
+        send_req(plci);
+        plci->State = OUTG_DIS_PENDING;
+      }
+    }
+    break;
+  case N_RESET:
+    a->ncci_state[ncci] = INC_RES_PENDING;
+    sendf(plci->appl,_RESET_B3_I,Id,0,"S",plci->ncpi_buffer);
+    break;
+  case N_RESET_ACK:
+    a->ncci_state[ncci] = CONNECTED;
+    sendf(plci->appl,_RESET_B3_I,Id,0,"S",plci->ncpi_buffer);
+    break;
+
+  case N_UDATA:
+    if (!(udata_forwarding_table[plci->NL.RBuffer->P[0] >> 5] & (1L << (plci->NL.RBuffer->P[0] & 0x1f))))
+    {
+      plci->RData[0].P = plci->internal_ind_buffer + (-((int)(plci->internal_ind_buffer)) & 3);
+      plci->RData[0].PLength = INTERNAL_IND_BUFFER_SIZE;
+      plci->NL.R = plci->RData;
+      plci->NL.RNum = 1;
+      return;
+    }
+  case N_BDATA:
+  case N_DATA:
+    if (((a->ncci_state[ncci] != CONNECTED) && (plci->B2_prot == 1)) /* transparent */
+     || (a->ncci_state[ncci] == IDLE)
+     || (a->ncci_state[ncci] == INC_DIS_PENDING))
+    {
+      plci->NL.RNR = 2;
+      break;
+    }
+    if ((a->ncci_state[ncci] != CONNECTED)
+     && (a->ncci_state[ncci] != OUTG_DIS_PENDING)
+     && (a->ncci_state[ncci] != OUTG_REJ_PENDING))
+    {
+      dbug(1,dprintf("flow control"));
+      plci->NL.RNR = 1; /* flow control  */
+      channel_x_off (plci, ch, 0);
+      break;
+    }
+
+    NCCIcode = ncci | (((word)a->Id) << 8);
+
+                /* count all buffers within the Application pool    */
+                /* belonging to the same NCCI. If this is below the */
+                /* number of buffers available per NCCI we accept   */
+                /* this packet, otherwise we reject it              */
+    count = 0;
+    Num = 0xffff;
+    for(i=0; i<APPLptr->MaxBuffer; i++) {
+      if(NCCIcode==APPLptr->DataNCCI[i]) count++;
+      if(!APPLptr->DataNCCI[i] && Num==0xffff) Num = i;
+    }
+
+    if(count>=APPLptr->MaxNCCIData || Num==0xffff)
+    {
+      dbug(3,dprintf("Flow-Control"));
+      plci->NL.RNR = 1;
+      if( ++(APPLptr->NCCIDataFlowCtrlTimer)>=
+       (word)((a->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL) ? 40 : 2000))
+      {
+        plci->NL.RNR = 2;
+        dbug(3,dprintf("DiscardData"));
+      } else {
+        channel_x_off (plci, ch, 0);
+      }
+      break;
+    }
+    else
+    {
+      APPLptr->NCCIDataFlowCtrlTimer = 0;
+    }
+
+    plci->RData[0].P = ReceiveBufferGet(APPLptr,Num);
+    if(!plci->RData[0].P) {
+      plci->NL.RNR = 1;
+      channel_x_off (plci, ch, 0);
+      break;
+    }
+
+    APPLptr->DataNCCI[Num] = NCCIcode;
+    APPLptr->DataFlags[Num] = (plci->Id<<8) | (plci->NL.Ind>>4);
+    dbug(3,dprintf("Buffer(%d), Max = %d",Num,APPLptr->MaxBuffer));
+
+    plci->RNum = Num;
+    plci->RFlags = plci->NL.Ind>>4;
+    plci->RData[0].PLength = APPLptr->MaxDataLength;
+    plci->NL.R = plci->RData;
+    if ((plci->NL.RLength != 0)
+     && ((plci->B2_prot == B2_V120_ASYNC)
+      || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
+      || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
+    {
+      plci->RData[1].P = plci->RData[0].P;
+      plci->RData[1].PLength = plci->RData[0].PLength;
+      plci->RData[0].P = v120_header_buffer + (-((int) v120_header_buffer) & 3);
+      if ((plci->NL.RBuffer->P[0] & V120_HEADER_EXTEND_BIT) || (plci->NL.RLength == 1))
+        plci->RData[0].PLength = 1;
+      else
+        plci->RData[0].PLength = 2;
+      if (plci->NL.RBuffer->P[0] & V120_HEADER_BREAK_BIT)
+        plci->RFlags |= 0x0010;
+      if (plci->NL.RBuffer->P[0] & (V120_HEADER_C1_BIT | V120_HEADER_C2_BIT))
+        plci->RFlags |= 0x8000;
+      plci->NL.RNum = 2;
+    }
+    else
+    {
+      if((plci->NL.Ind &0x0f)==N_UDATA)
+        plci->RFlags |= 0x0010;
+
+      else if ((plci->B3_prot == B3_RTP) && ((plci->NL.Ind & 0x0f) == N_BDATA))
+        plci->RFlags |= 0x0001;
+
+      plci->NL.RNum = 1;
+    }
+    break;
+  case N_DATA_ACK:
+    data_ack (plci, ch);
+    break;
+  default:
+    plci->NL.RNR = 2;
+    break;
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* find a free PLCI                                                 */
+/*------------------------------------------------------------------*/
+
+word get_plci(DIVA_CAPI_ADAPTER   * a)
+{
+  word i,j;
+  PLCI   * plci;
+
+  dump_plcis (a);
+  for(i=0;i<a->max_plci && a->plci[i].Id;i++);
+  if(i==a->max_plci) {
+    dbug(1,dprintf("get_plci: out of PLCIs"));
+    return 0;
+  }
+  plci = &a->plci[i];
+  plci->Id = (byte)(i+1);
+
+  plci->Sig.Id = 0;
+  plci->NL.Id = 0;
+  plci->sig_req = 0;
+  plci->nl_req = 0;
+
+  plci->appl = 0;
+  plci->relatedPTYPLCI = 0;
+  plci->State = IDLE;
+  plci->SuppState = IDLE;
+  plci->channels = 0;
+  plci->tel = 0;
+  plci->B1_resource = 0;
+  plci->B2_prot = 0;
+  plci->B3_prot = 0;
+
+  plci->command = 0;
+  plci->m_command = 0;
+  init_internal_command_queue (plci);
+  plci->number = 0;
+  plci->req_in_start = 0;
+  plci->req_in = 0;
+  plci->req_out = 0;
+  plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+
+  plci->data_sent = FALSE;
+  plci->send_disc = 0;
+  plci->sig_global_req = 0;
+  plci->sig_remove_id = 0;
+  plci->nl_global_req = 0;
+  plci->nl_remove_id = 0;
+  plci->adv_nl = 0;
+  plci->manufacturer = FALSE;
+  plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+  plci->spoofed_msg = 0;
+  plci->ptyState = 0;
+  plci->cr_enquiry = FALSE;
+  plci->hangup_flow_ctrl_timer = 0;
+
+  plci->ncci_ring_list = 0;
+  for(j=0;j<MAX_CHANNELS_PER_PLCI;j++) plci->inc_dis_ncci_table[j] = 0;
+  clear_c_ind_mask (plci);
+  set_group_ind_mask (plci);
+  plci->fax_connect_info_length = 0;
+  plci->nsf_control_bits = 0;
+  plci->ncpi_state = 0x00;
+  plci->ncpi_buffer[0] = 0;
+
+  plci->requested_options_conn = 0;
+  plci->requested_options = 0;
+  plci->notifiedcall = 0;
+  plci->vswitchstate = 0;
+  plci->vsprot = 0;
+  plci->vsprotdialect = 0;
+  init_b1_config (plci);
+  dbug(1,dprintf("get_plci(%x)",plci->Id));
+  return i+1;
+}
+
+/*------------------------------------------------------------------*/
+/* put a parameter in the parameter buffer                          */
+/*------------------------------------------------------------------*/
+
+static void add_p(PLCI   * plci, byte code, byte   * p)
+{
+  word p_length;
+
+  p_length = 0;
+  if(p) p_length = p[0];
+  add_ie(plci, code, p, p_length);
+}
+
+/*------------------------------------------------------------------*/
+/* put a structure in the parameter buffer                          */
+/*------------------------------------------------------------------*/
+static void add_s(PLCI   * plci, byte code, API_PARSE * p)
+{
+  if(p) add_ie(plci, code, p->info, (word)p->length);
+}
+
+/*------------------------------------------------------------------*/
+/* put multiple structures in the parameter buffer                  */
+/*------------------------------------------------------------------*/
+static void add_ss(PLCI   * plci, byte code, API_PARSE * p)
+{
+  byte i;
+
+  if(p){
+    dbug(1,dprintf("add_ss(%x,len=%d)",code,p->length));
+    for(i=2;i<(byte)p->length;i+=p->info[i]+2){
+      dbug(1,dprintf("add_ss_ie(%x,len=%d)",p->info[i-1],p->info[i]));
+      add_ie(plci, p->info[i-1], (byte   *)&(p->info[i]), (word)p->info[i]);
+    }
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* return the channel number sent by the application in a esc_chi   */
+/*------------------------------------------------------------------*/
+static byte getChannel(API_PARSE * p)
+{
+  byte i;
+
+  if(p){
+    for(i=2;i<(byte)p->length;i+=p->info[i]+2){
+      if(p->info[i]==2){
+        if(p->info[i-1]==ESC && p->info[i+1]==CHI) return (p->info[i+2]);
+      }
+    }
+  }
+  return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* put an information element in the parameter buffer               */
+/*------------------------------------------------------------------*/
+
+static void add_ie(PLCI   * plci, byte code, byte   * p, word p_length)
+{
+  word i;
+
+  if(!(code &0x80) && !p_length) return;
+
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+  }
+  else {
+    plci->req_in--;
+  }
+  plci->RBuffer[plci->req_in++] = code;
+
+  if(p) {
+    plci->RBuffer[plci->req_in++] = (byte)p_length;
+    for(i=0;i<p_length;i++) plci->RBuffer[plci->req_in++] = p[1+i];
+  }
+
+  plci->RBuffer[plci->req_in++] = 0;
+}
+
+/*------------------------------------------------------------------*/
+/* put a unstructured data into the buffer                          */
+/*------------------------------------------------------------------*/
+
+void add_d(PLCI   * plci, word length, byte   * p)
+{
+  word i;
+
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+  }
+  else {
+    plci->req_in--;
+  }
+  for(i=0;i<length;i++) plci->RBuffer[plci->req_in++] = p[i];
+}
+
+/*------------------------------------------------------------------*/
+/* put parameters from the Additional Info parameter in the         */
+/* parameter buffer                                                 */
+/*------------------------------------------------------------------*/
+
+void add_ai(PLCI   * plci, API_PARSE * ai)
+{
+  word i;
+    API_PARSE ai_parms[5];
+
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+
+  if(!ai->length)
+    return;
+  if(api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms))
+    return;
+
+  add_s (plci,KEY,&ai_parms[1]);
+  add_s (plci,UUI,&ai_parms[2]);
+  add_ss(plci,FTY,&ai_parms[3]);
+}
+
+/*------------------------------------------------------------------*/
+/* put parameter for b1 protocol in the parameter buffer            */
+/*------------------------------------------------------------------*/
+
+word add_b1(PLCI   * plci, API_PARSE * bp, word b_channel_info, word b1_facilities)
+{
+    API_PARSE bp_parms[8];
+    API_PARSE mdm_cfg[9];
+    API_PARSE global_config[2];
+    byte cai[256];
+  byte resource[] = {5,9,13,12,16,39,9,17,17,18};
+  byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08";
+  word i;
+
+    API_PARSE mdm_cfg_v18[4];
+  word j, n, w;
+  dword d;
+
+
+  for(i=0;i<8;i++) bp_parms[i].length = 0;
+  for(i=0;i<2;i++) global_config[i].length = 0;
+
+  dbug(1,dprintf("add_b1"));
+  api_save_msg(bp, "s", &plci->B_protocol);
+
+  if(b_channel_info==2){
+    plci->B1_resource = 0;
+    adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
+    add_p(plci, CAI, "\x01\x00");
+    dbug(1,dprintf("Cai=1,0 (no resource)"));
+    return 0;
+  }
+
+  if(plci->tel == CODEC_PERMANENT) return 0;
+  else if(plci->tel == CODEC){
+    plci->B1_resource = 1;
+    adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
+    add_p(plci, CAI, "\x01\x01");
+    dbug(1,dprintf("Cai=1,1 (Codec)"));
+    return 0;
+  }
+  else if(plci->tel == ADV_VOICE){
+    plci->B1_resource = add_b1_facilities (plci, 9, (word)(b1_facilities | B1_FACILITY_VOICE));
+    adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities | B1_FACILITY_VOICE));
+    voice_cai[1] = plci->B1_resource;
+    WRITE_WORD (&voice_cai[5], plci->appl->MaxDataLength);
+    add_p(plci, CAI, voice_cai);
+    dbug(1,dprintf("Cai=1,0x%x (AdvVoice)",voice_cai[1]));
+    return 0;
+  }
+  plci->call_dir &= ~(CALL_DIR_ORIGINATE | CALL_DIR_ANSWER);
+  if (plci->call_dir & CALL_DIR_OUT)
+    plci->call_dir |= CALL_DIR_ORIGINATE;
+  else if (plci->call_dir & CALL_DIR_IN)
+    plci->call_dir |= CALL_DIR_ANSWER;
+
+  if(!bp->length){
+    plci->B1_resource = 0x5;
+    adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
+    add_p(plci, CAI, "\x01\x05");
+    return 0;
+  }
+
+  dbug(1,dprintf("b_prot_len=%d",(word)bp->length));
+  if(bp->length>256) return _WRONG_MESSAGE_FORMAT;
+  if(api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
+  {
+    bp_parms[6].length = 0;
+    if(api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
+    {
+      dbug(1,dprintf("b-form.!"));
+      return _WRONG_MESSAGE_FORMAT;
+    }
+  }
+  else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
+  {
+    dbug(1,dprintf("b-form.!"));
+    return _WRONG_MESSAGE_FORMAT;
+  }
+
+  if(bp_parms[6].length)
+  {
+    if(api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
+    {
+      return _WRONG_MESSAGE_FORMAT;
+    }
+    switch(READ_WORD(global_config[0].info))
+    {
+    case 1:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
+      break;
+    case 2:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
+      break;
+    }
+  }
+  dbug(1,dprintf("call_dir=%04x", plci->call_dir));
+
+
+  if ((READ_WORD(bp_parms[0].info) == B1_RTP)
+   && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
+  {
+    plci->B1_resource = add_b1_facilities (plci, 31, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    cai[1] = plci->B1_resource;
+    cai[2] = 0;
+    cai[3] = 0;
+    cai[4] = 0;
+    WRITE_WORD(&cai[5],plci->appl->MaxDataLength);
+    for (i = 0; i < bp_parms[3].length; i++)
+      cai[7+i] = bp_parms[3].info[1+i];
+    cai[0] = 6 + bp_parms[3].length;
+    add_p(plci, CAI, cai);
+    return 0;
+  }
+
+
+  if ((READ_WORD(bp_parms[0].info) == B1_PIAFS)
+   && (plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))
+  {
+    plci->B1_resource = add_b1_facilities (plci, 35/* PIAFS HARDWARE FACILITY */, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    cai[1] = plci->B1_resource;
+    cai[2] = 0;
+    cai[3] = 0;
+    cai[4] = 0;
+    WRITE_WORD(&cai[5],plci->appl->MaxDataLength);
+    cai[0] = 6;
+    add_p(plci, CAI, cai);
+    return 0;
+  }
+
+
+  if ((READ_WORD(bp_parms[0].info) >= 32)
+   || (!((1L << READ_WORD(bp_parms[0].info)) & plci->adapter->profile.B1_Protocols)
+    && ((READ_WORD(bp_parms[0].info) != 3)
+     || !((1L << B1_HDLC) & plci->adapter->profile.B1_Protocols)
+     || ((bp_parms[3].length != 0) && (READ_WORD(&bp_parms[3].info[1]) != 0) && (READ_WORD(&bp_parms[3].info[1]) != 56000)))))
+  {
+    return _B1_NOT_SUPPORTED;
+  }
+  plci->B1_resource = add_b1_facilities (plci, resource[READ_WORD(bp_parms[0].info)],
+    (word)(b1_facilities & ~B1_FACILITY_VOICE));
+  adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+  cai[0] = 6;
+  cai[1] = plci->B1_resource;
+  for (i=2;i<sizeof(cai);i++) cai[i] = 0;
+
+  if ((READ_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
+   || (READ_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
+   || (READ_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC))
+  { /* B1 - modem */
+    for (i=0;i<7;i++) mdm_cfg[i].length = 0;
+
+    if (bp_parms[3].length)
+    {
+      if(api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwww", mdm_cfg))
+      {
+        return (_WRONG_MESSAGE_FORMAT);
+      }
+        
+      cai[2] = 0; /* Bit rate for adaptation */
+
+      dbug(1,dprintf("MDM Max Bit Rate:<%d>", READ_WORD(mdm_cfg[0].info)));
+
+      WRITE_WORD (&cai[13], 0);                          /* Min Tx speed */
+      WRITE_WORD (&cai[15], READ_WORD(mdm_cfg[0].info)); /* Max Tx speed */
+      WRITE_WORD (&cai[17], 0);                          /* Min Rx speed */
+      WRITE_WORD (&cai[19], READ_WORD(mdm_cfg[0].info)); /* Max Rx speed */
+
+      cai[3] = 0; /* Async framing parameters */
+      switch (READ_WORD (mdm_cfg[2].info))
+      {       /* Parity     */
+      case 1: /* odd parity */
+        cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
+        dbug(1,dprintf("MDM: odd parity"));
+        break;
+
+      case 2: /* even parity */
+        cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
+        dbug(1,dprintf("MDM: even parity"));
+        break;
+
+      default:
+        dbug(1,dprintf("MDM: no parity"));
+        break;
+      }
+
+      switch (READ_WORD (mdm_cfg[3].info))
+      {       /* stop bits   */
+      case 1: /* 2 stop bits */
+        cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
+        dbug(1,dprintf("MDM: 2 stop bits"));
+        break;
+
+      default:
+        dbug(1,dprintf("MDM: 1 stop bit"));
+        break;
+      }
+
+      switch (READ_WORD (mdm_cfg[1].info))
+      {     /* char length */
+      case 5:
+        cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
+        dbug(1,dprintf("MDM: 5 bits"));
+        break;
+
+      case 6:
+        cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
+        dbug(1,dprintf("MDM: 6 bits"));
+        break;
+
+      case 7:
+        cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
+        dbug(1,dprintf("MDM: 7 bits"));
+        break;
+
+      default:
+        dbug(1,dprintf("MDM: 8 bits"));
+        break;
+      }
+
+      cai[7] = 0; /* Line taking options */
+      cai[8] = 0; /* Modulation negotiation options */
+      cai[9] = 0; /* Modulation options */
+
+      if (((plci->call_dir & CALL_DIR_ORIGINATE) != 0) ^ ((plci->call_dir & CALL_DIR_OUT) != 0))
+      {
+        cai[9] |= DSP_CAI_MODEM_REVERSE_DIRECTION;
+        dbug(1, dprintf("MDM: Reverse direction"));
+      }
+
+      if (READ_WORD (mdm_cfg[4].info) & MDM_CAPI_DISABLE_RETRAIN)
+      {
+        cai[9] |= DSP_CAI_MODEM_DISABLE_RETRAIN;
+        dbug(1, dprintf("MDM: Disable retrain"));
+      }
+
+      if (READ_WORD (mdm_cfg[4].info) & MDM_CAPI_DISABLE_RING_TONE)
+      {
+        cai[7] |= DSP_CAI_MODEM_DISABLE_CALLING_TONE | DSP_CAI_MODEM_DISABLE_ANSWER_TONE;
+        dbug(1, dprintf("MDM: Disable ring tone"));
+      }
+
+      if (READ_WORD (mdm_cfg[4].info) & MDM_CAPI_GUARD_1800)
+      {
+        cai[8] |= DSP_CAI_MODEM_GUARD_TONE_1800HZ;
+        dbug(1, dprintf("MDM: 1800 guard tone"));
+      }
+      else if (READ_WORD (mdm_cfg[4].info) & MDM_CAPI_GUARD_550 )
+      {
+        cai[8] |= DSP_CAI_MODEM_GUARD_TONE_550HZ;
+        dbug(1, dprintf("MDM: 550 guard tone"));
+      }
+
+      if ((READ_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_V100)
+      {
+        cai[8] |= DSP_CAI_MODEM_NEGOTIATE_V100;
+        dbug(1, dprintf("MDM: V100"));
+      }
+      else if ((READ_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_MOD_CLASS)
+      {
+        cai[8] |= DSP_CAI_MODEM_NEGOTIATE_IN_CLASS;
+        dbug(1, dprintf("MDM: IN CLASS"));
+      }
+      else if ((READ_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_DISABLED)
+      {
+        cai[8] |= DSP_CAI_MODEM_NEGOTIATE_DISABLED;
+        dbug(1, dprintf("MDM: DISABLED"));
+      }
+      cai[0] = 20;
+
+      if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_V18))
+       && (READ_WORD(mdm_cfg[5].info) & 0x8000)) /* Private V.18 enable */
+      {
+        plci->requested_options |= 1L << PRIVATE_V18;
+      }
+      if (READ_WORD(mdm_cfg[5].info) & 0x4000) /* Private VOWN enable */
+        plci->requested_options |= 1L << PRIVATE_VOWN;
+
+      if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+        & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
+      {
+        if (!api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwwws", mdm_cfg))
+        {
+          i = 27;
+          if (mdm_cfg[6].length >= 4)
+          {
+            d = READ_DWORD(&mdm_cfg[6].info[1]);
+            cai[7] |= (byte) d;          /* line taking options */
+            cai[9] |= (byte)(d >> 8);    /* modulation options */
+            cai[++i] = (byte)(d >> 16);  /* vown modulation options */
+            cai[++i] = (byte)(d >> 24);
+            if (mdm_cfg[6].length >= 8)
+            {
+              d = READ_DWORD(&mdm_cfg[6].info[5]);
+              cai[10] |= (byte) d;        /* disabled modulations mask */
+              cai[11] |= (byte)(d >> 8);
+              if (mdm_cfg[6].length >= 12)
+              {
+                d = READ_DWORD(&mdm_cfg[6].info[9]);
+                cai[12] = (byte) d;          /* enabled modulations mask */
+                cai[++i] = (byte)(d >> 8);   /* vown enabled modulations */
+                cai[++i] = (byte)(d >> 16);
+                cai[++i] = (byte)(d >> 24);
+                cai[++i] = 0;
+                if (mdm_cfg[6].length >= 14)
+                {
+                  w = READ_WORD(&mdm_cfg[6].info[13]);
+                  if (w != 0)
+                    WRITE_WORD(&cai[13], w);  /* min tx speed */
+                  if (mdm_cfg[6].length >= 16)
+                  {
+                    w = READ_WORD(&mdm_cfg[6].info[15]);
+                    if (w != 0)
+                      WRITE_WORD(&cai[15], w);  /* max tx speed */
+                    if (mdm_cfg[6].length >= 18)
+                    {
+                      w = READ_WORD(&mdm_cfg[6].info[17]);
+                      if (w != 0)
+                        WRITE_WORD(&cai[17], w);  /* min rx speed */
+                      if (mdm_cfg[6].length >= 20)
+                      {
+                        w = READ_WORD(&mdm_cfg[6].info[19]);
+                        if (w != 0)
+                          WRITE_WORD(&cai[19], w);  /* max rx speed */
+                        if (mdm_cfg[6].length >= 22)
+                        {
+                          w = READ_WORD(&mdm_cfg[6].info[21]);
+                          cai[23] = (byte)(-((short) w));  /* transmit level */
+                          if (mdm_cfg[6].length >= 24)
+                          {
+                            w = READ_WORD(&mdm_cfg[6].info[23]);
+                            cai[22] |= (byte) w;        /* info options mask */
+                            cai[21] |= (byte)(w >> 8);  /* disabled symbol rates */
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+          cai[27] = i - 27;
+          i++;
+          if (!api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwwwss", mdm_cfg))
+          {
+            if (!api_parse(&mdm_cfg[7].info[1],(word)mdm_cfg[7].length,"sss", mdm_cfg_v18))
+            {
+              for (n = 0; n < 3; n++)
+              {
+                cai[i] = (byte)(mdm_cfg_v18[n].length);
+                for (j = 1; j < ((word)(cai[i] + 1)); j++)
+                  cai[i+j] = mdm_cfg_v18[n].info[j];
+                i += cai[i] + 1;
+              }
+            }
+          }
+          cai[0] = (byte)(i - 1);
+        }
+      }
+
+    }
+  }
+  if(READ_WORD(bp_parms[0].info)==2 ||                         // V.110 async
+     READ_WORD(bp_parms[0].info)==3 )                          // V.110 sync
+  {
+    if(bp_parms[3].length){
+      dbug(1,dprintf("V.110,%d",READ_WORD(&bp_parms[3].info[1])));
+      switch(READ_WORD(&bp_parms[3].info[1])){                 // Rate
+        case 0:
+        case 56000:
+          if(READ_WORD(bp_parms[0].info)==3){                  //V.110 sync 56k
+            dbug(1,dprintf("56k sync HSCX"));
+            cai[1] = 8;
+            cai[2] = 0;
+            cai[3] = 0;
+          }
+          else if(READ_WORD(bp_parms[0].info)==2){
+            dbug(1,dprintf("56k async DSP"));
+            cai[2] = 9;
+          }
+          break;
+        case 50:     cai[2] = 1;  break;
+        case 75:     cai[2] = 1;  break;
+        case 110:    cai[2] = 1;  break;
+        case 150:    cai[2] = 1;  break;
+        case 200:    cai[2] = 1;  break;
+        case 300:    cai[2] = 1;  break;
+        case 600:    cai[2] = 1;  break;
+        case 1200:   cai[2] = 2;  break;
+        case 2400:   cai[2] = 3;  break;
+        case 4800:   cai[2] = 4;  break;
+        case 7200:   cai[2] = 10; break;
+        case 9600:   cai[2] = 5;  break;
+        case 12000:  cai[2] = 13; break;
+        case 24000:  cai[2] = 0;  break;
+        case 14400:  cai[2] = 11; break;
+        case 19200:  cai[2] = 6;  break;
+        case 28800:  cai[2] = 12; break;
+        case 38400:  cai[2] = 7;  break;
+        case 48000:  cai[2] = 8;  break;
+        case 76:     cai[2] = 15; break;  /* 75/1200     */
+        case 1201:   cai[2] = 14; break;  /* 1200/75     */
+        case 56001:  cai[2] = 9;  break;  /* V.110 56000 */
+
+        default:
+          return _B1_PARM_NOT_SUPPORTED;
+      }
+      cai[3] = 0;
+      if (cai[1] == 13)                                        // v.110 async
+      {
+        if (bp_parms[3].length >= 8)
+        {
+          switch (READ_WORD (&bp_parms[3].info[3]))
+          {       /* char length */
+          case 5:
+            cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
+            break;
+          case 6:
+            cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
+            break;
+          case 7:
+            cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
+            break;
+          }
+          switch (READ_WORD (&bp_parms[3].info[5]))
+          {       /* Parity     */
+          case 1: /* odd parity */
+            cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
+            break;
+          case 2: /* even parity */
+            cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
+            break;
+          }
+          switch (READ_WORD (&bp_parms[3].info[7]))
+          {       /* stop bits   */
+          case 1: /* 2 stop bits */
+            cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
+            break;
+          }
+        }
+      }
+    }
+    else if(cai[1]==8 || READ_WORD(bp_parms[0].info)==3 ){
+      dbug(1,dprintf("V.110 default 56k sync"));
+      cai[1] = 8;
+      cai[2] = 0;
+      cai[3] = 0;
+    }
+    else {
+      dbug(1,dprintf("V.110 default 9600 async"));
+      cai[2] = 5;
+    }
+  }
+  WRITE_WORD(&cai[5],plci->appl->MaxDataLength);
+  dbug(1,dprintf("CAI[%d]=%x,%x,%x,%x,%x,%x", cai[0], cai[1], cai[2], cai[3], cai[4], cai[5], cai[6]));
+//HexDump ("CAI", sizeof(cai), &cai[0]);
+
+  add_p(plci, CAI, cai);
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* put parameter for b2 and B3  protocol in the parameter buffer    */
+/*------------------------------------------------------------------*/
+
+word add_b23(PLCI   * plci, API_PARSE * bp)
+{
+  word i, fax_control_bits;
+  byte pos, len;
+  byte SAPI = 0x40;  /* default SAPI 16 for x.31 */
+    API_PARSE bp_parms[8];
+  API_PARSE * b1_config;
+  API_PARSE * b2_config;
+    API_PARSE b2_config_parms[8];
+  API_PARSE * b3_config;
+    API_PARSE b3_config_parms[6];
+    API_PARSE global_config[2];
+
+  static byte llc[3] = {2,0,0};
+  static byte dlc[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+  static byte nlc[256];
+  static byte lli[12] = {1,1};
+
+  const byte llc2_out[] = {1,2,4,6,2,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
+  const byte llc2_in[]  = {1,3,4,6,3,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
+
+  const byte llc3[] = {4,3,2,2,6,6,0};
+  const byte header[] = {0,2,3,3,0,0,0};
+
+  for(i=0;i<8;i++) bp_parms[i].length = 0;
+  for(i=0;i<6;i++) b2_config_parms[i].length = 0;
+  for(i=0;i<5;i++) b3_config_parms[i].length = 0;
+
+  lli[0] = 1;
+  lli[1] = 1;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
+    lli[1] |= 2;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
+    lli[1] |= 4;
+
+  if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
+    lli[1] |= 0x10;
+    if (plci->rx_dma_descriptor <= 0) {
+      plci->rx_dma_descriptor=diva_get_dma_descriptor(plci,&plci->rx_dma_magic);
+      if (plci->rx_dma_descriptor >= 0)
+        plci->rx_dma_descriptor++;
+    }
+    if (plci->rx_dma_descriptor > 0) {
+      lli[0] = 6;
+      lli[1] |= 0x40;
+      lli[2] = (byte)(plci->rx_dma_descriptor - 1);
+      lli[3] = (byte)plci->rx_dma_magic;
+      lli[4] = (byte)(plci->rx_dma_magic >>  8);
+      lli[5] = (byte)(plci->rx_dma_magic >> 16);
+      lli[6] = (byte)(plci->rx_dma_magic >> 24);
+    }
+  }
+
+  if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
+    lli[1] |= 0x20;
+  }
+
+  dbug(1,dprintf("add_b23"));
+  api_save_msg(bp, "s", &plci->B_protocol);
+
+  if(!bp->length && plci->tel)
+  {
+    plci->adv_nl = TRUE;
+    dbug(1,dprintf("Default adv.Nl"));
+    add_p(plci,LLI,lli);
+    plci->B2_prot = 1 /*XPARENT*/;
+    plci->B3_prot = 0 /*XPARENT*/;
+    llc[1] = 2;
+    llc[2] = 4;
+    add_p(plci, LLC, llc);
+    dlc[0] = 2;
+    WRITE_WORD(&dlc[1],plci->appl->MaxDataLength);
+    add_p(plci, DLC, dlc);
+    return 0;
+  }
+
+  if(!bp->length) /*default*/
+  {   
+    dbug(1,dprintf("ret default"));
+    add_p(plci,LLI,lli);
+    plci->B2_prot = 0 /*X.75   */;
+    plci->B3_prot = 0 /*XPARENT*/;
+    llc[1] = 1;
+    llc[2] = 4;
+    add_p(plci, LLC, llc);
+    dlc[0] = 2;
+    WRITE_WORD(&dlc[1],plci->appl->MaxDataLength);
+    add_p(plci, DLC, dlc);
+    return 0;
+  }
+  dbug(1,dprintf("b_prot_len=%d",(word)bp->length));
+  if((word)bp->length > 256)    return _WRONG_MESSAGE_FORMAT;
+
+  if(api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
+  {
+    bp_parms[6].length = 0;
+    if(api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
+    {
+      dbug(1,dprintf("b-form.!"));
+      return _WRONG_MESSAGE_FORMAT;
+    }
+  }
+  else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
+  {
+    dbug(1,dprintf("b-form.!"));
+    return _WRONG_MESSAGE_FORMAT;
+  }
+
+  if(plci->tel==ADV_VOICE) /* transparent B on advanced voice */
+  {  
+    if(READ_WORD(bp_parms[1].info)!=1
+    || READ_WORD(bp_parms[2].info)!=0) return _B2_NOT_SUPPORTED;
+    plci->adv_nl = TRUE;
+  }
+  else if(plci->tel) return _B2_NOT_SUPPORTED;
+
+
+  if ((READ_WORD(bp_parms[1].info) == B2_RTP)
+   && (READ_WORD(bp_parms[2].info) == B3_RTP)
+   && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
+  {
+    add_p(plci,LLI,lli);
+    plci->B2_prot = (byte) READ_WORD(bp_parms[1].info);
+    plci->B3_prot = (byte) READ_WORD(bp_parms[2].info);
+    llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ? 14 : 13;
+    llc[2] = 4;
+    add_p(plci, LLC, llc);
+    dlc[0] = 2;
+    WRITE_WORD(&dlc[1],plci->appl->MaxDataLength);
+    dlc[3] = 3; /* Addr A */
+    dlc[4] = 1; /* Addr B */
+    dlc[5] = 7; /* modulo mode */
+    dlc[6] = 7; /* window size */
+    dlc[7] = 0; /* XID len Lo  */
+    dlc[8] = 0; /* XID len Hi  */
+    for (i = 0; i < bp_parms[4].length; i++)
+      dlc[9+i] = bp_parms[4].info[1+i];
+    dlc[0] = (byte)(8 + bp_parms[4].length);
+    add_p(plci, DLC, dlc);
+    for (i = 0; i < bp_parms[5].length; i++)
+      nlc[1+i] = bp_parms[5].info[1+i];
+    nlc[0] = (byte)(bp_parms[5].length);
+    add_p(plci, NLC, nlc);
+    return 0;
+  }
+
+
+
+  if ((READ_WORD(bp_parms[1].info) >= 32)
+   || (!((1L << READ_WORD(bp_parms[1].info)) & plci->adapter->profile.B2_Protocols)
+    && ((READ_WORD(bp_parms[1].info) != B2_PIAFS)
+     || !(plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))))
+
+  {
+    return _B2_NOT_SUPPORTED;
+  }
+  if ((READ_WORD(bp_parms[2].info) >= 32)
+   || !((1L << READ_WORD(bp_parms[2].info)) & plci->adapter->profile.B3_Protocols))
+  {
+    return _B3_NOT_SUPPORTED;
+  }
+  if ((READ_WORD(bp_parms[1].info) != B2_SDLC)
+   && ((READ_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
+    || (READ_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
+    || (READ_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC)))
+  {
+    return (add_modem_b23 (plci, bp_parms));
+  }
+
+  add_p(plci,LLI,lli);
+
+  plci->B2_prot = (byte) READ_WORD(bp_parms[1].info);
+  plci->B3_prot = (byte) READ_WORD(bp_parms[2].info);
+  if(plci->B2_prot==12) SAPI = 0; /* default SAPI D-channel */
+
+  if(bp_parms[6].length)
+  {
+    if(api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
+    {
+      return _WRONG_MESSAGE_FORMAT;
+    }
+    switch(READ_WORD(global_config[0].info))
+    {
+    case 1:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
+      break;
+    case 2:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
+      break;
+    }
+  }
+  dbug(1,dprintf("call_dir=%04x", plci->call_dir));
+
+
+  if (plci->B2_prot == B2_PIAFS)
+    llc[1] = PIAFS_CRC;
+  else
+/* IMPLEMENT_PIAFS */
+  {
+    llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
+             llc2_out[READ_WORD(bp_parms[1].info)] : llc2_in[READ_WORD(bp_parms[1].info)];
+  }
+  llc[2] = llc3[READ_WORD(bp_parms[2].info)];
+
+  add_p(plci, LLC, llc);
+
+  dlc[0] = 2;
+  WRITE_WORD(&dlc[1], plci->appl->MaxDataLength +
+                      header[READ_WORD(bp_parms[2].info)]);
+
+  b1_config = &bp_parms[3];
+  nlc[0] = 0;
+  if(plci->B3_prot == 4
+  || plci->B3_prot == 5)
+  {
+    for (i=0;i<sizeof(T30_INFO);i++) nlc[i] = 0;
+    nlc[0] = sizeof(T30_INFO);
+    if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+      ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI;
+    ((T30_INFO *)&nlc[1])->rate_div_2400 = 0xff;
+    if(b1_config->length>=2)
+    {
+      ((T30_INFO *)&nlc[1])->rate_div_2400 = (byte)(READ_WORD(&b1_config->info[1])/2400);
+    }
+  }
+  b2_config = &bp_parms[4];
+
+
+  if (llc[1] == PIAFS_CRC)
+  {
+    if (plci->B3_prot != B3_TRANSPARENT)
+    {
+      return _B_STACK_NOT_SUPPORTED;
+    }
+    if(b2_config->length && api_parse(&b2_config->info[1], (word)b2_config->length, "bwww", b2_config_parms)) {
+      return _WRONG_MESSAGE_FORMAT;
+    }
+    WRITE_WORD(&dlc[1],plci->appl->MaxDataLength);
+    dlc[3] = 0; /* Addr A */
+    dlc[4] = 0; /* Addr B */
+    dlc[5] = 0; /* modulo mode */
+    dlc[6] = 0; /* window size */
+    if (b2_config->length >= 7){
+      dlc[ 7] = 7; 
+      dlc[ 8] = 0; 
+      dlc[ 9] = b2_config_parms[0].info[0]; /* PIAFS protocol Speed configuration */
+      dlc[10] = b2_config_parms[1].info[0]; /* V.42bis P0 */
+      dlc[11] = b2_config_parms[1].info[1]; /* V.42bis P0 */
+      dlc[12] = b2_config_parms[2].info[0]; /* V.42bis P1 */
+      dlc[13] = b2_config_parms[2].info[1]; /* V.42bis P1 */
+      dlc[14] = b2_config_parms[3].info[0]; /* V.42bis P2 */
+      dlc[15] = b2_config_parms[3].info[1]; /* V.42bis P2 */
+      dlc[ 0] = 15;
+      if(b2_config->length >= 8) { /* PIAFS control abilities */
+        dlc[ 7] = 10; 
+        dlc[16] = 2; /* Length of PIAFS extention */
+        dlc[17] = PIAFS_UDATA_ABILITIES; /* control (UDATA) ability */
+        dlc[18] = b2_config_parms[4].info[0]; /* value */
+        dlc[ 0] = 18;
+      }
+    }
+    else /* default values, 64K, variable, no compression */
+    {
+      dlc[ 7] = 7; 
+      dlc[ 8] = 0; 
+      dlc[ 9] = 0x03; /* PIAFS protocol Speed configuration */
+      dlc[10] = 0x03; /* V.42bis P0 */
+      dlc[11] = 0;    /* V.42bis P0 */
+      dlc[12] = 0;    /* V.42bis P1 */
+      dlc[13] = 0;    /* V.42bis P1 */
+      dlc[14] = 0;    /* V.42bis P2 */
+      dlc[15] = 0;    /* V.42bis P2 */
+    dlc[ 0] = 15;
+    }
+    add_p(plci, DLC, dlc);
+  }
+  else
+
+  if ((llc[1] == V120_L2) || (llc[1] == V120_V42BIS))
+  {
+    if (plci->B3_prot != B3_TRANSPARENT)
+      return _B_STACK_NOT_SUPPORTED;
+
+    dlc[0] = 6;
+    WRITE_WORD (&dlc[1], READ_WORD (&dlc[1]) + 2);
+    dlc[3] = 0x08;
+    dlc[4] = 0x01;
+    dlc[5] = 127;
+    dlc[6] = 7;
+    if (b2_config->length != 0)
+    {
+      if((llc[1]==V120_V42BIS) && api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms)) {
+        return _WRONG_MESSAGE_FORMAT;
+      }
+      dlc[3] = (byte)((b2_config->info[2] << 3) | ((b2_config->info[1] >> 5) & 0x04));
+      dlc[4] = (byte)((b2_config->info[1] << 1) | 0x01);
+      if (b2_config->info[3] != 128)
+      {
+        dbug(1,dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
+        return _B2_PARM_NOT_SUPPORTED;
+      }
+      dlc[5] = (byte)(b2_config->info[3] - 1);
+      dlc[6] = b2_config->info[4];
+      if(llc[1]==V120_V42BIS){
+        if (b2_config->length >= 10){
+          dlc[ 7] = 6; 
+          dlc[ 8] = 0; 
+          dlc[ 9] = b2_config_parms[4].info[0];
+          dlc[10] = b2_config_parms[4].info[1];
+          dlc[11] = b2_config_parms[5].info[0];
+          dlc[12] = b2_config_parms[5].info[1];
+          dlc[13] = b2_config_parms[6].info[0];
+          dlc[14] = b2_config_parms[6].info[1];
+          dlc[ 0] = 14;
+          dbug(1,dprintf("b2_config_parms[4].info[0] [1]:  %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
+          dbug(1,dprintf("b2_config_parms[5].info[0] [1]:  %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
+          dbug(1,dprintf("b2_config_parms[6].info[0] [1]:  %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
+        }
+        else {
+          dlc[ 6] = 14;
+        }
+      }
+    }
+  }
+  else
+  {
+    if(b2_config->length)
+    {
+      dbug(1,dprintf("B2-Config"));
+      if(llc[1]==X75_V42BIS){
+        if(api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms))
+        {
+          return _WRONG_MESSAGE_FORMAT;
+        }
+      }
+      else {
+        if(api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbs", b2_config_parms))
+        {
+          return _WRONG_MESSAGE_FORMAT;
+        }
+      }
+          /* if B2 Protocol is LAPD, b2_config structure is different */
+      if(llc[1]==6)
+      {
+        dlc[0] = 4;
+        if(b2_config->length>=1) dlc[2] = b2_config->info[1];      /* TEI */
+        else dlc[2] = 0x01;
+        if( (b2_config->length>=2) && (plci->B2_prot==12) )
+        {
+          SAPI = b2_config->info[2];    /* SAPI */
+        }
+        dlc[1] = SAPI;
+        if( (b2_config->length>=3) && (b2_config->info[3]==128) )
+        {
+          dlc[3] = 127;      /* Mode */
+        }
+        else
+        {
+          dlc[3] = 7;        /* Mode */
+        }
+   
+        if(b2_config->length>=4) dlc[4] = b2_config->info[4];      /* Window */
+        else dlc[4] = 1;
+        dbug(1,dprintf("D-dlc[%d]=%x,%x,%x,%x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
+        if(b2_config->length>5) return _B2_PARM_NOT_SUPPORTED;
+      }
+      else
+      {
+        dlc[0] = (byte)(b2_config_parms[4].length+6);
+        dlc[3] = b2_config->info[1];
+        dlc[4] = b2_config->info[2];
+        if(b2_config->info[3]!=8 && b2_config->info[3]!=128){
+          dbug(1,dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
+          return _B2_PARM_NOT_SUPPORTED;
+        }
+
+        dlc[5] = (byte)(b2_config->info[3]-1);
+        dlc[6] = b2_config->info[4];
+        if(dlc[6]>dlc[5]){
+          dbug(1,dprintf("2D-dlc= %x %x %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4], dlc[5], dlc[6]));
+          return _B2_PARM_NOT_SUPPORTED;
+        }
+ 
+        if(llc[1]==X75_V42BIS) {
+          if (b2_config->length >= 10){
+            dlc[ 7] = 6; 
+            dlc[ 8] = 0; 
+            dlc[ 9] = b2_config_parms[4].info[0];
+            dlc[10] = b2_config_parms[4].info[1];
+            dlc[11] = b2_config_parms[5].info[0];
+            dlc[12] = b2_config_parms[5].info[1];
+            dlc[13] = b2_config_parms[6].info[0];
+            dlc[14] = b2_config_parms[6].info[1];
+            dlc[ 0] = 14;
+            dbug(1,dprintf("b2_config_parms[4].info[0] [1]:  %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
+            dbug(1,dprintf("b2_config_parms[5].info[0] [1]:  %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
+            dbug(1,dprintf("b2_config_parms[6].info[0] [1]:  %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
+          }
+          else {
+            dlc[ 6] = 14;
+          }
+
+        }
+        else {
+          WRITE_WORD(&dlc[7], (word)b2_config_parms[4].length);
+          for(i=0; i<b2_config_parms[4].length; i++)
+            dlc[11+i] = b2_config_parms[4].info[1+i];
+        }
+      }
+    }
+  }
+  add_p(plci, DLC, dlc);
+
+  b3_config = &bp_parms[5];
+  if(b3_config->length)
+  {
+    if(plci->B3_prot == 4 
+    || plci->B3_prot == 5)
+    {
+      if(api_parse(&b3_config->info[1], (word)b3_config->length, "wwss", b3_config_parms))
+      {
+        return _WRONG_MESSAGE_FORMAT;
+      }
+      i = READ_WORD((byte   *)(b3_config_parms[0].info));
+      ((T30_INFO *)&nlc[1])->resolution = (byte)(((i & 0x0001) ||
+        ((plci->B3_prot == 4) && (((byte)(READ_WORD((byte   *)b3_config_parms[1].info))) != 5))) ? T30_RESOLUTION_R8_0770_OR_200 : 0);
+      ((T30_INFO *)&nlc[1])->data_format = (byte)(READ_WORD((byte   *)b3_config_parms[1].info));
+      fax_control_bits = T30_CONTROL_BIT_ALL_FEATURES;
+      if ((((T30_INFO *)&nlc[1])->rate_div_2400 != 0) && (((T30_INFO *)&nlc[1])->rate_div_2400 <= 6))
+        fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_V34FAX;
+      if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+      {
+
+        if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+          & (1L << PRIVATE_FAX_PAPER_FORMATS))
+        {
+          ((T30_INFO *)&nlc[1])->resolution |= T30_RESOLUTION_R8_1540 |
+            T30_RESOLUTION_R16_1540_OR_400 | T30_RESOLUTION_300_300 |
+            T30_RESOLUTION_INCH_BASED | T30_RESOLUTION_METRIC_BASED;
+        }
+
+ ((T30_INFO *)&nlc[1])->recording_properties =
+   T30_RECORDING_WIDTH_ISO_A3 |
+   (T30_RECORDING_LENGTH_UNLIMITED << 2) |
+   (T30_MIN_SCANLINE_TIME_00_00_00 << 4);
+      }
+      if(plci->B3_prot == 5)
+      {
+        if (i & 0x0002) /* Accept incoming fax-polling requests */
+          fax_control_bits |= T30_CONTROL_BIT_ACCEPT_POLLING;
+        if (i & 0x2000) /* Do not use MR compression */
+          fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_2D_CODING;
+        if (i & 0x4000) /* Do not use MMR compression */
+          fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_T6_CODING;
+        if (i & 0x8000) /* Do not use ECM */
+          fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_ECM;
+        if (plci->fax_connect_info_length != 0)
+        {
+          ((T30_INFO *)&nlc[1])->resolution = ((T30_INFO   *)plci->fax_connect_info_buffer)->resolution;
+          ((T30_INFO *)&nlc[1])->data_format = ((T30_INFO   *)plci->fax_connect_info_buffer)->data_format;
+          ((T30_INFO *)&nlc[1])->recording_properties = ((T30_INFO   *)plci->fax_connect_info_buffer)->recording_properties;
+          fax_control_bits |= READ_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low) &
+            (T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
+        }
+      }
+      /* copy station id to NLC */
+      for(i=0; i<20; i++)
+      {
+        if(i<b3_config_parms[2].length)
+        {
+          ((T30_INFO *)&nlc[1])->station_id[i] = ((byte   *)b3_config_parms[2].info)[1+i];
+        }
+        else
+        {
+          ((T30_INFO *)&nlc[1])->station_id[i] = ' ';
+        }
+      }
+      ((T30_INFO *)&nlc[1])->station_id_len = 20;
+      /* copy head line to NLC */
+      if(b3_config_parms[3].length)
+      {
+
+        pos = (byte)(fax_head_line_time (&(((T30_INFO *)&nlc[1])->station_id[20])));
+        if (pos != 0)
+        {
+          if (CAPI_MAX_DATE_TIME_LENGTH + 2 + b3_config_parms[3].length > CAPI_MAX_HEAD_LINE_SPACE)
+            pos = 0;
+          else
+          {
+            ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+            ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+            len = (byte)b3_config_parms[2].length;
+            if (len > 20)
+              len = 20;
+            if (CAPI_MAX_DATE_TIME_LENGTH + 2 + len + 2 + b3_config_parms[3].length <= CAPI_MAX_HEAD_LINE_SPACE)
+            {
+              for (i = 0; i < len; i++)
+                ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte   *)b3_config_parms[2].info)[1+i];
+              ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+              ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+            }
+          }
+        }
+
+        len = (byte)b3_config_parms[3].length;
+        if (len > CAPI_MAX_HEAD_LINE_SPACE - pos)
+          len = (byte)(CAPI_MAX_HEAD_LINE_SPACE - pos);
+        ((T30_INFO *)&nlc[1])->head_line_len = (byte)(pos + len);
+        nlc[0] += (byte)(pos + len);
+        for (i = 0; i < len; i++)
+          ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte   *)b3_config_parms[3].info)[1+i];
+        }
+      else
+        ((T30_INFO *)&nlc[1])->head_line_len = 0;
+
+      plci->nsf_control_bits = 0;
+      if(plci->B3_prot == 5)
+      {
+        if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+         && (READ_WORD((byte   *)b3_config_parms[1].info) & 0x8000)) /* Private SUB/SEP/PWD enable */
+        {
+          plci->requested_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
+        }
+        if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
+         && (READ_WORD((byte   *)b3_config_parms[1].info) & 0x4000)) /* Private non-standard facilities enable */
+        {
+          plci->requested_options |= 1L << PRIVATE_FAX_NONSTANDARD;
+        }
+        if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+          & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+        {
+        if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+          & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+        {
+          fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
+          if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
+            fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
+          }
+            len = nlc[0];
+          pos = ((byte)(((T30_INFO *) 0)->station_id + 20));
+   if (pos < plci->fax_connect_info_length)
+   {
+     for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
+              nlc[++len] = plci->fax_connect_info_buffer[pos++];
+          }
+   else
+     nlc[++len] = 0;
+   if (pos < plci->fax_connect_info_length)
+   {
+     for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
+              nlc[++len] = plci->fax_connect_info_buffer[pos++];
+          }
+   else
+     nlc[++len] = 0;
+          if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+            & (1L << PRIVATE_FAX_NONSTANDARD))
+          {
+     if ((pos < plci->fax_connect_info_length) && (plci->fax_connect_info_buffer[pos] != 0))
+     {
+              if ((plci->fax_connect_info_buffer[pos] >= 3) && (plci->fax_connect_info_buffer[pos+1] >= 2))
+                plci->nsf_control_bits = READ_WORD(&plci->fax_connect_info_buffer[pos+2]);
+       for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
+                nlc[++len] = plci->fax_connect_info_buffer[pos++];
+            }
+     else
+     {
+              if(api_parse(&b3_config->info[1], (word)b3_config->length, "wwsss", b3_config_parms))
+              {
+                dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+                nlc[++len] = 0;
+              }
+       else
+       {
+                if ((b3_config_parms[4].length >= 3) && (b3_config_parms[4].info[1] >= 2))
+                  plci->nsf_control_bits = READ_WORD(&b3_config_parms[4].info[2]);
+         nlc[++len] = (byte)(b3_config_parms[4].length);
+         for (i = 0; i < b3_config_parms[4].length; i++)
+    nlc[++len] = b3_config_parms[4].info[1+i];
+       }
+            }
+          }
+            nlc[0] = len;
+   if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
+    && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
+   {
+            ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI_NEG;
+          }
+        }
+      }
+
+      WRITE_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits);
+      len = ((byte)(((T30_INFO *) 0)->station_id + 20));
+      for (i = 0; i < len; i++)
+        plci->fax_connect_info_buffer[i] = nlc[1+i];
+      ((T30_INFO   *) plci->fax_connect_info_buffer)->head_line_len = 0;
+      i += ((T30_INFO *)&nlc[1])->head_line_len;
+      while (i < nlc[0])
+        plci->fax_connect_info_buffer[len++] = nlc[++i];
+      plci->fax_connect_info_length = len;
+    }
+    else
+    {
+      nlc[0] = 14;
+      if(b3_config->length!=16)
+        return _B3_PARM_NOT_SUPPORTED;
+      for(i=0; i<12; i++) nlc[1+i] = b3_config->info[1+i];
+      if(READ_WORD(&b3_config->info[13])!=8 && READ_WORD(&b3_config->info[13])!=128)
+        return _B3_PARM_NOT_SUPPORTED;
+      nlc[13] = b3_config->info[13];
+      if(READ_WORD(&b3_config->info[15])>=nlc[13])
+        return _B3_PARM_NOT_SUPPORTED;
+      nlc[14] = b3_config->info[15];
+    }
+  }
+  else
+  {
+    if (plci->B3_prot == 4 
+     || plci->B3_prot == 5 /*T.30 - FAX*/ ) return _B3_PARM_NOT_SUPPORTED;
+  }
+  add_p(plci, NLC, nlc);
+  return 0;
+}
+
+/*----------------------------------------------------------------*/
+/*      make the same as add_b23, but only for the modem related  */
+/*      L2 and L3 B-Chan protocol.                                */
+/*                                                                */
+/*      Enabled L2 and L3 Configurations:                         */
+/*        If L1 == Modem all negotiation                          */
+/*          only L2 == Modem with full negotiation is allowed     */
+/*        If L1 == Modem async or sync                            */
+/*          only L2 == Transparent is allowed                     */
+/*        L3 == Modem or L3 == Transparent are allowed            */
+/*      B2 Configuration for modem:                               */
+/*          word : enable/disable compression, bitoptions         */
+/*      B3 Configuration for modem:                               */
+/*          empty                                                 */
+/*----------------------------------------------------------------*/
+static word add_modem_b23 (PLCI  * plci, API_PARSE* bp_parms)
+{
+  static byte lli[12] = {1,1};
+  static byte llc[3] = {2,0,0};
+  static byte dlc[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+    API_PARSE mdm_config[2];
+  word i;
+  word b2_config = 0;
+
+  for(i=0;i<2;i++) mdm_config[i].length = 0;
+  for(i=0;i<sizeof(dlc);i++) dlc[i] = 0;
+
+  if (((READ_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
+    && (READ_WORD(bp_parms[1].info) != B2_MODEM_EC_COMPRESSION))
+   || ((READ_WORD(bp_parms[0].info) != B1_MODEM_ALL_NEGOTIATE)
+    && (READ_WORD(bp_parms[1].info) != B2_TRANSPARENT)))
+  {
+    return (_B_STACK_NOT_SUPPORTED);
+  }
+  if ((READ_WORD(bp_parms[2].info) != B3_MODEM)
+   && (READ_WORD(bp_parms[2].info) != B3_TRANSPARENT))
+  {
+    return (_B_STACK_NOT_SUPPORTED);
+  }
+
+  plci->B2_prot = (byte) READ_WORD(bp_parms[1].info);
+  plci->B3_prot = (byte) READ_WORD(bp_parms[2].info);
+
+  if ((READ_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION) && bp_parms[4].length)
+  {
+    if (api_parse (&bp_parms[4].info[1],
+                  (word)bp_parms[4].length, "w",
+                  mdm_config))
+    {
+      return (_WRONG_MESSAGE_FORMAT);
+    }
+    b2_config = READ_WORD(mdm_config[0].info);
+  }
+
+  /* OK, L2 is modem */
+
+  lli[0] = 1;
+  lli[1] = 1;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
+    lli[1] |= 2;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
+    lli[1] |= 4;
+
+  if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
+    lli[1] |= 0x10;
+    if (plci->rx_dma_descriptor <= 0) {
+      plci->rx_dma_descriptor=diva_get_dma_descriptor(plci,&plci->rx_dma_magic);
+      if (plci->rx_dma_descriptor >= 0)
+        plci->rx_dma_descriptor++;
+    }
+    if (plci->rx_dma_descriptor > 0) {
+      lli[1] |= 0x40;
+      lli[0] = 6;
+      lli[2] = (byte)(plci->rx_dma_descriptor - 1);
+      lli[3] = (byte)plci->rx_dma_magic;
+      lli[4] = (byte)(plci->rx_dma_magic >>  8);
+      lli[5] = (byte)(plci->rx_dma_magic >> 16);
+      lli[6] = (byte)(plci->rx_dma_magic >> 24);
+    }
+  }
+
+  if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
+    lli[1] |= 0x20;
+  }
+
+  llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
+    /*V42*/ 10 : /*V42_IN*/ 9;
+  llc[2] = 4;                      /* pass L3 always transparent */
+  add_p(plci, LLI, lli);
+  add_p(plci, LLC, llc);
+  i =  1;
+  WRITE_WORD (&dlc[i], plci->appl->MaxDataLength);
+  i += 2;
+  if (READ_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION)
+  {
+    if (bp_parms[4].length)
+  {
+    dbug(1, dprintf("MDM b2_config=%02x", b2_config));
+    dlc[i++] = 3; /* Addr A */
+    dlc[i++] = 1; /* Addr B */
+    dlc[i++] = 7; /* modulo mode */
+    dlc[i++] = 7; /* window size */
+    dlc[i++] = 0; /* XID len Lo  */
+    dlc[i++] = 0; /* XID len Hi  */
+
+    if (b2_config & MDM_B2_DISABLE_V42bis)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_V42_V42BIS;
+    }
+    if (b2_config & MDM_B2_DISABLE_MNP)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_MNP_MNP5;
+    }
+    if (b2_config & MDM_B2_DISABLE_TRANS)
+    {
+      dlc[i] |= DLC_MODEMPROT_REQUIRE_PROTOCOL;
+    }
+    if (b2_config & MDM_B2_DISABLE_V42)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_V42_DETECT;
+    }
+    if (b2_config & MDM_B2_DISABLE_COMP)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_COMPRESSION;
+    }
+    i++;
+  }
+  }
+  else
+  {
+    dlc[i++] = 3; /* Addr A */
+    dlc[i++] = 1; /* Addr B */
+    dlc[i++] = 7; /* modulo mode */
+    dlc[i++] = 7; /* window size */
+    dlc[i++] = 0; /* XID len Lo  */
+    dlc[i++] = 0; /* XID len Hi  */
+    dlc[i++] = DLC_MODEMPROT_DISABLE_V42_V42BIS |
+               DLC_MODEMPROT_DISABLE_MNP_MNP5 |
+               DLC_MODEMPROT_DISABLE_V42_DETECT |
+               DLC_MODEMPROT_DISABLE_COMPRESSION;
+  }
+  dlc[0] = (byte)(i - 1);
+//HexDump ("DLC", sizeof(dlc), &dlc[0]);
+  add_p(plci, DLC, dlc);
+  return (0);
+}
+
+
+/*------------------------------------------------------------------*/
+/* send a request for the signaling entity                          */
+/*------------------------------------------------------------------*/
+
+void sig_req(PLCI   * plci, byte req, byte Id)
+{
+  if(!plci) return;
+  if(plci->adapter->adapter_disabled) return;
+  dbug(1,dprintf("sig_req(%x)",req));
+  if (req == REMOVE)
+    plci->sig_remove_id = plci->Sig.Id;
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+    plci->RBuffer[plci->req_in++] = 0;
+  }
+  WRITE_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start-2);
+  plci->RBuffer[plci->req_in++] = Id;   /* sig/nl flag */
+  plci->RBuffer[plci->req_in++] = req;  /* request */
+  plci->RBuffer[plci->req_in++] = 0;    /* channel */
+  plci->req_in_start = plci->req_in;
+}
+
+/*------------------------------------------------------------------*/
+/* send a request for the network layer entity                      */
+/*------------------------------------------------------------------*/
+
+void nl_req_ncci(PLCI   * plci, byte req, byte ncci)
+{
+  if(!plci) return;
+  if(plci->adapter->adapter_disabled) return;
+  dbug(1,dprintf("nl_req %02x %02x %02x", plci->Id, req, ncci));
+  if (req == REMOVE)
+  {
+    plci->nl_remove_id = plci->NL.Id;
+    ncci_remove (plci, 0, (byte)(ncci != 0));
+    ncci = 0;
+  }
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+    plci->RBuffer[plci->req_in++] = 0;
+  }
+  WRITE_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start-2);
+  plci->RBuffer[plci->req_in++] = 1;    /* sig/nl flag */
+  plci->RBuffer[plci->req_in++] = req;  /* request */
+  plci->RBuffer[plci->req_in++] = plci->adapter->ncci_ch[ncci];   /* channel */
+  plci->req_in_start = plci->req_in;
+}
+
+void send_req(PLCI   * plci)
+{
+  ENTITY   * e;
+  word l;
+//  word i;
+
+  if(!plci) return;
+  if(plci->adapter->adapter_disabled) return;
+  channel_xmit_xon (plci);
+
+        /* if nothing to do, return */
+  if(plci->req_in==plci->req_out) return;
+  dbug(1,dprintf("send_req(in=%d,out=%d)",plci->req_in,plci->req_out));
+
+  if(plci->nl_req || plci->sig_req) return;
+
+  l = READ_WORD(&plci->RBuffer[plci->req_out]);
+  plci->req_out += 2;
+  plci->XData[0].P = &plci->RBuffer[plci->req_out];
+  plci->req_out += l;
+  if(plci->RBuffer[plci->req_out]==1)
+  {
+    e = &plci->NL;
+    plci->req_out++;
+    e->Req = plci->nl_req = plci->RBuffer[plci->req_out++];
+    e->ReqCh = plci->RBuffer[plci->req_out++];
+    if(!(e->Id & 0x1f))
+    {
+      e->Id = NL_ID;
+      plci->RBuffer[plci->req_out-4] = CAI;
+      plci->RBuffer[plci->req_out-3] = 1;
+      plci->RBuffer[plci->req_out-2] = (plci->Sig.Id==0xff) ? 0 : plci->Sig.Id;
+      plci->RBuffer[plci->req_out-1] = 0;
+      l+=3;
+      plci->nl_global_req = plci->nl_req;
+    }
+    dbug(1,dprintf("%x:NLREQ(%x:%x:%x)",plci->adapter->Id,e->Id,e->Req,e->ReqCh));
+  }
+  else
+  {
+    e = &plci->Sig;
+    if(plci->RBuffer[plci->req_out])
+      e->Id = plci->RBuffer[plci->req_out];
+    plci->req_out++;
+    e->Req = plci->sig_req = plci->RBuffer[plci->req_out++];
+    e->ReqCh = plci->RBuffer[plci->req_out++];
+    if(!(e->Id & 0x1f))
+      plci->sig_global_req = plci->sig_req;
+    dbug(1,dprintf("%x:SIGREQ(%x:%x:%x)",plci->adapter->Id,e->Id,e->Req,e->ReqCh));
+  }
+  plci->XData[0].PLength = l;
+  e->X = plci->XData;
+  plci->adapter->request(e);
+  dbug(1,dprintf("send_ok"));
+}
+
+void send_data(PLCI   * plci)
+{
+  DIVA_CAPI_ADAPTER   * a;
+  DATA_B3_DESC   * data;
+  NCCI   *ncci_ptr;
+  word ncci;
+
+  if (!plci->nl_req && plci->ncci_ring_list)
+  {
+    a = plci->adapter;
+    ncci = plci->ncci_ring_list;
+    do
+    {
+      ncci = a->ncci_next[ncci];
+      ncci_ptr = &(a->ncci[ncci]);
+      if (!(a->ncci_ch[ncci]
+         && (a->ch_flow_control[a->ncci_ch[ncci]] & N_OK_FC_PENDING)))
+      {
+        if (ncci_ptr->data_pending)
+        {
+          if ((a->ncci_state[ncci] == CONNECTED)
+           || (a->ncci_state[ncci] == INC_ACT_PENDING)
+           || (plci->send_disc == ncci))
+          {
+            data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
+            if ((plci->B2_prot == B2_V120_ASYNC)
+             || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
+             || (plci->B2_prot == B2_V120_BIT_TRANSPARENT))
+            {
+              plci->NData[1].P = TransmitBufferGet (plci->appl, data->P);
+              plci->NData[1].PLength = data->Length;
+              if (data->Flags & 0x10)
+                plci->NData[0].P = v120_break_header;
+              else
+                plci->NData[0].P = v120_default_header;
+              plci->NData[0].PLength = 1 ;
+              plci->NL.XNum = 2;
+              plci->NL.Req = plci->nl_req = (byte)((data->Flags&0x07)<<4 |N_DATA);
+            }
+            else
+            {
+              plci->NData[0].P = TransmitBufferGet (plci->appl, data->P);
+              plci->NData[0].PLength = data->Length;
+              if (data->Flags & 0x10)
+                plci->NL.Req = plci->nl_req = (byte)N_UDATA;
+
+              else if ((plci->B3_prot == B3_RTP) && (data->Flags & 0x01))
+                plci->NL.Req = plci->nl_req = (byte)N_BDATA;
+
+              else
+                plci->NL.Req = plci->nl_req = (byte)((data->Flags&0x07)<<4 |N_DATA);
+            }
+            plci->NL.X = plci->NData;
+            plci->NL.ReqCh = a->ncci_ch[ncci];
+            dbug(1,dprintf("%x:DREQ(%x:%x)",a->Id,plci->NL.Id,plci->NL.Req));
+            plci->data_sent = TRUE;
+            plci->data_sent_ptr = data->P;
+            a->request(&plci->NL);
+          }
+          else {
+            cleanup_ncci_data (plci, ncci);
+          }
+        }
+        else if (plci->send_disc == ncci)
+        {
+          //dprintf("N_DISC");
+          plci->NData[0].PLength = 0;
+          plci->NL.ReqCh = a->ncci_ch[ncci];
+          plci->NL.Req = plci->nl_req = N_DISC;
+          a->request(&plci->NL);
+          plci->command = _DISCONNECT_B3_R;
+          plci->send_disc = 0;
+        }
+      }
+    } while (!plci->nl_req && (ncci != plci->ncci_ring_list));
+    plci->ncci_ring_list = ncci;
+  }
+}
+
+void listen_check(DIVA_CAPI_ADAPTER   * a)
+{
+  word i,j;
+  PLCI   * plci;
+  byte activnotifiedcalls = 0;
+
+  dbug(1,dprintf("listen_check(%d,%d)",a->listen_active,a->max_listen));
+  if (!remove_started && !a->adapter_disabled)
+  {
+    for(i=0;i<a->max_plci;i++)
+    {
+      plci = &(a->plci[i]);
+      if(plci->notifiedcall) activnotifiedcalls++;
+    }
+    dbug(1,dprintf("listen_check(%d)",activnotifiedcalls));
+
+    for(i=a->listen_active; i < ((word)(a->max_listen+activnotifiedcalls)); i++) {
+      if((j=get_plci(a))) {
+        a->listen_active++;
+        plci = &a->plci[j-1];
+        plci->State = LISTENING;
+
+        add_p(plci,OAD,"\x01\xfd");
+
+        add_p(plci,KEY,"\x04\x43\x41\x32\x30");
+
+        add_p(plci,CAI,"\x01\xc0");
+        add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+        add_p(plci,LLI,"\x01\xc4");                  /* support Dummy CR FAC + MWI + SpoofNotify */       
+        add_p(plci,SHIFT|6,0);
+        add_p(plci,SIN,"\x02\x00\x00");
+        plci->internal_command = LISTEN_SIG_ASSIGN_PEND;     /* do indicate_req if OK  */
+        sig_req(plci,ASSIGN,DSIG_ID);
+        send_req(plci);
+      }
+    }
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* functions for all parameters sent in INDs                        */
+/*------------------------------------------------------------------*/
+
+void IndParse(PLCI   * plci, word * parms_id, byte   ** parms, byte multiIEsize)
+{
+  word ploc;            /* points to current location within packet */
+  byte w;
+  byte wlen;
+  byte codeset,lock;
+  byte   * in;
+  word i;
+  word code;
+  word mIEindex = 0;
+  ploc = 0;
+  codeset = 0;
+  lock = 0;
+
+  in = plci->Sig.RBuffer->P;
+  for(i=0; i<parms_id[0]; i++)   /* multiIE parms_id contains just the 1st */
+  {                            /* element but parms array is larger      */
+    parms[i] = (byte   *)"";
+  }
+  for(i=0; i<multiIEsize; i++)
+  {
+    parms[i] = (byte   *)"";
+  }
+
+  while(ploc<plci->Sig.RBuffer->length-1) {
+
+        /* read information element id and length                   */
+    w = in[ploc];
+
+    if(w & 0x80) {
+/*    w &=0xf0; removed, cannot detect congestion levels */
+/*    upper 4 bit masked with w==SHIFT now               */
+      wlen = 0;
+    }
+    else {
+      wlen = (byte)(in[ploc+1]+1);
+    }
+        /* check if length valid (not exceeding end of packet)      */
+    if((ploc+wlen) > 270) return ;
+    if(lock & 0x80) lock &=0x7f;
+    else codeset = lock;
+
+    if((w&0xf0)==SHIFT) {
+      codeset = in[ploc];
+      if(!(codeset & 0x08)) lock = (byte)(codeset & 7);
+      codeset &=7;
+      lock |=0x80;
+    }
+    else {
+      if(w==ESC && wlen>=3) code = in[ploc+2] |0x800;
+      else code = w;
+      code |= (codeset<<8);
+
+      for(i=1; i<parms_id[0]+1 && parms_id[i]!=code; i++);
+
+      if(i<parms_id[0]+1) {
+        if(!multiIEsize) { /* with multiIEs use next field index,          */
+          mIEindex = i-1;    /* with normal IEs use same index like parms_id */
+        }
+
+        parms[mIEindex] = &in[ploc+1];
+        dbug(1,dprintf("mIE[%d]=0x%x",*parms[mIEindex],in[ploc]));
+        if(parms_id[i]==OAD
+        || parms_id[i]==CONN_NR
+        || parms_id[i]==CAD) {
+          if(in[ploc+2] &0x80) {
+            in[ploc+0] = (byte)(in[ploc+1]+1);
+            in[ploc+1] = (byte)(in[ploc+2] &0x7f);
+            in[ploc+2] = 0x80;
+            parms[mIEindex] = &in[ploc];
+          }
+        }
+        mIEindex++;       /* effects multiIEs only */
+      }
+    }
+
+    ploc +=(wlen+1);
+  }
+  return ;
+}
+
+/*------------------------------------------------------------------*/
+/* try to match a cip from received BC and HLC                      */
+/*------------------------------------------------------------------*/
+
+byte ie_compare(byte   * ie1, byte * ie2)
+{
+  word i;
+  if(!ie1 || ! ie2) return FALSE;
+  if(!ie1[0]) return FALSE;
+  for(i=0;i<(word)(ie1[0]+1);i++) if(ie1[i]!=ie2[i]) return FALSE;
+  return TRUE;
+}
+
+word find_cip(DIVA_CAPI_ADAPTER   * a, byte   * bc, byte   * hlc)
+{
+  word i;
+  word j;
+
+  for(i=9;i && !ie_compare(bc,cip_bc[i][a->u_law]);i--);
+
+  for(j=16;j<29 &&
+           (!ie_compare(bc,cip_bc[j][a->u_law]) || !ie_compare(hlc,cip_hlc[j])); j++);
+  if(j==29) return i;
+  return j;
+}
+
+
+static byte AddInfo(byte   **add_i,
+                    byte   **fty_i,
+                    byte   *esc_chi,
+                    byte *facility)
+{
+  byte i;
+  byte j;
+  byte k;
+  byte flen;
+  byte len=0;
+   /* facility is a nested structure */
+   /* FTY can be more than once      */
+
+  if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f )
+  {
+    add_i[0] = (byte   *)"\x02\x02\x00"; /* use neither b nor d channel */
+  }
+
+  else
+  {
+    add_i[0] = (byte   *)"";
+  }
+  if(!fty_i[0][0])
+  {
+    add_i[3] = (byte   *)"";
+  }
+  else
+  {    /* facility array found  */
+    for(i=0,j=1;i<MAX_MULTI_IE && fty_i[i][0];i++)
+    {
+      dbug(1,dprintf("AddIFac[%d]",fty_i[i][0]));
+      len += fty_i[i][0];
+      len += 2;
+      flen=fty_i[i][0];
+      facility[j++]=0x1c; /* copy fac IE */
+      for(k=0;k<=flen;k++,j++)
+      {
+        facility[j]=fty_i[i][k];
+//      dbug(1,dprintf("%x ",facility[j]));
+      }
+    }
+    facility[0] = len;
+    add_i[3] = facility;
+  }
+//  dbug(1,dprintf("FacArrLen=%d ",len));
+  len = add_i[0][0]+add_i[1][0]+add_i[2][0]+add_i[3][0];
+  len += 4;                          // calculate length of all
+  return(len);
+}
+
+/*------------------------------------------------------------------*/
+/* voice and codec features                                         */
+/*------------------------------------------------------------------*/
+
+void SetVoiceChannel(PLCI   *plci, byte   *chi, DIVA_CAPI_ADAPTER   * a)
+{
+  byte voice_chi[] = "\x02\x18\x01";
+  byte channel;
+
+  channel = chi[chi[0]]&0x3;
+  dbug(1,dprintf("ExtDevON(Ch=0x%x)",channel));
+  voice_chi[2] = (channel) ? channel : 1;
+  add_p(plci,FTY,"\x02\x01\x07");             // B On, default on 1
+  add_p(plci,ESC,voice_chi);                  // Channel
+  sig_req(plci,TEL_CTRL,0);
+  send_req(plci);
+  if(a->AdvSignalPLCI)
+  {
+    adv_voice_write_coefs (a->AdvSignalPLCI, ADV_VOICE_WRITE_ACTIVATION);
+  }
+}
+
+void VoiceChannelOff(PLCI   *plci)
+{
+  dbug(1,dprintf("ExtDevOFF"));
+  add_p(plci,FTY,"\x02\x01\x08");             // B Off
+  sig_req(plci,TEL_CTRL,0);
+  send_req(plci);
+  if(plci->adapter->AdvSignalPLCI)
+  {
+    adv_voice_clear_config (plci->adapter->AdvSignalPLCI);
+  }
+}
+
+
+word AdvCodecSupport(DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, byte hook_listen)
+{
+  word j;
+  PLCI   *splci;
+
+  /* check if hardware supports handset with hook states (adv.codec) */
+  /* or if just a on board codec is supported                        */
+  /* the advanced codec plci is just for internal use                */
+
+  /* diva Pro with on-board codec:                                   */
+  if(a->profile.Global_Options & HANDSET)
+  {
+    /* new call, but hook states are already signalled */
+    if(a->AdvCodecFLAG)
+    {
+      if(a->AdvSignalAppl!=appl || a->AdvSignalPLCI)
+      {
+        dbug(1,dprintf("AdvSigPlci=0x%x",a->AdvSignalPLCI));
+        return 0x2001; /* codec in use by another application */
+      }
+      if(plci!=0)
+      {
+        a->AdvSignalPLCI = plci;
+        plci->tel=ADV_VOICE;
+      }
+      return 0;                      /* adv codec still used */
+    }
+    if((j=get_plci(a)))
+    {
+      splci = &a->plci[j-1];
+      splci->tel = CODEC_PERMANENT;
+      /* hook_listen indicates if a facility_req with handset/hook support */
+      /* was sent. Otherwise if just a call on an external device was made */
+      /* the codec will be used but the hook info will be discarded (just  */
+      /* the external controller is in use                                 */
+      if(hook_listen) splci->State = ADVANCED_VOICE_SIG;
+      else
+      {
+        splci->State = ADVANCED_VOICE_NOSIG;
+        if(plci)
+        {
+          plci->spoofed_msg = SPOOFING_REQUIRED;
+        }
+                                               /* indicate D-ch connect if  */
+      }                                        /* codec is connected OK     */
+      if(plci!=0)
+      {
+        a->AdvSignalPLCI = plci;
+        plci->tel=ADV_VOICE;
+      }
+      a->AdvSignalAppl = appl;
+      a->AdvCodecFLAG = TRUE;
+      a->AdvCodecPLCI = splci;
+      add_p(splci,CAI,"\x01\x15");
+      add_p(splci,LLI,"\x01\x00");
+      add_p(splci,ESC,"\x02\x18\x00");
+      add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+      splci->internal_command = PERM_COD_ASSIGN;
+      dbug(1,dprintf("Codec Assign"));
+      sig_req(splci,ASSIGN,DSIG_ID);
+      send_req(splci);
+    }
+    else
+    {
+      return 0x2001; /* wrong state, no more plcis */
+    }
+  }
+  else if(a->profile.Global_Options & ON_BOARD_CODEC)
+  {
+    if(hook_listen) return 0x300B;               /* Facility not supported */
+                                                 /* no hook with SCOM      */
+    if(plci!=0) plci->tel = CODEC;
+    dbug(1,dprintf("S/SCOM codec"));
+    /* first time we use the scom-s codec we must shut down the internal   */
+    /* handset application of the card. This can be done by an assign with */
+    /* a cai with the 0x80 bit set. Assign return code is 'out of resource'*/
+    if(!a->scom_appl_disable){
+      if((j=get_plci(a))) {
+        splci = &a->plci[j-1];
+        add_p(splci,CAI,"\x01\x80");
+        add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+        sig_req(splci,ASSIGN,0xC0);  /* 0xc0 is the TEL_ID */
+        send_req(splci);
+        a->scom_appl_disable = TRUE;
+      }
+      else{
+        return 0x2001; /* wrong state, no more plcis */
+      }
+    }
+  }
+  else return 0x300B;               /* Facility not supported */
+
+  return 0;
+}
+
+
+void CodecIdCheck(DIVA_CAPI_ADAPTER   *a, PLCI   *plci)
+{
+
+  dbug(1,dprintf("CodecIdCheck"));
+
+  if(a->AdvSignalPLCI == plci)
+  {
+    dbug(1,dprintf("PLCI owns codec"));
+    VoiceChannelOff(a->AdvCodecPLCI);
+    if(a->AdvCodecPLCI->State == ADVANCED_VOICE_NOSIG)
+    {
+      dbug(1,dprintf("remove temp codec PLCI"));
+      plci_remove(a->AdvCodecPLCI);
+      a->AdvCodecFLAG  = 0;
+      a->AdvCodecPLCI  = 0;
+      a->AdvSignalAppl = 0;
+    }
+    a->AdvSignalPLCI = 0;
+  }
+}
+
+/* -------------------------------------------------------------------
+    Ask for physical address of card on PCI bus
+   ------------------------------------------------------------------- */
+static void diva_ask_for_xdi_sdram_bar (DIVA_CAPI_ADAPTER  * a,
+                                        IDI_SYNC_REQ  * preq) {
+  a->sdram_bar = 0;
+  if (diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR) {
+    ENTITY   * e = (ENTITY   *)preq;
+
+    e->user[0] = a->Id - 1;
+    preq->xdi_sdram_bar.info.bar    = 0;
+    preq->xdi_sdram_bar.Req         = 0;
+    preq->xdi_sdram_bar.Rc           = IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR;
+
+    (*(a->request))(e);
+
+    a->sdram_bar = preq->xdi_sdram_bar.info.bar;
+    dbug(3,dprintf("A(%d) SDRAM BAR = %08x", a->Id, a->sdram_bar));
+  }
+}
+
+/* -------------------------------------------------------------------
+     Ask XDI about extended features
+   ------------------------------------------------------------------- */
+static void diva_get_extended_adapter_features (DIVA_CAPI_ADAPTER  * a) {
+  IDI_SYNC_REQ   * preq;
+    char buffer[              ((sizeof(preq->xdi_extended_features)+4) > sizeof(ENTITY)) ?                     (sizeof(preq->xdi_extended_features)+4) : sizeof(ENTITY)];
+
+    char features[4];
+  preq = (IDI_SYNC_REQ   *)&buffer[0];
+
+  if (!diva_xdi_extended_features) {
+    ENTITY   * e = (ENTITY   *)preq;
+    diva_xdi_extended_features |= 0x80000000;
+
+    e->user[0] = a->Id - 1;
+    preq->xdi_extended_features.Req = 0;
+    preq->xdi_extended_features.Rc  = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
+    preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
+    preq->xdi_extended_features.info.features = &features[0];
+
+    (*(a->request))(e);
+
+    if (features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) {
+      /*
+         Check features located in the byte '0'
+         */
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_CMA) {
+        diva_xdi_extended_features |= DIVA_CAPI_USE_CMA;
+      }
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_RX_DMA) {
+        diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_RX_DMA;
+        dbug(1,dprintf("XDI provides RxDMA"));
+      }
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR) {
+        diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR;
+      }
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC) {
+        diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_NO_CANCEL;
+        dbug(3,dprintf("XDI provides NO_CANCEL_RC feature"));
+      }
+
+    }
+  }
+
+  diva_ask_for_xdi_sdram_bar (a, preq);
+}
+
+/*------------------------------------------------------------------*/
+/* automatic law                                                    */
+/*------------------------------------------------------------------*/
+/* called from OS specific part after init time to get the Law              */
+/* a-law (Euro) and u-law (us,japan) use different BCs in the Setup message */
+void AutomaticLaw(DIVA_CAPI_ADAPTER   *a)
+{
+  word j;
+  PLCI   *splci;
+
+  if(a->automatic_law) {
+    return;
+  }
+  if((j=get_plci(a))) {
+    diva_get_extended_adapter_features (a);
+    splci = &a->plci[j-1];
+    a->automatic_lawPLCI = splci;
+    a->automatic_law = 1;
+    add_p(splci,CAI,"\x01\x80");
+    add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+    splci->internal_command = USELAW_REQ;
+    splci->command = 0;
+    splci->number = 0;
+    sig_req(splci,ASSIGN,DSIG_ID);
+    send_req(splci);
+  }
+}
+
+/* called from OS specific part if an application sends an Capi20Release */
+word CapiRelease(word Id)
+{
+  word i, j, appls_found;
+  PLCI   *plci;
+  APPL   *this;
+  DIVA_CAPI_ADAPTER   *a;
+
+  if (!Id)
+  {
+    dbug(0,dprintf("A: CapiRelease(Id==0)"));
+    return (_WRONG_APPL_ID);
+  }
+
+  this = &application[Id-1];               /* get application pointer */
+
+  for(i=0,appls_found=0; i<max_appl; i++)
+  {
+    if(application[i].Id)       /* an application has been found        */
+    {
+      appls_found++;
+    }
+  }
+
+  for(i=0; i<max_adapter; i++)             /* scan all adapters...    */
+  {
+    a = &adapter[i];
+    if (a->request)
+    {
+      a->Info_Mask[Id-1] = 0;
+      a->CIP_Mask[Id-1] = 0;
+      a->Notification_Mask[Id-1] = 0;
+      a->codec_listen[Id-1] = 0;
+      a->requested_options_table[Id-1] = 0;
+      for(j=0; j<a->max_plci; j++)           /* and all PLCIs connected */
+      {                                      /* with this application   */
+        plci = &a->plci[j];
+        if(plci->Id)                         /* if plci owns no application */
+        {                                    /* it may be not jet connected */
+          if(plci->State==INC_CON_PENDING
+          || plci->State==INC_CON_ALERT)
+          {
+            if(test_c_ind_mask_bit (plci, (word)(Id-1)))
+            {
+              clear_c_ind_mask_bit (plci, (word)(Id-1));
+              if(c_ind_mask_empty (plci))
+              {
+                sig_req(plci,HANGUP,0);
+                send_req(plci);
+                plci->State = OUTG_DIS_PENDING;
+              }
+            }
+          }
+          if(test_c_ind_mask_bit (plci, (word)(Id-1)))
+          {
+            clear_c_ind_mask_bit (plci, (word)(Id-1));
+            if(c_ind_mask_empty (plci))
+            {
+              if(!plci->appl)
+              {
+                plci_remove(plci);
+                plci->State = IDLE;
+              }
+            }
+          }
+          if(plci->appl==this)
+          {
+            plci->appl = 0;
+            plci_remove(plci);
+            plci->State = IDLE;
+          }
+        }
+      }
+      listen_check(a);
+
+      if(a->flag_dynamic_l1_down)
+      {
+        if(appls_found==1)            /* last application does a capi release */
+        {
+          if((j=get_plci(a)))
+          {
+            plci = &a->plci[j-1];
+            plci->command = 0;
+            add_p(plci,OAD,"\x01\xfd");
+            add_p(plci,CAI,"\x01\x80");
+            add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            add_p(plci,SHIFT|6,0);
+            add_p(plci,SIN,"\x02\x00\x00");
+            plci->internal_command = REM_L1_SIG_ASSIGN_PEND;
+            sig_req(plci,ASSIGN,DSIG_ID);
+            add_p(plci,FTY,"\x02\xff\x06"); /* l1 down */
+            sig_req(plci,SIG_CTRL,0);
+            send_req(plci);
+          }
+        }
+      }
+      if(a->AdvSignalAppl==this)
+      {
+        this->NullCREnable = FALSE;
+        if (a->AdvCodecPLCI)
+        {
+          plci_remove(a->AdvCodecPLCI);
+          a->AdvCodecPLCI->tel = 0;
+          a->AdvCodecPLCI->adv_nl = 0;
+        }
+        a->AdvSignalAppl = 0;
+        a->AdvSignalPLCI = 0;
+        a->AdvCodecFLAG = 0;
+        a->AdvCodecPLCI = 0;
+      }
+    }
+  }
+
+  this->Id = 0;
+
+  return GOOD;
+}
+
+static word plci_remove_check(PLCI   *plci)
+{
+  if(!plci) return TRUE;
+  if(!plci->NL.Id && c_ind_mask_empty (plci))
+  {
+    if(plci->Sig.Id == 0xff)
+      plci->Sig.Id = 0;
+    if(!plci->Sig.Id)
+    {
+      dbug(1,dprintf("plci_remove_complete(%x)",plci->Id));
+      dbug(1,dprintf("tel=0x%x,Sig=0x%x",plci->tel,plci->Sig.Id));
+      if (plci->Id)
+      {
+        CodecIdCheck(plci->adapter, plci);
+        clear_b1_config (plci);
+        ncci_remove (plci, 0, FALSE);
+        plci_free_msg_in_queue (plci);
+        channel_flow_control_remove (plci);
+        plci->Id = 0;
+        plci->State = IDLE;
+        plci->channels = 0;
+        plci->appl = 0;
+        plci->notifiedcall = 0;
+      }
+      listen_check(plci->adapter);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+
+/*------------------------------------------------------------------*/
+
+static byte plci_nl_busy (PLCI   *plci)
+{
+  /* only applicable for non-multiplexed protocols */
+  return (plci->nl_req
+    || (plci->ncci_ring_list
+     && plci->adapter->ncci_ch[plci->ncci_ring_list]
+     && (plci->adapter->ch_flow_control[plci->adapter->ncci_ch[plci->ncci_ring_list]] & N_OK_FC_PENDING)));
+}
+
+
+/*------------------------------------------------------------------*/
+/* DTMF facilities                                                  */
+/*------------------------------------------------------------------*/
+
+
+static struct
+{
+  byte send_mask;
+  byte listen_mask;
+  byte character;
+  byte code;
+} dtmf_digit_map[] =
+{
+  { 0x01, 0x01, 0x23, DTMF_DIGIT_TONE_CODE_HASHMARK },
+  { 0x01, 0x01, 0x2a, DTMF_DIGIT_TONE_CODE_STAR },
+  { 0x01, 0x01, 0x30, DTMF_DIGIT_TONE_CODE_0 },
+  { 0x01, 0x01, 0x31, DTMF_DIGIT_TONE_CODE_1 },
+  { 0x01, 0x01, 0x32, DTMF_DIGIT_TONE_CODE_2 },
+  { 0x01, 0x01, 0x33, DTMF_DIGIT_TONE_CODE_3 },
+  { 0x01, 0x01, 0x34, DTMF_DIGIT_TONE_CODE_4 },
+  { 0x01, 0x01, 0x35, DTMF_DIGIT_TONE_CODE_5 },
+  { 0x01, 0x01, 0x36, DTMF_DIGIT_TONE_CODE_6 },
+  { 0x01, 0x01, 0x37, DTMF_DIGIT_TONE_CODE_7 },
+  { 0x01, 0x01, 0x38, DTMF_DIGIT_TONE_CODE_8 },
+  { 0x01, 0x01, 0x39, DTMF_DIGIT_TONE_CODE_9 },
+  { 0x01, 0x01, 0x41, DTMF_DIGIT_TONE_CODE_A },
+  { 0x01, 0x01, 0x42, DTMF_DIGIT_TONE_CODE_B },
+  { 0x01, 0x01, 0x43, DTMF_DIGIT_TONE_CODE_C },
+  { 0x01, 0x01, 0x44, DTMF_DIGIT_TONE_CODE_D },
+  { 0x01, 0x00, 0x61, DTMF_DIGIT_TONE_CODE_A },
+  { 0x01, 0x00, 0x62, DTMF_DIGIT_TONE_CODE_B },
+  { 0x01, 0x00, 0x63, DTMF_DIGIT_TONE_CODE_C },
+  { 0x01, 0x00, 0x64, DTMF_DIGIT_TONE_CODE_D },
+
+  { 0x04, 0x04, 0x80, DTMF_SIGNAL_NO_TONE },
+  { 0x00, 0x04, 0x81, DTMF_SIGNAL_UNIDENTIFIED_TONE },
+  { 0x04, 0x04, 0x82, DTMF_SIGNAL_DIAL_TONE },
+  { 0x04, 0x04, 0x83, DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE },
+  { 0x04, 0x04, 0x84, DTMF_SIGNAL_SPECIAL_DIAL_TONE },
+  { 0x04, 0x04, 0x85, DTMF_SIGNAL_SECOND_DIAL_TONE },
+  { 0x04, 0x04, 0x86, DTMF_SIGNAL_RINGING_TONE },
+  { 0x04, 0x04, 0x87, DTMF_SIGNAL_SPECIAL_RINGING_TONE },
+  { 0x04, 0x04, 0x88, DTMF_SIGNAL_BUSY_TONE },
+  { 0x04, 0x04, 0x89, DTMF_SIGNAL_CONGESTION_TONE },
+  { 0x04, 0x04, 0x8a, DTMF_SIGNAL_SPECIAL_INFORMATION_TONE },
+  { 0x04, 0x04, 0x8b, DTMF_SIGNAL_COMFORT_TONE },
+  { 0x04, 0x04, 0x8c, DTMF_SIGNAL_HOLD_TONE },
+  { 0x04, 0x04, 0x8d, DTMF_SIGNAL_RECORD_TONE },
+  { 0x04, 0x04, 0x8e, DTMF_SIGNAL_CALLER_WAITING_TONE },
+  { 0x04, 0x04, 0x8f, DTMF_SIGNAL_CALL_WAITING_TONE },
+  { 0x04, 0x04, 0x90, DTMF_SIGNAL_PAY_TONE },
+  { 0x04, 0x04, 0x91, DTMF_SIGNAL_POSITIVE_INDICATION_TONE },
+  { 0x04, 0x04, 0x92, DTMF_SIGNAL_NEGATIVE_INDICATION_TONE },
+  { 0x04, 0x04, 0x93, DTMF_SIGNAL_WARNING_TONE },
+  { 0x04, 0x04, 0x94, DTMF_SIGNAL_INTRUSION_TONE },
+  { 0x04, 0x04, 0x95, DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE },
+  { 0x04, 0x04, 0x96, DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE },
+  { 0x04, 0x04, 0x97, DTMF_SIGNAL_CPE_ALERTING_SIGNAL },
+  { 0x04, 0x04, 0x98, DTMF_SIGNAL_OFF_HOOK_WARNING_TONE },
+  { 0x04, 0x04, 0xbf, DTMF_SIGNAL_INTERCEPT_TONE },
+  { 0x04, 0x04, 0xc0, DTMF_SIGNAL_MODEM_CALLING_TONE },
+  { 0x04, 0x04, 0xc1, DTMF_SIGNAL_FAX_CALLING_TONE },
+  { 0x04, 0x04, 0xc2, DTMF_SIGNAL_ANSWER_TONE },
+  { 0x04, 0x04, 0xc3, DTMF_SIGNAL_REVERSED_ANSWER_TONE },
+  { 0x04, 0x04, 0xc4, DTMF_SIGNAL_ANSAM_TONE },
+  { 0x04, 0x04, 0xc5, DTMF_SIGNAL_REVERSED_ANSAM_TONE },
+  { 0x04, 0x04, 0xc6, DTMF_SIGNAL_BELL103_ANSWER_TONE },
+  { 0x04, 0x04, 0xc7, DTMF_SIGNAL_FAX_FLAGS },
+  { 0x04, 0x04, 0xc8, DTMF_SIGNAL_G2_FAX_GROUP_ID },
+  { 0x00, 0x04, 0xc9, DTMF_SIGNAL_HUMAN_SPEECH },
+  { 0x04, 0x04, 0xca, DTMF_SIGNAL_ANSWERING_MACHINE_390 },
+  { 0x02, 0x02, 0xf1, DTMF_MF_DIGIT_TONE_CODE_1 },
+  { 0x02, 0x02, 0xf2, DTMF_MF_DIGIT_TONE_CODE_2 },
+  { 0x02, 0x02, 0xf3, DTMF_MF_DIGIT_TONE_CODE_3 },
+  { 0x02, 0x02, 0xf4, DTMF_MF_DIGIT_TONE_CODE_4 },
+  { 0x02, 0x02, 0xf5, DTMF_MF_DIGIT_TONE_CODE_5 },
+  { 0x02, 0x02, 0xf6, DTMF_MF_DIGIT_TONE_CODE_6 },
+  { 0x02, 0x02, 0xf7, DTMF_MF_DIGIT_TONE_CODE_7 },
+  { 0x02, 0x02, 0xf8, DTMF_MF_DIGIT_TONE_CODE_8 },
+  { 0x02, 0x02, 0xf9, DTMF_MF_DIGIT_TONE_CODE_9 },
+  { 0x02, 0x02, 0xfa, DTMF_MF_DIGIT_TONE_CODE_0 },
+  { 0x02, 0x02, 0xfb, DTMF_MF_DIGIT_TONE_CODE_K1 },
+  { 0x02, 0x02, 0xfc, DTMF_MF_DIGIT_TONE_CODE_K2 },
+  { 0x02, 0x02, 0xfd, DTMF_MF_DIGIT_TONE_CODE_KP },
+  { 0x02, 0x02, 0xfe, DTMF_MF_DIGIT_TONE_CODE_S1 },
+  { 0x02, 0x02, 0xff, DTMF_MF_DIGIT_TONE_CODE_ST },
+
+};
+
+#define DTMF_DIGIT_MAP_ENTRIES (sizeof(dtmf_digit_map) / sizeof(dtmf_digit_map[0]))
+
+
+static void dtmf_enable_receiver (PLCI   *plci, byte enable_mask)
+{
+  word min_digit_duration, min_gap_duration;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_enable_receiver %02x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, enable_mask));
+
+  if (enable_mask != 0)
+  {
+    min_digit_duration = (plci->dtmf_rec_pulse_ms == 0) ? 40 : plci->dtmf_rec_pulse_ms;
+    min_gap_duration = (plci->dtmf_rec_pause_ms == 0) ? 40 : plci->dtmf_rec_pause_ms;
+    plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_ENABLE_RECEIVER;
+    WRITE_WORD (&plci->internal_req_buffer[1], min_digit_duration);
+    WRITE_WORD (&plci->internal_req_buffer[3], min_gap_duration);
+    plci->NData[0].PLength = 5;
+
+    WRITE_WORD (&plci->internal_req_buffer[5], INTERNAL_IND_BUFFER_SIZE);
+    plci->NData[0].PLength += 2;
+    capidtmf_recv_enable (&(plci->capidtmf_state), min_digit_duration, min_gap_duration);
+
+  }
+  else
+  {
+    plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_DISABLE_RECEIVER;
+    plci->NData[0].PLength = 1;
+
+    capidtmf_recv_disable (&(plci->capidtmf_state));
+
+  }
+  plci->NData[0].P = plci->internal_req_buffer;
+  plci->NL.X = plci->NData;
+  plci->NL.ReqCh = 0;
+  plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+  plci->adapter->request (&plci->NL);
+}
+
+
+static void dtmf_send_digits (PLCI   *plci, byte   *digit_buffer, word digit_count)
+{
+  word w, i;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_send_digits %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, digit_count));
+
+  plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_SEND_DIGITS;
+  w = (plci->dtmf_send_pulse_ms == 0) ? 40 : plci->dtmf_send_pulse_ms;
+  WRITE_WORD (&plci->internal_req_buffer[1], w);
+  w = (plci->dtmf_send_pause_ms == 0) ? 40 : plci->dtmf_send_pause_ms;
+  WRITE_WORD (&plci->internal_req_buffer[3], w);
+  for (i = 0; i < digit_count; i++)
+  {
+    w = 0;
+    while ((w < DTMF_DIGIT_MAP_ENTRIES)
+      && (digit_buffer[i] != dtmf_digit_map[w].character))
+    {
+      w++;
+    }
+    plci->internal_req_buffer[5+i] = (w < DTMF_DIGIT_MAP_ENTRIES) ?
+      dtmf_digit_map[w].code : DTMF_DIGIT_TONE_CODE_STAR;
+  }
+  plci->NData[0].PLength = 5 + digit_count;
+  plci->NData[0].P = plci->internal_req_buffer;
+  plci->NL.X = plci->NData;
+  plci->NL.ReqCh = 0;
+  plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+  plci->adapter->request (&plci->NL);
+}
+
+
+static void dtmf_rec_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_rec_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->dtmf_rec_active = 0;
+  plci->dtmf_rec_pulse_ms = 0;
+  plci->dtmf_rec_pause_ms = 0;
+
+  capidtmf_init (&(plci->capidtmf_state), plci->adapter->u_law);
+
+}
+
+
+static void dtmf_send_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_send_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->dtmf_send_requests = 0;
+  plci->dtmf_send_pulse_ms = 0;
+  plci->dtmf_send_pause_ms = 0;
+}
+
+
+static void dtmf_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  while (plci->dtmf_send_requests != 0)
+    dtmf_confirmation (Id, plci);
+}
+
+
+static word dtmf_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word dtmf_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  if (plci->B1_facilities & B1_FACILITY_DTMFR)
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_DTMF_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci_nl_busy (plci))
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+        break;
+      }
+      dtmf_enable_receiver (plci, plci->dtmf_rec_active);
+      plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_2;
+      break;
+    case ADJUST_B_RESTORE_DTMF_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Reenable DTMF receiver failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+static void dtmf_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command, Info;
+  byte mask;
+    byte result[4];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_command %02x %04x %04x %d %d %d %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command,
+    plci->dtmf_cmd, plci->dtmf_rec_pulse_ms, plci->dtmf_rec_pause_ms,
+    plci->dtmf_send_pulse_ms, plci->dtmf_send_pause_ms));
+
+  Info = GOOD;
+  result[0] = 2;
+  WRITE_WORD (&result[1], DTMF_SUCCESS);
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  mask = 0x01;
+  switch (plci->dtmf_cmd)
+  {
+
+  case DTMF_LISTEN_TONE_START:
+    mask <<= 1;
+  case DTMF_LISTEN_MF_START:
+    mask <<= 1;
+
+  case DTMF_LISTEN_START:
+    switch (internal_command)
+    {
+    default:
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+        B1_FACILITY_DTMFR), DTMF_COMMAND_1);
+    case DTMF_COMMAND_1:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Load DTMF failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+    case DTMF_COMMAND_2:
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = DTMF_COMMAND_2;
+        return;
+      }
+      plci->internal_command = DTMF_COMMAND_3;
+      dtmf_enable_receiver (plci, (byte)(plci->dtmf_rec_active | mask));
+      return;
+    case DTMF_COMMAND_3:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Enable DTMF receiver failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+
+      plci->tone_last_indication_code = DTMF_SIGNAL_NO_TONE;
+
+      plci->dtmf_rec_active |= mask;
+      break;
+    }
+    break;
+
+
+  case DTMF_LISTEN_TONE_STOP:
+    mask <<= 1;
+  case DTMF_LISTEN_MF_STOP:
+    mask <<= 1;
+
+  case DTMF_LISTEN_STOP:
+    switch (internal_command)
+    {
+    default:
+      plci->dtmf_rec_active &= ~mask;
+      if (plci->dtmf_rec_active)
+        break;
+/*
+    case DTMF_COMMAND_1:
+      if (plci->dtmf_rec_active)
+      {
+        if (plci_nl_busy (plci))
+        {
+          plci->internal_command = DTMF_COMMAND_1;
+          return;
+        }
+        plci->dtmf_rec_active &= ~mask;
+        plci->internal_command = DTMF_COMMAND_2;
+        dtmf_enable_receiver (plci, FALSE);
+        return;
+      }
+      Rc = OK;
+    case DTMF_COMMAND_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Disable DTMF receiver failed %02x",
+          UnMapId (Id), (char far *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+*/
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
+        ~(B1_FACILITY_DTMFX | B1_FACILITY_DTMFR)), DTMF_COMMAND_3);
+    case DTMF_COMMAND_3:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Unload DTMF failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+      break;
+    }
+    break;
+
+
+  case DTMF_SEND_TONE:
+    mask <<= 1;
+  case DTMF_SEND_MF:
+    mask <<= 1;
+
+  case DTMF_DIGITS_SEND:
+    switch (internal_command)
+    {
+    default:
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+        ((plci->dtmf_parameter_length != 0) ? B1_FACILITY_DTMFX | B1_FACILITY_DTMFR : B1_FACILITY_DTMFX)),
+        DTMF_COMMAND_1);
+    case DTMF_COMMAND_1:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Load DTMF failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+    case DTMF_COMMAND_2:
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = DTMF_COMMAND_2;
+        return;
+      }
+      plci->dtmf_msg_number_queue[(plci->dtmf_send_requests)++] = plci->number;
+      plci->internal_command = DTMF_COMMAND_3;
+      dtmf_send_digits (plci, &plci->saved_msg.parms[3].info[1], plci->saved_msg.parms[3].length);
+      return;
+    case DTMF_COMMAND_3:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Send DTMF digits failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        if (plci->dtmf_send_requests != 0)
+          (plci->dtmf_send_requests)--;
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      return;
+    }
+    break;
+  }
+  sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
+    "wws", Info, SELECTOR_DTMF, result);
+}
+
+
+static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg)
+{
+  word Info;
+  word i, j;
+  byte mask;
+    API_PARSE dtmf_parms[5];
+    byte result[40];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_request",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result[0] = 2;
+  WRITE_WORD (&result[1], DTMF_SUCCESS);
+  if (!(a->profile.Global_Options & GL_DTMF_SUPPORTED))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _FACILITY_NOT_SUPPORTED;
+  }
+  else if (api_parse (&msg[1].info[1], msg[1].length, "w", dtmf_parms))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+
+  else if ((READ_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
+    || (READ_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_SEND_CODES))
+  {
+    if (!((a->requested_options_table[appl->Id-1])
+        & (1L << PRIVATE_DTMF_TONE)))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, READ_WORD (dtmf_parms[0].info)));
+      WRITE_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+    }
+    else
+    {
+      for (i = 0; i < 32; i++)
+        result[4 + i] = 0;
+      if (READ_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
+      {
+        for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
+        {
+          if (dtmf_digit_map[i].listen_mask != 0)
+            result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
+        }
+      }
+      else
+      {
+        for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
+        {
+          if (dtmf_digit_map[i].send_mask != 0)
+            result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
+        }
+      }
+      result[0] = 3 + 32;
+      result[3] = 32;
+    }
+  }
+
+  else if (plci == NULL)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _WRONG_IDENTIFIER;
+  }
+  else
+  {
+    if (!plci->State
+     || !plci->NL.Id || plci->nl_remove_id)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      Info = _WRONG_STATE;
+    }
+    else
+    {
+      plci->command = 0;
+      plci->dtmf_cmd = READ_WORD (dtmf_parms[0].info);
+      mask = 0x01;
+      switch (plci->dtmf_cmd)
+      {
+
+      case DTMF_LISTEN_TONE_START:
+      case DTMF_LISTEN_TONE_STOP:
+        mask <<= 1;
+      case DTMF_LISTEN_MF_START:
+      case DTMF_LISTEN_MF_STOP:
+        mask <<= 1;
+        if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id-1])
+          & (1L << PRIVATE_DTMF_TONE)))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+            UnMapId (Id), (char   *)(FILE_), __LINE__, READ_WORD (dtmf_parms[0].info)));
+          WRITE_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+          break;
+        }
+
+      case DTMF_LISTEN_START:
+      case DTMF_LISTEN_STOP:
+        if (!(a->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
+         && !(a->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (mask & DTMF_LISTEN_ACTIVE_FLAG)
+        {
+          if (api_parse (&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
+          {
+            plci->dtmf_rec_pulse_ms = 0;
+            plci->dtmf_rec_pause_ms = 0;
+          }
+          else
+          {
+            plci->dtmf_rec_pulse_ms = READ_WORD (dtmf_parms[1].info);
+            plci->dtmf_rec_pause_ms = READ_WORD (dtmf_parms[2].info);
+          }
+        }
+        start_internal_command (Id, plci, dtmf_command);
+        return (FALSE);
+
+
+      case DTMF_SEND_TONE:
+        mask <<= 1;
+      case DTMF_SEND_MF:
+        mask <<= 1;
+        if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id-1])
+          & (1L << PRIVATE_DTMF_TONE)))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+            UnMapId (Id), (char   *)(FILE_), __LINE__, READ_WORD (dtmf_parms[0].info)));
+          WRITE_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+          break;
+        }
+
+      case DTMF_DIGITS_SEND:
+        if (api_parse (&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        if (mask & DTMF_LISTEN_ACTIVE_FLAG)
+        {
+          plci->dtmf_send_pulse_ms = READ_WORD (dtmf_parms[1].info);
+          plci->dtmf_send_pause_ms = READ_WORD (dtmf_parms[2].info);
+        }
+        i = 0;
+        j = 0;
+        while ((i < dtmf_parms[3].length) && (j < DTMF_DIGIT_MAP_ENTRIES))
+        {
+          j = 0;
+          while ((j < DTMF_DIGIT_MAP_ENTRIES)
+            && ((dtmf_parms[3].info[i+1] != dtmf_digit_map[j].character)
+             || ((dtmf_digit_map[j].send_mask & mask) == 0)))
+          {
+            j++;
+          }
+          i++;
+        }
+        if (j == DTMF_DIGIT_MAP_ENTRIES)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Incorrect DTMF digit %02x",
+            UnMapId (Id), (char   *)(FILE_), __LINE__, dtmf_parms[3].info[i]));
+          WRITE_WORD (&result[1], DTMF_INCORRECT_DIGIT);
+          break;
+        }
+        if (plci->dtmf_send_requests >=
+          sizeof(plci->dtmf_msg_number_queue) / sizeof(plci->dtmf_msg_number_queue[0]))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: DTMF request overrun",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_STATE;
+          break;
+        }
+        api_save_msg (dtmf_parms, "wwws", &plci->saved_msg);
+        start_internal_command (Id, plci, dtmf_command);
+        return (FALSE);
+
+      default:
+        dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, plci->dtmf_cmd));
+        WRITE_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+      }
+    }
+  }
+  sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+    "wws", Info, SELECTOR_DTMF, result);
+  return (FALSE);
+}
+
+
+static void dtmf_confirmation (dword Id, PLCI   *plci)
+{
+  word Info;
+  word i;
+    byte result[4];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_confirmation",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result[0] = 2;
+  WRITE_WORD (&result[1], DTMF_SUCCESS);
+  if (plci->dtmf_send_requests != 0)
+  {
+    sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->dtmf_msg_number_queue[0],
+      "wws", GOOD, SELECTOR_DTMF, result);
+    (plci->dtmf_send_requests)--;
+    for (i = 0; i < plci->dtmf_send_requests; i++)
+      plci->dtmf_msg_number_queue[i] = plci->dtmf_msg_number_queue[i+1];      
+  }
+}
+
+
+static void dtmf_indication (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+  word i, j, n;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_indication",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  n = 0;
+  for (i = 1; i < length; i++)
+  {
+    j = 0;
+    while ((j < DTMF_DIGIT_MAP_ENTRIES)
+      && ((msg[i] != dtmf_digit_map[j].code)
+       || ((dtmf_digit_map[j].listen_mask & plci->dtmf_rec_active) == 0)))
+    {
+      j++;
+    }
+    if (j < DTMF_DIGIT_MAP_ENTRIES)
+    {
+
+      if ((dtmf_digit_map[j].listen_mask & DTMF_TONE_LISTEN_ACTIVE_FLAG)
+       && (plci->tone_last_indication_code == DTMF_SIGNAL_NO_TONE)
+       && (dtmf_digit_map[j].character != DTMF_SIGNAL_UNIDENTIFIED_TONE))
+      {
+        if (n + 1 == i)
+        {
+          for (i = length; i > n + 1; i--)
+            msg[i] = msg[i - 1];
+          length++;
+          i++;
+        }
+        msg[++n] = DTMF_SIGNAL_UNIDENTIFIED_TONE;
+      }
+      plci->tone_last_indication_code = dtmf_digit_map[j].character;
+
+      msg[++n] = dtmf_digit_map[j].character;
+    }
+  }
+  if (n != 0)
+  {
+    msg[0] = (byte) n;
+    sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "wS", SELECTOR_DTMF, msg);
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* DTMF parameters                                                  */
+/*------------------------------------------------------------------*/
+
+static void dtmf_parameter_write (PLCI   *plci)
+{
+  word i;
+    byte parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE + 2];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_write",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  parameter_buffer[0] = plci->dtmf_parameter_length + 1;
+  parameter_buffer[1] = DSP_CTRL_SET_DTMF_PARAMETERS;
+  for (i = 0; i < plci->dtmf_parameter_length; i++)
+    parameter_buffer[2+i] = plci->dtmf_parameter_buffer[i];
+  add_p (plci, FTY, parameter_buffer);
+  sig_req (plci, TEL_CTRL, 0);
+  send_req (plci);
+}
+
+
+static void dtmf_parameter_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->dtmf_parameter_length = 0;
+}
+
+
+static void dtmf_parameter_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+}
+
+
+static word dtmf_parameter_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word dtmf_parameter_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  if ((plci->B1_facilities & B1_FACILITY_DTMFR)
+   && (plci->dtmf_parameter_length != 0))
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->sig_req)
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
+        break;
+      }
+      dtmf_parameter_write (plci);
+      plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_2;
+      break;
+    case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Restore DTMF parameters failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+/*------------------------------------------------------------------*/
+/* Line interconnect facilities                                     */
+/*------------------------------------------------------------------*/
+
+
+LI_CONFIG   *li_config_table = 0;
+word li_total_channels = 0;
+
+
+/*------------------------------------------------------------------*/
+/* translate a CHI information element to a channel number          */
+/* returns 0xff - any channel                                       */
+/*         0xfe - chi wrong coding                                  */
+/*         0xfd - D-channel                                         */
+/*         0x00 - no channel                                        */
+/*         else channel number / PRI: timeslot                      */
+/* if channels is provided we accept more than one channel.         */
+/*------------------------------------------------------------------*/
+
+static byte chi_to_channel (byte   *chi, dword *pchannelmap)
+{
+  int p;
+  int i;
+  dword map;
+  byte excl;
+  byte ofs;
+  byte ch;
+
+  if (pchannelmap) *pchannelmap = 0;
+  if(!chi[0]) return 0xff;
+  excl = 0;
+
+  if(chi[1] & 0x20) {
+    if(chi[0]==1 && chi[1]==0xac) return 0xfd; /* exclusive d-channel */
+    for(i=1; i<chi[0] && !(chi[i] &0x80); i++);
+    if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
+    if((chi[1] |0xc8)!=0xe9) return 0xfe;
+    if(chi[1] &0x08) excl = 0x40;
+
+        /* int. id present */
+    if(chi[1] &0x40) {
+      p=i+1;
+      for(i=p; i<chi[0] && !(chi[i] &0x80); i++);
+      if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
+    }
+
+        /* coding standard, Number/Map, Channel Type */
+    p=i+1;
+    for(i=p; i<chi[0] && !(chi[i] &0x80); i++);
+    if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
+    if((chi[p]|0xd0)!=0xd3) return 0xfe;
+
+        /* Number/Map */
+    if(chi[p] &0x10) {
+
+        /* map */
+      if((chi[0]-p)==4) ofs = 0;
+      else if((chi[0]-p)==3) ofs = 1;
+      else return 0xfe;
+      ch = 0;
+      map = 0;
+      for(i=0; i<4 && p<chi[0]; i++) {
+        p++;
+        ch += 8;
+        map <<= 8;
+        if(chi[p]) {
+          for (ch=0; !(chi[p] & (1 << ch)); ch++);
+          map |= chi[p];
+        }
+      }
+      ch += ofs;
+      map <<= ofs;
+    }
+    else {
+
+        /* number */
+      p=i+1;
+      ch = chi[p] &0x3f;
+      if(pchannelmap) {
+        if((byte)(chi[0]-p)>30) return 0xfe;
+        map = 0;
+        for(i=p; i<=chi[0]; i++) {
+          if ((chi[i] &0x7f) > 31) return 0xfe;
+          map |= (1L << (chi[i] &0x7f));
+        }
+      }
+      else {
+        if(p!=chi[0]) return 0xfe;
+        if (ch > 31) return 0xfe;
+        map = (1L << ch);
+      }
+      if(chi[p] &0x40) return 0xfe;
+    }
+    if (pchannelmap) *pchannelmap = map;
+    else if (map != ((dword)(1L << ch))) return 0xfe;
+    return (byte)(excl | ch);
+  }
+  else {  /* not PRI */
+    for(i=1; i<chi[0] && !(chi[i] &0x80); i++);
+    if(i!=chi[0] || !(chi[i] &0x80)) return 0xfe;
+    if(chi[1] &0x08) excl = 0x40;
+
+    switch(chi[1] |0x98) {
+    case 0x98: return 0;
+    case 0x99:
+      if (pchannelmap) *pchannelmap = 2;
+      return excl |1;
+    case 0x9a:
+      if (pchannelmap) *pchannelmap = 4;
+      return excl |2;
+    case 0x9b: return 0xff;
+    case 0x9c: return 0xfd; /* d-ch */
+    default: return 0xfe;
+    }
+  }
+}
+
+
+static void mixer_set_bchannel_id_esc (PLCI   *plci, byte bchannel_id)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  PLCI   *splci;
+  byte old_id;
+
+  a = plci->adapter;
+  old_id = plci->li_bchannel_id;
+  if (a->li_pri)
+  {
+    if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+      li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+    plci->li_bchannel_id = (bchannel_id & 0x1f) + 1;
+    if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+      li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+  }
+  else
+  {
+    if (((bchannel_id & 0x03) == 1) || ((bchannel_id & 0x03) == 2))
+    {
+      if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+        li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+      plci->li_bchannel_id = bchannel_id & 0x03;
+      if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+      {
+        splci = a->AdvSignalPLCI;
+        if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
+        {
+          if ((splci->li_bchannel_id != 0)
+           && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
+          {
+            li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
+          }
+          splci->li_bchannel_id = 3 - plci->li_bchannel_id;
+          li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
+          dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id_esc %d",
+            (dword)((splci->Id << 8) | UnMapController (splci->adapter->Id)),
+            (char   *)(FILE_), __LINE__, splci->li_bchannel_id));
+        }
+      }
+      if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+        li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+    }
+  }
+  if ((old_id == 0) && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    mixer_clear_config (plci);
+  }
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_set_bchannel_id_esc %d %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, bchannel_id, plci->li_bchannel_id));
+}
+
+
+static void mixer_set_bchannel_id (PLCI   *plci, byte   *chi)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  PLCI   *splci;
+  byte ch, old_id;
+
+  a = plci->adapter;
+  old_id = plci->li_bchannel_id;
+  ch = chi_to_channel (chi, NULL);
+  if (!(ch & 0x80))
+  {
+    if (a->li_pri)
+    {
+      if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+        li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+      plci->li_bchannel_id = (ch & 0x1f) + 1;
+      if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+        li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+    }
+    else
+    {
+      if (((ch & 0x1f) == 1) || ((ch & 0x1f) == 2))
+      {
+        if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+          li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+        plci->li_bchannel_id = ch & 0x1f;
+        if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+        {
+          splci = a->AdvSignalPLCI;
+          if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
+          {
+            if ((splci->li_bchannel_id != 0)
+             && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
+            {
+              li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
+            }
+            splci->li_bchannel_id = 3 - plci->li_bchannel_id;
+            li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
+            dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
+              (dword)((splci->Id << 8) | UnMapController (splci->adapter->Id)),
+              (char   *)(FILE_), __LINE__, splci->li_bchannel_id));
+          }
+        }
+        if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+          li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+      }
+    }
+  }
+  if ((old_id == 0) && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    mixer_clear_config (plci);
+  }
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_set_bchannel_id %02x %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, ch, plci->li_bchannel_id));
+}
+
+
+#define MIXER_MAX_DUMP_CHANNELS 34
+
+static void mixer_calculate_coefs (DIVA_CAPI_ADAPTER   *a)
+{
+static char hex_digit_table[0x10] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+  word n, i, j;
+  char *p;
+    char hex_line[2 * MIXER_MAX_DUMP_CHANNELS + MIXER_MAX_DUMP_CHANNELS / 8 + 4];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_calculate_coefs",
+    (dword)(UnMapController (a->Id)), (char   *)(FILE_), __LINE__));
+
+  for (i = 0; i < li_total_channels; i++)
+  {
+    li_config_table[i].channel &= LI_CHANNEL_ADDRESSES_SET;
+    if (li_config_table[i].chflags != 0)
+      li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
+    else
+    {
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if (((li_config_table[i].flag_table[j]) != 0)
+         || ((li_config_table[j].flag_table[i]) != 0))
+        {
+          li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
+        }
+        if (((li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE) != 0)
+         || ((li_config_table[j].flag_table[i] & LI_FLAG_CONFERENCE) != 0))
+        {
+          li_config_table[i].channel |= LI_CHANNEL_CONFERENCE;
+        }
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    for (j = 0; j < li_total_channels; j++)
+    {
+      li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC);
+      if (li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE)
+        li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
+    }
+  }
+  for (n = 0; n < li_total_channels; n++)
+  {
+    if (li_config_table[n].channel & LI_CHANNEL_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (li_config_table[i].channel & LI_CHANNEL_CONFERENCE)
+        {
+          for (j = 0; j < li_total_channels; j++)
+          {
+            li_config_table[i].coef_table[j] |=
+              li_config_table[i].coef_table[n] & li_config_table[n].coef_table[j];
+          }
+        }
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      li_config_table[i].coef_table[i] &= ~LI_COEF_CH_CH;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if (li_config_table[i].coef_table[j] & LI_COEF_CH_CH)
+          li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE;
+      }
+      if (li_config_table[i].flag_table[i] & LI_FLAG_CONFERENCE)
+        li_config_table[i].coef_table[i] |= LI_COEF_CH_CH;
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+          li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
+        if (li_config_table[i].flag_table[j] & LI_FLAG_MONITOR)
+          li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
+        if (li_config_table[i].flag_table[j] & LI_FLAG_MIX)
+          li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
+        if (li_config_table[i].flag_table[j] & LI_FLAG_PCCONNECT)
+          li_config_table[i].coef_table[j] |= LI_COEF_PC_PC;
+      }
+      if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+          {
+            li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
+            if (li_config_table[j].chflags & LI_CHFLAG_MIX)
+              li_config_table[i].coef_table[j] |= LI_COEF_PC_CH | LI_COEF_PC_PC;
+          }
+        }
+      }
+      if (li_config_table[i].chflags & LI_CHFLAG_MIX)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT)
+            li_config_table[j].coef_table[i] |= LI_COEF_PC_CH;
+        }
+      }
+      if (li_config_table[i].chflags & LI_CHFLAG_LOOP)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+          {
+            for (n = 0; n < li_total_channels; n++)
+            {
+              if (li_config_table[n].flag_table[i] & LI_FLAG_INTERCONNECT)
+              {
+                li_config_table[n].coef_table[j] |= LI_COEF_CH_CH;
+                if (li_config_table[j].chflags & LI_CHFLAG_MIX)
+                {
+                  li_config_table[n].coef_table[j] |= LI_COEF_PC_CH;
+                  if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
+                    li_config_table[n].coef_table[j] |= LI_COEF_CH_PC | LI_COEF_PC_PC;
+                }
+                else if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
+                  li_config_table[n].coef_table[j] |= LI_COEF_CH_PC;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      if (li_config_table[i].chflags & (LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP))
+        li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
+      if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
+        li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
+      if (li_config_table[i].chflags & LI_CHFLAG_MIX)
+        li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if ((li_config_table[i].flag_table[j] &
+          (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_MONITOR))
+         || (li_config_table[j].flag_table[i] &
+          (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX)))
+        {
+          li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
+        }
+        if (li_config_table[i].flag_table[j] & (LI_FLAG_PCCONNECT | LI_FLAG_MONITOR))
+          li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
+        if (li_config_table[j].flag_table[i] & (LI_FLAG_PCCONNECT | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX))
+          li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
+      }
+      if (!(li_config_table[i].channel & LI_CHANNEL_ACTIVE))
+      {
+        li_config_table[i].coef_table[i] |= LI_COEF_PC_CH | LI_COEF_CH_PC;
+        li_config_table[i].channel |= LI_CHANNEL_TX_DATA | LI_CHANNEL_RX_DATA;
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      j = 0;
+      while ((j < li_total_channels) && !(li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT))
+        j++;
+      if (j < li_total_channels)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_PC_CH);
+          if (li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT)
+            li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
+        }
+      }
+    }
+  }
+  n = li_total_channels;
+  if (n > MIXER_MAX_DUMP_CHANNELS)
+    n = MIXER_MAX_DUMP_CHANNELS;
+  p = hex_line;
+  for (j = 0; j < n; j++)
+  {
+    if ((j & 0x7) == 0)
+      *(p++) = ' ';
+    *(p++) = hex_digit_table[li_config_table[j].curchnl >> 4];
+    *(p++) = hex_digit_table[li_config_table[j].curchnl & 0xf];
+  }
+  *p = '\0';
+  dbug (1, dprintf ("[%06lx] CURRENT %s",
+    (dword)(UnMapController (a->Id)), (char   *) hex_line));
+  p = hex_line;
+  for (j = 0; j < n; j++)
+  {
+    if ((j & 0x7) == 0)
+      *(p++) = ' ';
+    *(p++) = hex_digit_table[li_config_table[j].channel >> 4];
+    *(p++) = hex_digit_table[li_config_table[j].channel & 0xf];
+  }
+  *p = '\0';
+  dbug (1, dprintf ("[%06lx] CHANNEL %s",
+    (dword)(UnMapController (a->Id)), (char   *) hex_line));
+  p = hex_line;
+  for (j = 0; j < n; j++)
+  {
+    if ((j & 0x7) == 0)
+      *(p++) = ' ';
+    *(p++) = hex_digit_table[li_config_table[j].chflags >> 4];
+    *(p++) = hex_digit_table[li_config_table[j].chflags & 0xf];
+  }
+  *p = '\0';
+  dbug (1, dprintf ("[%06lx] CHFLAG  %s",
+    (dword)(UnMapController (a->Id)), (char   *) hex_line));
+  for (i = 0; i < n; i++)
+  {
+    p = hex_line;
+    for (j = 0; j < n; j++)
+    {
+      if ((j & 0x7) == 0)
+        *(p++) = ' ';
+      *(p++) = hex_digit_table[li_config_table[i].flag_table[j] >> 4];
+      *(p++) = hex_digit_table[li_config_table[i].flag_table[j] & 0xf];
+    }
+    *p = '\0';
+    dbug (1, dprintf ("[%06lx] FLAG[%02x]%s",
+      (dword)(UnMapController (a->Id)), i, (char   *) hex_line));
+  }
+  for (i = 0; i < n; i++)
+  {
+    p = hex_line;
+    for (j = 0; j < n; j++)
+    {
+      if ((j & 0x7) == 0)
+        *(p++) = ' ';
+      *(p++) = hex_digit_table[li_config_table[i].coef_table[j] >> 4];
+      *(p++) = hex_digit_table[li_config_table[i].coef_table[j] & 0xf];
+    }
+    *p = '\0';
+    dbug (1, dprintf ("[%06lx] COEF[%02x]%s",
+      (dword)(UnMapController (a->Id)), i, (char   *) hex_line));
+  }
+}
+
+
+static struct
+{
+  byte mask;
+  byte line_flags;
+} mixer_write_prog_pri[] =
+{
+  { LI_COEF_CH_CH, 0 },
+  { LI_COEF_CH_PC, MIXER_COEF_LINE_TO_PC_FLAG },
+  { LI_COEF_PC_CH, MIXER_COEF_LINE_FROM_PC_FLAG },
+  { LI_COEF_PC_PC, MIXER_COEF_LINE_TO_PC_FLAG | MIXER_COEF_LINE_FROM_PC_FLAG }
+};
+
+static struct
+{
+  byte from_ch;
+  byte to_ch;
+  byte mask;
+  byte xconnect_override;
+} mixer_write_prog_bri[] =
+{
+  { 0, 0, LI_COEF_CH_CH, 0x01 },  /* B      to B      */
+  { 1, 0, LI_COEF_CH_CH, 0x01 },  /* Alt B  to B      */
+  { 0, 0, LI_COEF_PC_CH, 0x80 },  /* PC     to B      */
+  { 1, 0, LI_COEF_PC_CH, 0x01 },  /* Alt PC to B      */
+  { 2, 0, LI_COEF_CH_CH, 0x00 },  /* IC     to B      */
+  { 3, 0, LI_COEF_CH_CH, 0x00 },  /* Alt IC to B      */
+  { 0, 0, LI_COEF_CH_PC, 0x80 },  /* B      to PC     */
+  { 1, 0, LI_COEF_CH_PC, 0x01 },  /* Alt B  to PC     */
+  { 0, 0, LI_COEF_PC_PC, 0x01 },  /* PC     to PC     */
+  { 1, 0, LI_COEF_PC_PC, 0x01 },  /* Alt PC to PC     */
+  { 2, 0, LI_COEF_CH_PC, 0x00 },  /* IC     to PC     */
+  { 3, 0, LI_COEF_CH_PC, 0x00 },  /* Alt IC to PC     */
+  { 0, 2, LI_COEF_CH_CH, 0x00 },  /* B      to IC     */
+  { 1, 2, LI_COEF_CH_CH, 0x00 },  /* Alt B  to IC     */
+  { 0, 2, LI_COEF_PC_CH, 0x00 },  /* PC     to IC     */
+  { 1, 2, LI_COEF_PC_CH, 0x00 },  /* Alt PC to IC     */
+  { 2, 2, LI_COEF_CH_CH, 0x00 },  /* IC     to IC     */
+  { 3, 2, LI_COEF_CH_CH, 0x00 },  /* Alt IC to IC     */
+  { 1, 1, LI_COEF_CH_CH, 0x01 },  /* Alt B  to Alt B  */
+  { 0, 1, LI_COEF_CH_CH, 0x01 },  /* B      to Alt B  */
+  { 1, 1, LI_COEF_PC_CH, 0x80 },  /* Alt PC to Alt B  */
+  { 0, 1, LI_COEF_PC_CH, 0x01 },  /* PC     to Alt B  */
+  { 3, 1, LI_COEF_CH_CH, 0x00 },  /* Alt IC to Alt B  */
+  { 2, 1, LI_COEF_CH_CH, 0x00 },  /* IC     to Alt B  */
+  { 1, 1, LI_COEF_CH_PC, 0x80 },  /* Alt B  to Alt PC */
+  { 0, 1, LI_COEF_CH_PC, 0x01 },  /* B      to Alt PC */
+  { 1, 1, LI_COEF_PC_PC, 0x01 },  /* Alt PC to Alt PC */
+  { 0, 1, LI_COEF_PC_PC, 0x01 },  /* PC     to Alt PC */
+  { 3, 1, LI_COEF_CH_PC, 0x00 },  /* Alt IC to Alt PC */
+  { 2, 1, LI_COEF_CH_PC, 0x00 },  /* IC     to Alt PC */
+  { 1, 3, LI_COEF_CH_CH, 0x00 },  /* Alt B  to Alt IC */
+  { 0, 3, LI_COEF_CH_CH, 0x00 },  /* B      to Alt IC */
+  { 1, 3, LI_COEF_PC_CH, 0x00 },  /* Alt PC to Alt IC */
+  { 0, 3, LI_COEF_PC_CH, 0x00 },  /* PC     to Alt IC */
+  { 3, 3, LI_COEF_CH_CH, 0x00 },  /* Alt IC to Alt IC */
+  { 2, 3, LI_COEF_CH_CH, 0x00 }   /* IC     to Alt IC */
+};
+
+static byte mixer_swapped_index_bri[] =
+{
+  18,  /* B      to B      */
+  19,  /* Alt B  to B      */
+  20,  /* PC     to B      */
+  21,  /* Alt PC to B      */
+  22,  /* IC     to B      */
+  23,  /* Alt IC to B      */
+  24,  /* B      to PC     */
+  25,  /* Alt B  to PC     */
+  26,  /* PC     to PC     */
+  27,  /* Alt PC to PC     */
+  28,  /* IC     to PC     */
+  29,  /* Alt IC to PC     */
+  30,  /* B      to IC     */
+  31,  /* Alt B  to IC     */
+  32,  /* PC     to IC     */
+  33,  /* Alt PC to IC     */
+  34,  /* IC     to IC     */
+  35,  /* Alt IC to IC     */
+  0,   /* Alt B  to Alt B  */
+  1,   /* B      to Alt B  */
+  2,   /* Alt PC to Alt B  */
+  3,   /* PC     to Alt B  */
+  4,   /* Alt IC to Alt B  */
+  5,   /* IC     to Alt B  */
+  6,   /* Alt B  to Alt PC */
+  7,   /* B      to Alt PC */
+  8,   /* Alt PC to Alt PC */
+  9,   /* PC     to Alt PC */
+  10,  /* Alt IC to Alt PC */
+  11,  /* IC     to Alt PC */
+  12,  /* Alt B  to Alt IC */
+  13,  /* B      to Alt IC */
+  14,  /* Alt PC to Alt IC */
+  15,  /* PC     to Alt IC */
+  16,  /* Alt IC to Alt IC */
+  17   /* IC     to Alt IC */
+};
+
+static struct
+{
+  byte mask;
+  byte from_pc;
+  byte to_pc;
+} xconnect_write_prog[] =
+{
+  { LI_COEF_CH_CH, FALSE, FALSE },
+  { LI_COEF_CH_PC, FALSE, TRUE },
+  { LI_COEF_PC_CH, TRUE, FALSE },
+  { LI_COEF_PC_PC, TRUE, TRUE }
+};
+
+
+static void xconnect_query_addresses (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word w, ch;
+  byte   *p;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: xconnect_query_addresses",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  if (a->li_pri && ((plci->li_bchannel_id == 0)
+   || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci)))
+  {
+    dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out",
+      (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+      (char   *)(FILE_), __LINE__));
+    return;
+  }
+  p = plci->internal_req_buffer;
+  ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
+  *(p++) = UDATA_REQUEST_XCONNECT_FROM;
+  w = ch;
+  *(p++) = (byte) w;
+  *(p++) = (byte)(w >> 8);
+  w = ch | XCONNECT_CHANNEL_PORT_PC;
+  *(p++) = (byte) w;
+  *(p++) = (byte)(w >> 8);
+  plci->NData[0].P = plci->internal_req_buffer;
+  plci->NData[0].PLength = p - plci->internal_req_buffer;
+  plci->NL.X = plci->NData;
+  plci->NL.ReqCh = 0;
+  plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+  plci->adapter->request (&plci->NL);
+}
+
+
+static void xconnect_write_coefs (PLCI   *plci, word internal_command)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: xconnect_write_coefs %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, internal_command));
+
+  plci->li_write_command = internal_command;
+  plci->li_write_channel = 0;
+}
+
+
+static byte xconnect_write_coefs_process (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word w, n, i, j, r, s, to_ch;
+  dword d;
+  byte   *p;
+  struct xconnect_transfer_address_s   *transfer_address;
+  byte ch_map[MIXER_CHANNELS_BRI];
+
+  dbug (1, dprintf ("[%06x] %s,%d: xconnect_write_coefs_process %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->li_write_channel));
+
+  a = plci->adapter;
+  if ((plci->li_bchannel_id == 0)
+   || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
+  {
+    dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    return (TRUE);
+  }
+  i = a->li_base + (plci->li_bchannel_id - 1);
+  j = plci->li_write_channel;
+  p = plci->internal_req_buffer;
+  if (j != 0)
+  {
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: LI write coefs failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      return (FALSE);
+    }
+  }
+  if (li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+  {
+    r = 0;
+    s = 0;
+    if (j < li_total_channels)
+    {
+      if (li_config_table[i].channel & LI_CHANNEL_ADDRESSES_SET)
+      {
+        s = ((li_config_table[i].send_b.card_address.low | li_config_table[i].send_b.card_address.high) ?
+            (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_PC | LI_COEF_PC_PC)) &
+          ((li_config_table[i].send_pc.card_address.low | li_config_table[i].send_pc.card_address.high) ?
+            (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_PC_CH));
+      }
+      r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+      while ((j < li_total_channels)
+        && ((r == 0)
+         || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
+         || (!li_config_table[j].adapter->li_pri
+          && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
+         || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
+           || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
+          && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
+           || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
+         || ((li_config_table[j].adapter->li_base != a->li_base)
+          && !(r & s &
+            ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
+            ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))))
+      {
+        j++;
+        if (j < li_total_channels)
+          r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+      }
+    }
+    if (j < li_total_channels)
+    {
+      plci->internal_command = plci->li_write_command;
+      if (plci_nl_busy (plci))
+        return (TRUE);
+      to_ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
+      *(p++) = UDATA_REQUEST_XCONNECT_TO;
+      do
+      {
+        if (li_config_table[j].adapter->li_base != a->li_base)
+        {
+          r &= s &
+            ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
+            ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC));
+        }
+        n = 0;
+        do
+        {
+          if (r & xconnect_write_prog[n].mask)
+          {
+            if (xconnect_write_prog[n].from_pc)
+              transfer_address = &(li_config_table[j].send_pc);
+            else
+              transfer_address = &(li_config_table[j].send_b);
+            d = transfer_address->card_address.low;
+            *(p++) = (byte) d;
+            *(p++) = (byte)(d >> 8);
+            *(p++) = (byte)(d >> 16);
+            *(p++) = (byte)(d >> 24);
+            d = transfer_address->card_address.high;
+            *(p++) = (byte) d;
+            *(p++) = (byte)(d >> 8);
+            *(p++) = (byte)(d >> 16);
+            *(p++) = (byte)(d >> 24);
+            d = transfer_address->offset;
+            *(p++) = (byte) d;
+            *(p++) = (byte)(d >> 8);
+            *(p++) = (byte)(d >> 16);
+            *(p++) = (byte)(d >> 24);
+            w = xconnect_write_prog[n].to_pc ? to_ch | XCONNECT_CHANNEL_PORT_PC : to_ch;
+            *(p++) = (byte) w;
+            *(p++) = (byte)(w >> 8);
+            w = ((li_config_table[i].coef_table[j] & xconnect_write_prog[n].mask) == 0) ? 0x01 :
+              (li_config_table[i].adapter->u_law ?
+                 (li_config_table[j].adapter->u_law ? 0x80 : 0x86) :
+                 (li_config_table[j].adapter->u_law ? 0x7a : 0x80));
+            *(p++) = (byte) w;
+            *(p++) = (byte) 0;
+            li_config_table[i].coef_table[j] ^= xconnect_write_prog[n].mask << 4;
+          }
+          n++;
+        } while ((n < sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
+          && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
+        if (n == sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
+        {
+          do
+          {
+            j++;
+            if (j < li_total_channels)
+              r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+          } while ((j < li_total_channels)
+            && ((r == 0)
+             || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
+             || (!li_config_table[j].adapter->li_pri
+              && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
+             || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
+               || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
+              && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
+               || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
+             || ((li_config_table[j].adapter->li_base != a->li_base)
+              && !(r & s &
+                ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
+                  (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
+                ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
+                  (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))));
+        }
+      } while ((j < li_total_channels)
+        && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
+    }
+    else if (j == li_total_channels)
+    {
+      plci->internal_command = plci->li_write_command;
+      if (plci_nl_busy (plci))
+        return (TRUE);
+      if (a->li_pri)
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
+        w = 0;
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+      }
+      else
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
+        w = 0;
+        if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
+         && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
+        {
+          w = READ_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
+        }
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+        for (j = 0; j < sizeof(ch_map); j += 2)
+        {
+          if (plci->li_bchannel_id == 2)
+          {
+            ch_map[j] = (byte)(j+1);
+            ch_map[j+1] = (byte) j;
+          }
+          else
+          {
+            ch_map[j] = (byte) j;
+            ch_map[j+1] = (byte)(j+1);
+          }
+        }
+        for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+        {
+          i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
+          j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
+          if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
+          {
+            *p = (mixer_write_prog_bri[n].xconnect_override != 0) ?
+              mixer_write_prog_bri[n].xconnect_override :
+              ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
+            if ((i >= a->li_base + MIXER_BCHANNELS_BRI) || (j >= a->li_base + MIXER_BCHANNELS_BRI))
+            {
+              w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+              li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
+            }
+          }
+          else
+          {
+            *p = 0x00;
+            if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+            {
+              w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
+              if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
+                *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
+            }
+          }
+          p++;
+        }
+      }
+      j = li_total_channels + 1;
+    }
+  }
+  else
+  {
+    if (j <= li_total_channels)
+    {
+      plci->internal_command = plci->li_write_command;
+      if (plci_nl_busy (plci))
+        return (TRUE);
+      if (j < a->li_base)
+        j = a->li_base;
+      if (a->li_pri)
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
+        w = 0;
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+        for (n = 0; n < sizeof(mixer_write_prog_pri) / sizeof(mixer_write_prog_pri[0]); n++)
+        {
+          *(p++) = (byte)((plci->li_bchannel_id - 1) | mixer_write_prog_pri[n].line_flags);
+          for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
+          {
+            w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+            if (w & mixer_write_prog_pri[n].mask)
+            {
+              *(p++) = (li_config_table[i].coef_table[j] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
+              li_config_table[i].coef_table[j] ^= mixer_write_prog_pri[n].mask << 4;
+            }
+            else
+              *(p++) = 0x00;
+          }
+          *(p++) = (byte)((plci->li_bchannel_id - 1) | MIXER_COEF_LINE_ROW_FLAG | mixer_write_prog_pri[n].line_flags);
+          for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
+          {
+            w = ((li_config_table[j].coef_table[i] & 0xf) ^ (li_config_table[j].coef_table[i] >> 4));
+            if (w & mixer_write_prog_pri[n].mask)
+            {
+              *(p++) = (li_config_table[j].coef_table[i] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
+              li_config_table[j].coef_table[i] ^= mixer_write_prog_pri[n].mask << 4;
+            }
+            else
+              *(p++) = 0x00;
+          }
+        }
+      }
+      else
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
+        w = 0;
+        if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
+         && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
+        {
+          w = READ_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
+        }
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+        for (j = 0; j < sizeof(ch_map); j += 2)
+        {
+          if (plci->li_bchannel_id == 2)
+          {
+            ch_map[j] = (byte)(j+1);
+            ch_map[j+1] = (byte) j;
+          }
+          else
+          {
+            ch_map[j] = (byte) j;
+            ch_map[j+1] = (byte)(j+1);
+          }
+        }
+        for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+        {
+          i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
+          j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
+          if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
+          {
+            *p = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
+            w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+            li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
+          }
+          else
+          {
+            *p = 0x00;
+            if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+            {
+              w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
+              if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
+                *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
+            }
+          }
+          p++;
+        }
+      }
+      j = li_total_channels + 1;
+    }
+  }
+  plci->li_write_channel = j;
+  if (p != plci->internal_req_buffer)
+  {
+    plci->NData[0].P = plci->internal_req_buffer;
+    plci->NData[0].PLength = p - plci->internal_req_buffer;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+    plci->adapter->request (&plci->NL);
+  }
+  return (TRUE);
+}
+
+
+static void mixer_notify_update (PLCI   *plci, byte others)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, w;
+  PLCI   *notify_plci;
+    byte msg[sizeof(CAPI_MSG_HEADER) + 6];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_notify_update %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, others));
+
+  a = plci->adapter;
+  if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
+  {
+    if (others)
+      plci->li_notify_update = TRUE;
+    i = 0;
+    do
+    {
+      notify_plci = NULL;
+      if (others)
+      {
+        while ((i < li_total_channels) && (li_config_table[i].plci == NULL))
+          i++;
+        if (i < li_total_channels)
+          notify_plci = li_config_table[i++].plci;
+      }
+      else
+      {
+        if ((plci->li_bchannel_id != 0)
+         && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+        {
+          notify_plci = plci;
+        }
+      }
+      if ((notify_plci != NULL)
+       && !notify_plci->li_notify_update
+       && (notify_plci->appl != NULL)
+       && (notify_plci->State)
+       && notify_plci->NL.Id && !notify_plci->nl_remove_id)
+      {
+        notify_plci->li_notify_update = TRUE;
+        ((CAPI_MSG *) msg)->header.length = 18;
+        ((CAPI_MSG *) msg)->header.appl_id = notify_plci->appl->Id;
+        ((CAPI_MSG *) msg)->header.command = _FACILITY_R;
+        ((CAPI_MSG *) msg)->header.number = 0;
+        ((CAPI_MSG *) msg)->header.controller = notify_plci->adapter->Id;
+        ((CAPI_MSG *) msg)->header.plci = notify_plci->Id;
+        ((CAPI_MSG *) msg)->header.ncci = 0;
+        ((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT;
+        ((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3;
+        WRITE_WORD (&(((CAPI_MSG *) msg)->info.facility_req.structs[1]), LI_REQ_SILENT_UPDATE);
+        ((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0;
+        w = api_put (notify_plci->appl, (CAPI_MSG *) msg);
+        if (w != _QUEUE_FULL)
+        {
+          if (w != 0)
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Interconnect notify failed %06x %d",
+              (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+              (char   *)(FILE_), __LINE__,
+              (dword)((notify_plci->Id << 8) | UnMapController (notify_plci->adapter->Id)), w));
+          }
+          notify_plci->li_notify_update = FALSE;
+        }
+      }
+    } while (others && (notify_plci != NULL));
+    if (others)
+      plci->li_notify_update = FALSE;
+  }
+}
+
+
+static void mixer_clear_config (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, j;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->li_notify_update = FALSE;
+  plci->li_plci_b_write_pos = 0;
+  plci->li_plci_b_read_pos = 0;
+  plci->li_plci_b_req_pos = 0;
+  a = plci->adapter;
+  if ((plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    li_config_table[i].curchnl = 0;
+    li_config_table[i].channel = 0;
+    li_config_table[i].chflags = 0;
+    for (j = 0; j < li_total_channels; j++)
+    {
+      li_config_table[j].flag_table[i] = 0;
+      li_config_table[i].flag_table[j] = 0;
+      li_config_table[i].coef_table[j] = 0;
+      li_config_table[j].coef_table[i] = 0;
+    }
+    if (!a->li_pri)
+    {
+      li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
+      if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+      {
+        i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+        li_config_table[i].curchnl = 0;
+        li_config_table[i].channel = 0;
+        li_config_table[i].chflags = 0;
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[i].flag_table[j] = 0;
+          li_config_table[j].flag_table[i] = 0;
+          li_config_table[i].coef_table[j] = 0;
+          li_config_table[j].coef_table[i] = 0;
+        }
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+        {
+          i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+          li_config_table[i].curchnl = 0;
+          li_config_table[i].channel = 0;
+          li_config_table[i].chflags = 0;
+          for (j = 0; j < li_total_channels; j++)
+          {
+            li_config_table[i].flag_table[j] = 0;
+            li_config_table[j].flag_table[i] = 0;
+            li_config_table[i].coef_table[j] = 0;
+            li_config_table[j].coef_table[i] = 0;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+static void mixer_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  do
+  {
+    mixer_indication_coefs_set (Id, plci);
+  } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
+}
+
+
+static word mixer_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, j;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  a = plci->adapter;
+  if ((plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    for (j = 0; j < li_total_channels; j++)
+    {
+      li_config_table[i].coef_table[j] &= 0xf;
+      li_config_table[j].coef_table[i] &= 0xf;
+    }
+    if (!a->li_pri)
+      li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
+  }
+  return (GOOD);
+}
+
+
+static word mixer_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  a = plci->adapter;
+  if ((plci->B1_facilities & B1_FACILITY_MIXER)
+   && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_MIXER_1:
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        if (plci_nl_busy (plci))
+        {
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
+          break;
+        }
+        xconnect_query_addresses (plci);
+        plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_2;
+        break;
+      }
+      plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
+      Rc = OK;
+    case ADJUST_B_RESTORE_MIXER_2:
+    case ADJUST_B_RESTORE_MIXER_3:
+    case ADJUST_B_RESTORE_MIXER_4:
+      if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B query addresses failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      if (Rc == OK)
+      {
+        if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_3;
+        else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
+      }
+      else if (Rc == 0)
+      {
+        if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_4;
+        else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
+      }
+      if (plci->adjust_b_state != ADJUST_B_RESTORE_MIXER_5)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+    case ADJUST_B_RESTORE_MIXER_5:
+      xconnect_write_coefs (plci, plci->adjust_b_command);
+      plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_6;
+      Rc = OK;
+    case ADJUST_B_RESTORE_MIXER_6:
+      if (!xconnect_write_coefs_process (Id, plci, Rc))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Write mixer coefs failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        break;
+      plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_7;
+    case ADJUST_B_RESTORE_MIXER_7:
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+static void mixer_command (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, internal_command, Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_command %02x %04x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command,
+    plci->li_cmd));
+
+  Info = GOOD;
+  a = plci->adapter;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (plci->li_cmd)
+  {
+  case LI_REQ_CONNECT:
+  case LI_REQ_DISCONNECT:
+  case LI_REQ_SILENT_UPDATE:
+    switch (internal_command)
+    {
+    default:
+      if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+      {
+        adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+          B1_FACILITY_MIXER), MIXER_COMMAND_1);
+      }
+    case MIXER_COMMAND_1:
+      if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+      {
+        if (adjust_b_process (Id, plci, Rc) != GOOD)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Load mixer failed",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (plci->internal_command)
+          return;
+      }
+      plci->li_plci_b_req_pos = plci->li_plci_b_write_pos;
+      if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+       || ((get_b1_facilities (plci, plci->B1_resource) & B1_FACILITY_MIXER)
+        && (add_b1_facilities (plci, plci->B1_resource, (word)(plci->B1_facilities &
+         ~B1_FACILITY_MIXER)) == plci->B1_resource)))
+      {
+        xconnect_write_coefs (plci, MIXER_COMMAND_2);
+      }
+      else
+      {
+        do
+        {
+          mixer_indication_coefs_set (Id, plci);
+        } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
+      }
+    case MIXER_COMMAND_2:
+      if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+       || ((get_b1_facilities (plci, plci->B1_resource) & B1_FACILITY_MIXER)
+        && (add_b1_facilities (plci, plci->B1_resource, (word)(plci->B1_facilities &
+         ~B1_FACILITY_MIXER)) == plci->B1_resource)))
+      {
+        if (!xconnect_write_coefs_process (Id, plci, Rc))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Write mixer coefs failed",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          if (plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
+          {
+            do
+            {
+              plci->li_plci_b_write_pos = (plci->li_plci_b_write_pos == 0) ?
+                LI_PLCI_B_QUEUE_ENTRIES-1 : plci->li_plci_b_write_pos - 1;
+              i = (plci->li_plci_b_write_pos == 0) ?
+                LI_PLCI_B_QUEUE_ENTRIES-1 : plci->li_plci_b_write_pos - 1;
+            } while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
+              && !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG));
+          }
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (plci->internal_command)
+          return;
+      }
+      if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
+      {
+        adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
+          ~B1_FACILITY_MIXER), MIXER_COMMAND_3);
+      }
+    case MIXER_COMMAND_3:
+      if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
+      {
+        if (adjust_b_process (Id, plci, Rc) != GOOD)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Unload mixer failed",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (plci->internal_command)
+          return;
+      }
+      break;
+    }
+    break;
+  }
+  if ((plci->li_bchannel_id == 0)
+   || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
+  {
+    dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out %d",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, (int)(plci->li_bchannel_id)));
+  }
+  else
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    li_config_table[i].curchnl = plci->li_channel_bits;
+    if (!a->li_pri && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+    {
+      i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      li_config_table[i].curchnl = plci->li_channel_bits;
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+        li_config_table[i].curchnl = plci->li_channel_bits;
+      }
+    }
+  }
+}
+
+
+static void li_update_connect (dword Id, DIVA_CAPI_ADAPTER   *a, PLCI   *plci,
+  dword plci_b_id, byte connect, dword li_flags)
+{
+  word i, ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
+  PLCI   *plci_b;
+  DIVA_CAPI_ADAPTER   *a_b;
+
+  a_b = &(adapter[MapController ((byte)(plci_b_id & 0x7f)) - 1]);
+  plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
+  ch_a = a->li_base + (plci->li_bchannel_id - 1);
+  if (!a->li_pri && (plci->tel == ADV_VOICE)
+   && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
+  {
+    ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
+    ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
+  }
+  else
+  {
+    ch_a_v = ch_a;
+    ch_a_s = ch_a;
+  }
+  ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
+  if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
+   && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
+  {
+    ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
+    ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
+  }
+  else
+  {
+    ch_b_v = ch_b;
+    ch_b_s = ch_b;
+  }
+  if (connect)
+  {
+    li_config_table[ch_a].flag_table[ch_a_v] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_a].flag_table[ch_a_s] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_a_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+    li_config_table[ch_a_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+  }
+  li_config_table[ch_a].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
+  li_config_table[ch_a].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
+  li_config_table[ch_b_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+  li_config_table[ch_b_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+  if (ch_a_v == ch_b_v)
+  {
+    li_config_table[ch_a_v].flag_table[ch_b_v] &= ~LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_b_s] &= ~LI_FLAG_CONFERENCE;
+  }
+  else
+  {
+    if (li_config_table[ch_a_v].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_v)
+          li_config_table[ch_a_v].flag_table[i] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+    if (li_config_table[ch_a_s].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_s)
+          li_config_table[ch_a_s].flag_table[i] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+    if (li_config_table[ch_b_v].flag_table[ch_a_v] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_v)
+          li_config_table[i].flag_table[ch_a_v] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+    if (li_config_table[ch_b_v].flag_table[ch_a_s] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_s)
+          li_config_table[i].flag_table[ch_a_s] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+  }
+  if (li_flags & LI_FLAG_CONFERENCE_A_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+  }
+  if (li_flags & LI_FLAG_CONFERENCE_B_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+  }
+  if (li_flags & LI_FLAG_MONITOR_A)
+  {
+    li_config_table[ch_a].flag_table[ch_a_v] |= LI_FLAG_MONITOR;
+    li_config_table[ch_a].flag_table[ch_a_s] |= LI_FLAG_MONITOR;
+  }
+  if (li_flags & LI_FLAG_MONITOR_B)
+  {
+    li_config_table[ch_a].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
+    li_config_table[ch_a].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
+  }
+  if (li_flags & LI_FLAG_ANNOUNCEMENT_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+    li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+  }
+  if (li_flags & LI_FLAG_ANNOUNCEMENT_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+    li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+  }
+  if (li_flags & LI_FLAG_MIX_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_MIX;
+    li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_MIX;
+  }
+  if (li_flags & LI_FLAG_MIX_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_MIX;
+    li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_MIX;
+  }
+  if (ch_a_v != ch_a_s)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+  }
+  if (ch_b_v != ch_b_s)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+  }
+}
+
+
+static void li2_update_connect (dword Id, DIVA_CAPI_ADAPTER   *a, PLCI   *plci,
+  dword plci_b_id, byte connect, dword li_flags)
+{
+  word ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
+  PLCI   *plci_b;
+  DIVA_CAPI_ADAPTER   *a_b;
+
+  a_b = &(adapter[MapController ((byte)(plci_b_id & 0x7f)) - 1]);
+  plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
+  ch_a = a->li_base + (plci->li_bchannel_id - 1);
+  if (!a->li_pri && (plci->tel == ADV_VOICE)
+   && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
+  {
+    ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
+    ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
+  }
+  else
+  {
+    ch_a_v = ch_a;
+    ch_a_s = ch_a;
+  }
+  ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
+  if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
+   && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
+  {
+    ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
+    ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
+  }
+  else
+  {
+    ch_b_v = ch_b;
+    ch_b_s = ch_b;
+  }
+  if (connect)
+  {
+    li_config_table[ch_b].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_b].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_b_v].flag_table[ch_b] &= ~LI_FLAG_MIX;
+    li_config_table[ch_b_s].flag_table[ch_b] &= ~LI_FLAG_MIX;
+    li_config_table[ch_b].flag_table[ch_b] &= ~LI_FLAG_PCCONNECT;
+    li_config_table[ch_b].chflags &= ~(LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP);
+  }
+  li_config_table[ch_b_v].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_b_s].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_b_v].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_b_s].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_v].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_v].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_s].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_s].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  if (li_flags & LI2_FLAG_INTERCONNECT_A_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
+  }
+  if (li_flags & LI2_FLAG_INTERCONNECT_B_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+  }
+  if (li_flags & LI2_FLAG_MONITOR_B)
+  {
+    li_config_table[ch_b].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
+    li_config_table[ch_b].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
+  }
+  if (li_flags & LI2_FLAG_MIX_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b] |= LI_FLAG_MIX;
+    li_config_table[ch_b_s].flag_table[ch_b] |= LI_FLAG_MIX;
+  }
+  if (li_flags & LI2_FLAG_MONITOR_X)
+    li_config_table[ch_b].chflags |= LI_CHFLAG_MONITOR;
+  if (li_flags & LI2_FLAG_MIX_X)
+    li_config_table[ch_b].chflags |= LI_CHFLAG_MIX;
+  if (li_flags & LI2_FLAG_LOOP_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+  }
+  if (li_flags & LI2_FLAG_LOOP_PC)
+    li_config_table[ch_b].flag_table[ch_b] |= LI_FLAG_PCCONNECT;
+  if (li_flags & LI2_FLAG_LOOP_X)
+    li_config_table[ch_b].chflags |= LI_CHFLAG_LOOP;
+  if (li_flags & LI2_FLAG_PCCONNECT_A_B)
+    li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_PCCONNECT;
+  if (li_flags & LI2_FLAG_PCCONNECT_B_A)
+    li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_PCCONNECT;
+  if (ch_a_v != ch_a_s)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+  }
+  if (ch_b_v != ch_b_s)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+  }
+}
+
+
+static word li_check_main_plci (dword Id, PLCI   *plci)
+{
+  if (plci == NULL)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    return (_WRONG_IDENTIFIER);
+  }
+  if (!plci->State
+   || !plci->NL.Id || plci->nl_remove_id
+   || (plci->li_bchannel_id == 0))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    return (_WRONG_STATE);
+  }
+  li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+  return (GOOD);
+}
+
+
+static PLCI   *li_check_plci_b (dword Id, PLCI   *plci,
+  dword plci_b_id, word plci_b_write_pos, byte   *p_result)
+{
+  byte ctlr_b;
+  PLCI   *plci_b;
+
+  if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+    LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    WRITE_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
+    return (NULL);
+  }
+  ctlr_b = 0;
+  if ((plci_b_id & 0x7f) != 0)
+  {
+    ctlr_b = MapController ((byte)(plci_b_id & 0x7f));
+    if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
+      ctlr_b = 0;
+  }
+  if ((ctlr_b == 0)
+   || (((plci_b_id >> 8) & 0xff) == 0)
+   || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI invalid second PLCI %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    WRITE_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
+  if (!plci_b->State
+   || !plci_b->NL.Id || plci_b->nl_remove_id
+   || (plci_b->li_bchannel_id == 0))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI peer in wrong state %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    WRITE_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
+    return (NULL);
+  }
+  li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci = plci_b;
+  if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
+    ((byte)(UnMapController (plci->adapter->Id) & ~EXT_CONTROLLER))
+   && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+    || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI not on same ctrl %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    WRITE_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  if (!(get_b1_facilities (plci_b, add_b1_facilities (plci_b, plci_b->B1_resource,
+    (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Interconnect peer cannot mix %d",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b->B1_resource));
+    WRITE_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
+    return (NULL);
+  }
+  return (plci_b);
+}
+
+
+static PLCI   *li2_check_plci_b (dword Id, PLCI   *plci,
+  dword plci_b_id, word plci_b_write_pos, byte   *p_result)
+{
+  byte ctlr_b;
+  PLCI   *plci_b;
+
+  if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+    LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    WRITE_WORD (p_result, _WRONG_STATE);
+    return (NULL);
+  }
+  ctlr_b = 0;
+  if ((plci_b_id & 0x7f) != 0)
+  {
+    ctlr_b = MapController ((byte)(plci_b_id & 0x7f));
+    if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
+      ctlr_b = 0;
+  }
+  if ((ctlr_b == 0)
+   || (((plci_b_id >> 8) & 0xff) == 0)
+   || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI invalid second PLCI %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    WRITE_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
+  if (!plci_b->State
+   || !plci_b->NL.Id || plci_b->nl_remove_id
+   || (plci_b->li_bchannel_id == 0)
+   || (li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci != plci_b))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI peer in wrong state %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    WRITE_WORD (p_result, _WRONG_STATE);
+    return (NULL);
+  }
+  if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
+    ((byte)(UnMapController (plci->adapter->Id) & ~EXT_CONTROLLER))
+   && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+    || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI not on same ctrl %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    WRITE_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  if (!(get_b1_facilities (plci_b, add_b1_facilities (plci_b, plci_b->B1_resource,
+    (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Interconnect peer cannot mix %d",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b->B1_resource));
+    WRITE_WORD (p_result, _WRONG_STATE);
+    return (NULL);
+  }
+  return (plci_b);
+}
+
+
+static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg)
+{
+  word Info;
+  word i;
+  dword d, li_flags, plci_b_id;
+  PLCI   *plci_b;
+    API_PARSE li_parms[3];
+    API_PARSE li_req_parms[3];
+    API_PARSE li_participant_struct[2];
+    API_PARSE li_participant_parms[3];
+  word participant_parms_pos;
+  byte result_buffer[32];
+  byte   *result;
+  word result_pos;
+  word plci_b_write_pos;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_request",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result = result_buffer;
+  result_buffer[0] = 0;
+  if (!(a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _FACILITY_NOT_SUPPORTED;
+  }
+  else if (api_parse (&msg[1].info[1], msg[1].length, "ws", li_parms))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+  else
+  {
+    result_buffer[0] = 3;
+    WRITE_WORD (&result_buffer[1], READ_WORD (li_parms[0].info));
+    result_buffer[3] = 0;
+    switch (READ_WORD (li_parms[0].info))
+    {
+    case LI_GET_SUPPORTED_SERVICES:
+      if (appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
+      {
+        result_buffer[0] = 17;
+        result_buffer[3] = 14;
+        WRITE_WORD (&result_buffer[4], GOOD);
+        d = 0;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_CH)
+          d |= LI_CONFERENCING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
+          d |= LI_MONITORING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
+          d |= LI_ANNOUNCEMENTS_SUPPORTED | LI_MIXING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+          d |= LI_CROSS_CONTROLLER_SUPPORTED;
+        WRITE_DWORD (&result_buffer[6], d);
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+        {
+          d = 0;
+          for (i = 0; i < li_total_channels; i++)
+          {
+            if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+             && (li_config_table[i].adapter->li_pri
+              || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
+            {
+              d++;
+            }
+          }
+        }
+        else
+        {
+          d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
+        }
+        WRITE_DWORD (&result_buffer[10], d / 2);
+        WRITE_DWORD (&result_buffer[14], d);
+      }
+      else
+      {
+        result_buffer[0] = 25;
+        result_buffer[3] = 22;
+        WRITE_WORD (&result_buffer[4], GOOD);
+        d = LI2_ASYMMETRIC_SUPPORTED | LI2_B_LOOPING_SUPPORTED | LI2_X_LOOPING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
+          d |= LI2_MONITORING_SUPPORTED | LI2_REMOTE_MONITORING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
+          d |= LI2_MIXING_SUPPORTED | LI2_REMOTE_MIXING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_PC)
+          d |= LI2_PC_LOOPING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+          d |= LI2_CROSS_CONTROLLER_SUPPORTED;
+        WRITE_DWORD (&result_buffer[6], d);
+        d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
+        WRITE_DWORD (&result_buffer[10], d / 2);
+        WRITE_DWORD (&result_buffer[14], d - 1);
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+        {
+          d = 0;
+          for (i = 0; i < li_total_channels; i++)
+          {
+            if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+             && (li_config_table[i].adapter->li_pri
+              || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
+            {
+              d++;
+            }
+          }
+        }
+        WRITE_DWORD (&result_buffer[18], d / 2);
+        WRITE_DWORD (&result_buffer[22], d - 1);
+      }
+      break;
+
+    case LI_REQ_CONNECT:
+      if (li_parms[1].length == 8)
+      {
+        appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "dd", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        plci_b_id = READ_DWORD (li_req_parms[0].info) & 0xffff;
+        li_flags = READ_DWORD (li_req_parms[1].info);
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 9;
+        result_buffer[3] = 6;
+        WRITE_DWORD (&result_buffer[4], plci_b_id);
+        WRITE_WORD (&result_buffer[8], GOOD);
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
+        if (plci_b == NULL)
+          break;
+        li_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
+        plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_LAST_FLAG;
+        plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      else
+      {
+        appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "ds", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        li_flags = READ_DWORD (li_req_parms[0].info) & ~(LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A);
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 7;
+        result_buffer[3] = 4;
+        WRITE_WORD (&result_buffer[4], Info);
+        result_buffer[6] = 0;
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        participant_parms_pos = 0;
+        result_pos = 7;
+        li2_update_connect (Id, a, plci, UnMapId (Id), TRUE, li_flags);
+        while (participant_parms_pos < li_req_parms[1].length)
+        {
+          result[result_pos] = 6;
+          result_pos += 7;
+          WRITE_DWORD (&result[result_pos - 6], 0);
+          WRITE_WORD (&result[result_pos - 2], GOOD);
+          if (api_parse (&li_req_parms[1].info[1 + participant_parms_pos],
+            (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            WRITE_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          if (api_parse (&li_participant_struct[0].info[1],
+            li_participant_struct[0].length, "dd", li_participant_parms))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            WRITE_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          plci_b_id = READ_DWORD (li_participant_parms[0].info) & 0xffff;
+          li_flags = READ_DWORD (li_participant_parms[1].info);
+          WRITE_DWORD (&result[result_pos - 6], plci_b_id);
+          if (sizeof(result) - result_pos < 7)
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: LI result overrun",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            WRITE_WORD (&result[result_pos - 2], _WRONG_STATE);
+            break;
+          }
+          plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
+          if (plci_b != NULL)
+          {
+            li2_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
+            plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id |
+              ((li_flags & (LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A |
+              LI2_FLAG_PCCONNECT_A_B | LI2_FLAG_PCCONNECT_B_A)) ? 0 : LI_PLCI_B_DISC_FLAG);
+            plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+          }
+          participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
+            (&li_req_parms[1].info[1]));
+        }
+        result[0] = (byte)(result_pos - 1);
+        result[3] = (byte)(result_pos - 4);
+        result[6] = (byte)(result_pos - 7);
+        i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
+        if ((plci_b_write_pos == plci->li_plci_b_read_pos)
+         || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
+        {
+          plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
+          plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        }
+        else
+          plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      mixer_calculate_coefs (a);
+      plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
+      mixer_notify_update (plci, TRUE);
+      sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+        "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
+      plci->command = 0;
+      plci->li_cmd = READ_WORD (li_parms[0].info);
+      start_internal_command (Id, plci, mixer_command);
+      return (FALSE);
+
+    case LI_REQ_DISCONNECT:
+      if (li_parms[1].length == 4)
+      {
+        appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "d", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        plci_b_id = READ_DWORD (li_req_parms[0].info) & 0xffff;
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 9;
+        result_buffer[3] = 6;
+        WRITE_DWORD (&result_buffer[4], READ_DWORD (li_req_parms[0].info));
+        WRITE_WORD (&result_buffer[8], GOOD);
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
+        if (plci_b == NULL)
+          break;
+        li_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
+        plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG | LI_PLCI_B_LAST_FLAG;
+        plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      else
+      {
+        appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "s", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 7;
+        result_buffer[3] = 4;
+        WRITE_WORD (&result_buffer[4], Info);
+        result_buffer[6] = 0;
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        participant_parms_pos = 0;
+        result_pos = 7;
+        while (participant_parms_pos < li_req_parms[0].length)
+        {
+          result[result_pos] = 6;
+          result_pos += 7;
+          WRITE_DWORD (&result[result_pos - 6], 0);
+          WRITE_WORD (&result[result_pos - 2], GOOD);
+          if (api_parse (&li_req_parms[0].info[1 + participant_parms_pos],
+            (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            WRITE_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          if (api_parse (&li_participant_struct[0].info[1],
+            li_participant_struct[0].length, "d", li_participant_parms))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            WRITE_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          plci_b_id = READ_DWORD (li_participant_parms[0].info) & 0xffff;
+          WRITE_DWORD (&result[result_pos - 6], plci_b_id);
+          if (sizeof(result) - result_pos < 7)
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: LI result overrun",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            WRITE_WORD (&result[result_pos - 2], _WRONG_STATE);
+            break;
+          }
+          plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
+          if (plci_b != NULL)
+          {
+            li2_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
+            plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
+            plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+          }
+          participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
+            (&li_req_parms[0].info[1]));
+        }
+        result[0] = (byte)(result_pos - 1);
+        result[3] = (byte)(result_pos - 4);
+        result[6] = (byte)(result_pos - 7);
+        i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
+        if ((plci_b_write_pos == plci->li_plci_b_read_pos)
+         || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
+        {
+          plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
+          plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        }
+        else
+          plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      mixer_calculate_coefs (a);
+      plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
+      mixer_notify_update (plci, TRUE);
+      sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+        "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
+      plci->command = 0;
+      plci->li_cmd = READ_WORD (li_parms[0].info);
+      start_internal_command (Id, plci, mixer_command);
+      return (FALSE);
+
+    case LI_REQ_SILENT_UPDATE:
+      if (!plci || !plci->State
+       || !plci->NL.Id || plci->nl_remove_id
+       || (plci->li_bchannel_id == 0)
+       || (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci != plci))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        return (FALSE);
+      }
+      plci_b_write_pos = plci->li_plci_b_write_pos;
+      if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+        LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        return (FALSE);
+      }
+      i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
+      if ((plci_b_write_pos == plci->li_plci_b_read_pos)
+       || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
+      {
+        plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
+        plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+      }
+      else
+        plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
+      plci->li_plci_b_write_pos = plci_b_write_pos;
+      plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
+      plci->command = 0;
+      plci->li_cmd = READ_WORD (li_parms[0].info);
+      start_internal_command (Id, plci, mixer_command);
+      return (FALSE);
+
+    default:
+      dbug (1, dprintf ("[%06lx] %s,%d: LI unknown request %04x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, READ_WORD (li_parms[0].info)));
+      Info = _FACILITY_NOT_SUPPORTED;
+    }
+  }
+  sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+    "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
+  return (FALSE);
+}
+
+
+static void mixer_indication_coefs_set (dword Id, PLCI   *plci)
+{
+  dword d;
+  DIVA_CAPI_ADAPTER   *a;
+    byte result[12];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_coefs_set",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos)
+  {
+    do
+    {
+      d = plci->li_plci_b_queue[plci->li_plci_b_read_pos];
+      if (!(d & LI_PLCI_B_SKIP_FLAG))
+      {
+        if (plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
+        {
+          if (d & LI_PLCI_B_DISC_FLAG)
+          {
+            result[0] = 5;
+            WRITE_WORD (&result[1], LI_IND_DISCONNECT);
+            result[3] = 2;
+            WRITE_WORD (&result[4], _LI_USER_INITIATED);
+          }
+          else
+          {
+            result[0] = 7;
+            WRITE_WORD (&result[1], LI_IND_CONNECT_ACTIVE);
+            result[3] = 4;
+            WRITE_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
+          }
+        }
+        else
+        {
+          if (d & LI_PLCI_B_DISC_FLAG)
+          {
+            result[0] = 9;
+            WRITE_WORD (&result[1], LI_IND_DISCONNECT);
+            result[3] = 6;
+            WRITE_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
+            WRITE_WORD (&result[8], _LI_USER_INITIATED);
+          }
+          else
+          {
+            result[0] = 7;
+            WRITE_WORD (&result[1], LI_IND_CONNECT_ACTIVE);
+            result[3] = 4;
+            WRITE_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
+          }
+        }
+        sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0,
+          "ws", SELECTOR_LINE_INTERCONNECT, result);
+      }
+      plci->li_plci_b_read_pos = (plci->li_plci_b_read_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ?
+        0 : plci->li_plci_b_read_pos + 1;
+    } while (!(d & LI_PLCI_B_LAST_FLAG) && (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos));
+  }
+}
+
+
+static void mixer_indication_xconnect_from (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+  word i, j, ch;
+  struct xconnect_transfer_address_s s,   *p;
+  DIVA_CAPI_ADAPTER   *a;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_xconnect_from %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, (int) length));
+
+  a = plci->adapter;
+  i = 1;
+  for (i = 1; i < length; i += 16)
+  {
+    s.card_address.low = msg[i] | (msg[i+1] << 8) | (((dword)(msg[i+2])) << 16) | (((dword)(msg[i+3])) << 24);
+    s.card_address.high = msg[i+4] | (msg[i+5] << 8) | (((dword)(msg[i+6])) << 16) | (((dword)(msg[i+7])) << 24);
+    s.offset = msg[i+8] | (msg[i+9] << 8) | (((dword)(msg[i+10])) << 16) | (((dword)(msg[i+11])) << 24);
+    ch = msg[i+12] | (msg[i+13] << 8);
+    j = ch & XCONNECT_CHANNEL_NUMBER_MASK;
+    if (!a->li_pri && (plci->li_bchannel_id == 2))
+      j = 1 - j;
+    j += a->li_base;
+    if (ch & XCONNECT_CHANNEL_PORT_PC)
+      p = &(li_config_table[j].send_pc);
+    else
+      p = &(li_config_table[j].send_b);
+    p->card_address.low = s.card_address.low;
+    p->card_address.high = s.card_address.high;
+    p->offset = s.offset;
+    li_config_table[j].channel |= LI_CHANNEL_ADDRESSES_SET;
+  }
+  if (plci->internal_command_queue[0]
+   && ((plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
+    || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
+    || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)))
+  {
+    (*(plci->internal_command_queue[0]))(Id, plci, 0);
+    if (!plci->internal_command)
+      next_internal_command (Id, plci);
+  }
+  mixer_notify_update (plci, TRUE);
+}
+
+
+static void mixer_indication_xconnect_to (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_xconnect_to %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, (int) length));
+
+}
+
+
+static byte mixer_notify_source_removed (PLCI   *plci, dword plci_b_id)
+{
+  word plci_b_write_pos;
+
+  plci_b_write_pos = plci->li_plci_b_write_pos;
+  if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+    LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 1)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+      (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+      (char   *)(FILE_), __LINE__));
+    return (FALSE);
+  }
+  plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
+  plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+  plci->li_plci_b_write_pos = plci_b_write_pos;
+  return (TRUE);
+}
+
+
+static void mixer_remove (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  PLCI   *notify_plci;
+  dword plci_b_id;
+  word i, j;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_remove",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  plci_b_id = (plci->Id << 8) | UnMapController (plci->adapter->Id);
+  if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
+  {
+    if ((plci->li_bchannel_id != 0)
+     && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+    {
+      i = a->li_base + (plci->li_bchannel_id - 1);
+      if ((li_config_table[i].curchnl | li_config_table[i].channel) & LI_CHANNEL_INVOLVED)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if ((li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+           || (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT))
+          {
+            notify_plci = li_config_table[j].plci;
+            if ((notify_plci != NULL)
+             && (notify_plci != plci)
+             && (notify_plci->appl != NULL)
+             && !(notify_plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
+             && (notify_plci->State)
+             && notify_plci->NL.Id && !notify_plci->nl_remove_id)
+            {
+              mixer_notify_source_removed (notify_plci, plci_b_id);
+            }
+          }
+        }
+        mixer_clear_config (plci);
+        mixer_calculate_coefs (a);
+        mixer_notify_update (plci, TRUE);
+      }
+      li_config_table[i].plci = NULL;
+      plci->li_bchannel_id = 0;
+    }
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* Echo canceller facilities                                        */
+/*------------------------------------------------------------------*/
+
+
+static void ec_write_parameters (PLCI   *plci)
+{
+  word w;
+    byte parameter_buffer[6];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_write_parameters",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  parameter_buffer[0] = 5;
+  parameter_buffer[1] = DSP_CTRL_SET_LEC_PARAMETERS;
+  WRITE_WORD (&parameter_buffer[2], plci->ec_idi_options);
+  plci->ec_idi_options &= ~LEC_RESET_COEFFICIENTS;
+  w = (plci->ec_tail_length == 0) ? 128 : plci->ec_tail_length;
+  WRITE_WORD (&parameter_buffer[4], w);
+  add_p (plci, FTY, parameter_buffer);
+  sig_req (plci, TEL_CTRL, 0);
+  send_req (plci);
+}
+
+
+static void ec_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
+    LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING;
+  plci->ec_tail_length = 0;
+}
+
+
+static void ec_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+}
+
+
+static word ec_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word ec_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  if (plci->B1_facilities & B1_FACILITY_EC)
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_EC_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->sig_req)
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
+        break;
+      }
+      ec_write_parameters (plci);
+      plci->adjust_b_state = ADJUST_B_RESTORE_EC_2;
+      break;
+    case ADJUST_B_RESTORE_EC_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Restore EC failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+static void ec_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command, Info;
+    byte result[8];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_command %02x %04x %04x %04x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command,
+    plci->ec_cmd, plci->ec_idi_options, plci->ec_tail_length));
+
+  Info = GOOD;
+  if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
+  {
+    result[0] = 2;
+    WRITE_WORD (&result[1], EC_SUCCESS);
+  }
+  else
+  {
+    result[0] = 5;
+    WRITE_WORD (&result[1], plci->ec_cmd);
+    result[3] = 2;
+    WRITE_WORD (&result[4], GOOD);
+  }
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (plci->ec_cmd)
+  {
+  case EC_ENABLE_OPERATION:
+  case EC_FREEZE_COEFFICIENTS:
+  case EC_RESUME_COEFFICIENT_UPDATE:
+  case EC_RESET_COEFFICIENTS:
+    switch (internal_command)
+    {
+    default:
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+        B1_FACILITY_EC), EC_COMMAND_1);
+    case EC_COMMAND_1:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Load EC failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+    case EC_COMMAND_2:
+      if (plci->sig_req)
+      {
+        plci->internal_command = EC_COMMAND_2;
+        return;
+      }
+      plci->internal_command = EC_COMMAND_3;
+      ec_write_parameters (plci);
+      return;
+    case EC_COMMAND_3:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Enable EC failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      break;
+    }
+    break;
+
+  case EC_DISABLE_OPERATION:
+    switch (internal_command)
+    {
+    default:
+    case EC_COMMAND_1:
+      if (plci->B1_facilities & B1_FACILITY_EC)
+      {
+        if (plci->sig_req)
+        {
+          plci->internal_command = EC_COMMAND_1;
+          return;
+        }
+        plci->internal_command = EC_COMMAND_2;
+        ec_write_parameters (plci);
+        return;
+      }
+      Rc = OK;
+    case EC_COMMAND_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Disable EC failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
+        ~B1_FACILITY_EC), EC_COMMAND_3);
+    case EC_COMMAND_3:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Unload EC failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+      break;
+    }
+    break;
+  }
+  sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
+    "wws", Info, (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
+    PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
+}
+
+
+static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg)
+{
+  word Info;
+  word opt;
+    API_PARSE ec_parms[3];
+    byte result[16];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_request",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result[0] = 0;
+  if (!(a->man_profile.private_options & (1L << PRIVATE_ECHO_CANCELLER)))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _FACILITY_NOT_SUPPORTED;
+  }
+  else
+  {
+    if (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
+    {
+      if (api_parse (&msg[1].info[1], msg[1].length, "w", ec_parms))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _WRONG_MESSAGE_FORMAT;
+      }
+      else
+      {
+        if (plci == NULL)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_IDENTIFIER;
+        }
+        else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_STATE;
+        }
+        else
+        {
+          plci->command = 0;
+          plci->ec_cmd = READ_WORD (ec_parms[0].info);
+          plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
+          result[0] = 2;
+          WRITE_WORD (&result[1], EC_SUCCESS);
+          if (msg[1].length >= 4)
+          {
+            opt = READ_WORD (&ec_parms[0].info[2]);
+            plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
+              LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
+            if (!(opt & EC_DISABLE_NON_LINEAR_PROCESSING))
+              plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
+            if (opt & EC_DETECT_DISABLE_TONE)
+              plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
+            if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
+              plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
+            if (msg[1].length >= 6)
+            {
+              plci->ec_tail_length = READ_WORD (&ec_parms[0].info[4]);
+            }
+          }
+          switch (plci->ec_cmd)
+          {
+          case EC_ENABLE_OPERATION:
+            plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_DISABLE_OPERATION:
+            plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
+              LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
+              LEC_RESET_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_FREEZE_COEFFICIENTS:
+            plci->ec_idi_options |= LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_RESUME_COEFFICIENT_UPDATE:
+            plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_RESET_COEFFICIENTS:
+            plci->ec_idi_options |= LEC_RESET_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          default:
+            dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
+              UnMapId (Id), (char   *)(FILE_), __LINE__, plci->ec_cmd));
+            WRITE_WORD (&result[1], EC_UNSUPPORTED_OPERATION);
+          }
+        }
+      }
+    }
+    else
+    {
+      if (api_parse (&msg[1].info[1], msg[1].length, "ws", ec_parms))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _WRONG_MESSAGE_FORMAT;
+      }
+      else
+      {
+        if (READ_WORD (ec_parms[0].info) == EC_GET_SUPPORTED_SERVICES)
+        {
+          result[0] = 11;
+          WRITE_WORD (&result[1], EC_GET_SUPPORTED_SERVICES);
+          result[3] = 8;
+          WRITE_WORD (&result[4], GOOD);
+          WRITE_WORD (&result[6], 0x0007);
+          WRITE_WORD (&result[8], LEC_MAX_SUPPORTED_TAIL_LENGTH);
+          WRITE_WORD (&result[10], 0);
+        }
+        else if (plci == NULL)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_IDENTIFIER;
+        }
+        else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_STATE;
+        }
+        else
+        {
+          plci->command = 0;
+          plci->ec_cmd = READ_WORD (ec_parms[0].info);
+          plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
+          result[0] = 5;
+          WRITE_WORD (&result[1], plci->ec_cmd);
+          result[3] = 2;
+          WRITE_WORD (&result[4], GOOD);
+          plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
+            LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
+          plci->ec_tail_length = 0;
+          if (ec_parms[1].length >= 2)
+          {
+            opt = READ_WORD (&ec_parms[1].info[1]);
+            if (opt & EC_ENABLE_NON_LINEAR_PROCESSING)
+              plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
+            if (opt & EC_DETECT_DISABLE_TONE)
+              plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
+            if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
+              plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
+            if (ec_parms[1].length >= 4)
+            {
+              plci->ec_tail_length = READ_WORD (&ec_parms[1].info[3]);
+            }
+          }
+          switch (plci->ec_cmd)
+          {
+          case EC_ENABLE_OPERATION:
+            plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_DISABLE_OPERATION:
+            plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
+              LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
+              LEC_RESET_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          default:
+            dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
+              UnMapId (Id), (char   *)(FILE_), __LINE__, plci->ec_cmd));
+            WRITE_WORD (&result[4], _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP);
+          }
+        }
+      }
+    }
+  }
+  sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+    "wws", Info, (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
+    PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
+  return (FALSE);
+}
+
+
+static void ec_indication (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+    byte result[8];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_indication",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  if (!(plci->ec_idi_options & LEC_MANUAL_DISABLE))
+  {
+    if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
+    {
+      result[0] = 2;
+      WRITE_WORD (&result[1], 0);
+      switch (msg[1])
+      {
+      case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
+        WRITE_WORD (&result[1], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
+        break;
+      case LEC_DISABLE_TYPE_REVERSED_2100HZ:
+        WRITE_WORD (&result[1], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
+        break;
+      case LEC_DISABLE_RELEASED:
+        WRITE_WORD (&result[1], EC_BYPASS_RELEASED);
+        break;
+      }
+    }
+    else
+    {
+      result[0] = 5;
+      WRITE_WORD (&result[1], EC_BYPASS_INDICATION);
+      result[3] = 2;
+      WRITE_WORD (&result[4], 0);
+      switch (msg[1])
+      {
+      case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
+        WRITE_WORD (&result[4], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
+        break;
+      case LEC_DISABLE_TYPE_REVERSED_2100HZ:
+        WRITE_WORD (&result[4], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
+        break;
+      case LEC_DISABLE_RELEASED:
+        WRITE_WORD (&result[4], EC_BYPASS_RELEASED);
+        break;
+      }
+    }
+    sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
+      PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
+  }
+}
+
+
+
+/*------------------------------------------------------------------*/
+/* Advanced voice                                                   */
+/*------------------------------------------------------------------*/
+
+static void adv_voice_write_coefs (PLCI   *plci, word write_command)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i;
+  byte *p;
+
+  word w, n, j, k;
+  byte ch_map[MIXER_CHANNELS_BRI];
+
+    byte coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE + 2];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_write_coefs %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, write_command));
+
+  a = plci->adapter;
+  p = coef_buffer + 1;
+  *(p++) = DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS;
+  i = 0;
+  while (i + sizeof(word) <= a->adv_voice_coef_length)
+  {
+    WRITE_WORD (p, READ_WORD (a->adv_voice_coef_buffer + i));
+    p += 2;
+    i += 2;
+  }
+  while (i < ADV_VOICE_OLD_COEF_COUNT * sizeof(word))
+  {
+    WRITE_WORD (p, 0x8000);
+    p += 2;
+    i += 2;
+  }
+
+  if (!a->li_pri && (plci->li_bchannel_id == 0))
+  {
+    if ((li_config_table[a->li_base].plci == NULL) && (li_config_table[a->li_base + 1].plci != NULL))
+    {
+      plci->li_bchannel_id = 1;
+      li_config_table[a->li_base].plci = plci;
+      dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
+        (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+        (char   *)(FILE_), __LINE__, plci->li_bchannel_id));
+    }
+    else if ((li_config_table[a->li_base].plci != NULL) && (li_config_table[a->li_base + 1].plci == NULL))
+    {
+      plci->li_bchannel_id = 2;
+      li_config_table[a->li_base + 1].plci = plci;
+      dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
+        (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+        (char   *)(FILE_), __LINE__, plci->li_bchannel_id));
+    }
+  }
+  if (!a->li_pri && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    switch (write_command)
+    {
+    case ADV_VOICE_WRITE_ACTIVATION:
+      j = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+      if (!(plci->B1_facilities & B1_FACILITY_MIXER))
+      {
+        li_config_table[j].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
+        li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
+      }
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        li_config_table[k].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
+        li_config_table[i].flag_table[k] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
+        li_config_table[k].flag_table[j] |= LI_FLAG_CONFERENCE;
+        li_config_table[j].flag_table[k] |= LI_FLAG_CONFERENCE;
+      }
+      mixer_calculate_coefs (a);
+      li_config_table[i].curchnl = li_config_table[i].channel;
+      li_config_table[j].curchnl = li_config_table[j].channel;
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+        li_config_table[k].curchnl = li_config_table[k].channel;
+      break;
+
+    case ADV_VOICE_WRITE_DEACTIVATION:
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[i].flag_table[j] = 0;
+        li_config_table[j].flag_table[i] = 0;
+      }
+      k = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[k].flag_table[j] = 0;
+        li_config_table[j].flag_table[k] = 0;
+      }
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[k].flag_table[j] = 0;
+          li_config_table[j].flag_table[k] = 0;
+        }
+      }
+      mixer_calculate_coefs (a);
+      break;
+    }
+    if (plci->B1_facilities & B1_FACILITY_MIXER)
+    {
+      w = 0;
+      if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length)
+        w = READ_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
+      if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+        w |= MIXER_FEATURE_ENABLE_TX_DATA;
+      if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+        w |= MIXER_FEATURE_ENABLE_RX_DATA;
+      *(p++) = (byte) w;
+      *(p++) = (byte)(w >> 8);
+      for (j = 0; j < sizeof(ch_map); j += 2)
+      {
+        ch_map[j] = (byte)(j + (plci->li_bchannel_id - 1));
+        ch_map[j+1] = (byte)(j + (2 - plci->li_bchannel_id));
+      }
+      for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+      {
+        i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
+        j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
+        if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
+        {
+          *(p++) = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
+          w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+          li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
+        }
+        else
+        {
+          *(p++) = (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n < a->adv_voice_coef_length) ?
+            a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n] : 0x00;
+        }
+      }
+    }
+    else
+    {
+      for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
+        *(p++) = a->adv_voice_coef_buffer[i];
+    }
+  }
+  else
+
+  {
+    for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
+      *(p++) = a->adv_voice_coef_buffer[i];
+  }
+  coef_buffer[0] = (p - coef_buffer) - 1;
+  add_p (plci, FTY, coef_buffer);
+  sig_req (plci, TEL_CTRL, 0);
+  send_req (plci);
+}
+
+
+static void adv_voice_clear_config (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+
+  word i, j;
+
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+  {
+    a->adv_voice_coef_length = 0;
+
+    if (!a->li_pri && (plci->li_bchannel_id != 0)
+     && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+    {
+      i = a->li_base + (plci->li_bchannel_id - 1);
+      li_config_table[i].curchnl = 0;
+      li_config_table[i].channel = 0;
+      li_config_table[i].chflags = 0;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[i].flag_table[j] = 0;
+        li_config_table[j].flag_table[i] = 0;
+        li_config_table[i].coef_table[j] = 0;
+        li_config_table[j].coef_table[i] = 0;
+      }
+      li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
+      i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      li_config_table[i].curchnl = 0;
+      li_config_table[i].channel = 0;
+      li_config_table[i].chflags = 0;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[i].flag_table[j] = 0;
+        li_config_table[j].flag_table[i] = 0;
+        li_config_table[i].coef_table[j] = 0;
+        li_config_table[j].coef_table[i] = 0;
+      }
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+        li_config_table[i].curchnl = 0;
+        li_config_table[i].channel = 0;
+        li_config_table[i].chflags = 0;
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[i].flag_table[j] = 0;
+          li_config_table[j].flag_table[i] = 0;
+          li_config_table[i].coef_table[j] = 0;
+          li_config_table[j].coef_table[i] = 0;
+        }
+      }
+    }
+
+  }
+}
+
+
+static void adv_voice_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+}
+
+
+static word adv_voice_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word adv_voice_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  a = plci->adapter;
+  if ((plci->B1_facilities & B1_FACILITY_VOICE)
+   && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_VOICE_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->sig_req)
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
+        break;
+      }
+      adv_voice_write_coefs (plci, ADV_VOICE_WRITE_UPDATE);
+      plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_2;
+      break;
+    case ADJUST_B_RESTORE_VOICE_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Restore voice config failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+
+
+/*------------------------------------------------------------------*/
+/* B1 resource switching                                            */
+/*------------------------------------------------------------------*/
+
+static byte b1_facilities_table[] =
+{
+  0x00,  /* 0  No bchannel resources      */
+  0x00,  /* 1  Codec (automatic law)      */
+  0x00,  /* 2  Codec (A-law)              */
+  0x00,  /* 3  Codec (y-law)              */
+  0x00,  /* 4  HDLC for X.21              */
+  0x00,  /* 5  HDLC                       */
+  0x00,  /* 6  External Device 0          */
+  0x00,  /* 7  External Device 1          */
+  0x00,  /* 8  HDLC 56k                   */
+  0x00,  /* 9  Transparent                */
+  0x00,  /* 10 Loopback to network        */
+  0x00,  /* 11 Test pattern to net        */
+  0x00,  /* 12 Rate adaptation sync       */
+  0x00,  /* 13 Rate adaptation async      */
+  0x00,  /* 14 R-Interface                */
+  0x00,  /* 15 HDLC 128k leased line      */
+  0x00,  /* 16 FAX                        */
+  0x00,  /* 17 Modem async                */
+  0x00,  /* 18 Modem sync HDLC            */
+  0x00,  /* 19 V.110 async HDLC           */
+  0x12,  /* 20 Adv voice (Trans,mixer)    */
+  0x00,  /* 21 Codec connected to IC      */
+  0x0c,  /* 22 Trans,DTMF                 */
+  0x1e,  /* 23 Trans,DTMF+mixer           */
+  0x1f,  /* 24 Trans,DTMF+mixer+local     */
+  0x13,  /* 25 Trans,mixer+local          */
+  0x12,  /* 26 HDLC,mixer                 */
+  0x12,  /* 27 HDLC 56k,mixer             */
+  0x2c,  /* 28 Trans,LEC+DTMF             */
+  0x3e,  /* 29 Trans,LEC+DTMF+mixer       */
+  0x3f,  /* 30 Trans,LEC+DTMF+mixer+local */
+  0x2c,  /* 31 RTP,LEC+DTMF               */
+  0x3e,  /* 32 RTP,LEC+DTMF+mixer         */
+  0x3f,  /* 33 RTP,LEC+DTMF+mixer+local   */
+  0x00,  /* 34 Signaling task             */
+  0x00,  /* 35 PIAFS                      */
+  0x0c,  /* 36 Trans,DTMF+TONE            */
+  0x1e,  /* 37 Trans,DTMF+TONE+mixer      */
+  0x1f   /* 38 Trans,DTMF+TONE+mixer+local*/
+};
+
+
+static word get_b1_facilities (PLCI   * plci, byte b1_resource)
+{
+  word b1_facilities;
+
+  b1_facilities = b1_facilities_table[b1_resource];
+  if ((b1_resource == 9) || (b1_resource == 20) || (b1_resource == 25))
+  {
+
+    if (!(((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
+       || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id-1] & (1L << PRIVATE_DTMF_TONE)))))
+
+    {
+      if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND)
+        b1_facilities |= B1_FACILITY_DTMFX;
+      if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)
+        b1_facilities |= B1_FACILITY_DTMFR;
+    }
+  }
+  if ((b1_resource == 17) || (b1_resource == 18))
+  {
+    if (plci->adapter->manufacturer_features & (MANUFACTURER_FEATURE_V18 | MANUFACTURER_FEATURE_VOWN))
+      b1_facilities |= B1_FACILITY_DTMFX | B1_FACILITY_DTMFR;
+  }
+/*
+  dbug (1, dprintf ("[%06lx] %s,%d: get_b1_facilities %d %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char far *)(FILE_), __LINE__, b1_resource, b1_facilites));
+*/
+  return (b1_facilities);
+}
+
+
+static byte add_b1_facilities (PLCI   * plci, byte b1_resource, word b1_facilities)
+{
+  byte b;
+
+  switch (b1_resource)
+  {
+  case 5:
+  case 26:
+    if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+      b = 26;
+    else
+      b = 5;
+    break;
+
+  case 8:
+  case 27:
+    if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+      b = 27;
+    else
+      b = 8;
+    break;
+
+  case 9:
+  case 20:
+  case 22:
+  case 23:
+  case 24:
+  case 25:
+  case 28:
+  case 29:
+  case 30:
+  case 36:
+  case 37:
+  case 38:
+    if (b1_facilities & B1_FACILITY_EC)
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 30;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 29;
+      else
+        b = 28;
+    }
+
+    else if ((b1_facilities & (B1_FACILITY_DTMFX | B1_FACILITY_DTMFR | B1_FACILITY_MIXER))
+      && (((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
+       || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id-1] & (1L << PRIVATE_DTMF_TONE)))))
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 38;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 37;
+      else
+        b = 36;
+    }
+
+    else if (((plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
+      && !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
+     || ((b1_facilities & B1_FACILITY_DTMFR)
+      && ((b1_facilities & B1_FACILITY_MIXER)
+       || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)))
+     || ((b1_facilities & B1_FACILITY_DTMFX)
+      && ((b1_facilities & B1_FACILITY_MIXER)
+       || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND))))
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 24;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 23;
+      else
+        b = 22;
+    }
+    else
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 25;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 20;
+      else
+        b = 9;
+    }
+    break;
+
+  case 31:
+  case 32:
+  case 33:
+    if (b1_facilities & B1_FACILITY_LOCAL)
+      b = 33;
+    else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+      b = 32;
+    else
+      b = 31;
+    break;
+
+  default:
+    b = b1_resource;
+  }
+  dbug (1, dprintf ("[%06lx] %s,%d: add_b1_facilities %d %04x %d %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__,
+    b1_resource, b1_facilities, b, get_b1_facilities (plci, b)));
+  return (b);
+}
+
+
+static void adjust_b1_facilities (PLCI   *plci, byte new_b1_resource, word new_b1_facilities)
+{
+  word removed_facilities;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b1_facilities %d %04x %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, new_b1_resource, new_b1_facilities,
+    new_b1_facilities & get_b1_facilities (plci, new_b1_resource)));
+
+  new_b1_facilities &= get_b1_facilities (plci, new_b1_resource);
+  removed_facilities = plci->B1_facilities & ~new_b1_facilities;
+
+  if (removed_facilities & B1_FACILITY_EC)
+    ec_clear_config (plci);
+
+
+  if (removed_facilities & B1_FACILITY_DTMFR)
+  {
+    dtmf_rec_clear_config (plci);
+    dtmf_parameter_clear_config (plci);
+  }
+  if (removed_facilities & B1_FACILITY_DTMFX)
+    dtmf_send_clear_config (plci);
+
+
+  if (removed_facilities & B1_FACILITY_MIXER)
+    mixer_clear_config (plci);
+
+  if (removed_facilities & B1_FACILITY_VOICE)
+    adv_voice_clear_config (plci);
+  plci->B1_facilities = new_b1_facilities;
+}
+
+
+static void adjust_b_clear (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_clear",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->adjust_b_restore = FALSE;
+}
+
+
+static word adjust_b_process (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  byte b1_resource;
+  NCCI   * ncci_ptr;
+    API_PARSE bp[2];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_process %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  switch (plci->adjust_b_state)
+  {
+  case ADJUST_B_START:
+    if ((plci->adjust_b_parms_msg == NULL)
+     && (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
+     && ((plci->adjust_b_mode & ~(ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 |
+      ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_RESTORE)) == 0))
+    {
+      b1_resource = (plci->adjust_b_mode == ADJUST_B_MODE_NO_RESOURCE) ?
+        0 : add_b1_facilities (plci, plci->B1_resource, plci->adjust_b_facilities);
+      if (b1_resource == plci->B1_resource)
+      {
+        adjust_b1_facilities (plci, b1_resource, plci->adjust_b_facilities);
+        break;
+      }
+      if (plci->adjust_b_facilities & ~get_b1_facilities (plci, b1_resource))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B nonsupported facilities %d %d %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__,
+          plci->B1_resource, b1_resource, plci->adjust_b_facilities));
+        Info = _WRONG_STATE;
+        break;
+      }
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      mixer_prepare_switch (Id, plci);
+
+
+      dtmf_prepare_switch (Id, plci);
+      dtmf_parameter_prepare_switch (Id, plci);
+
+
+      ec_prepare_switch (Id, plci);
+
+      adv_voice_prepare_switch (Id, plci);
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_MIXER_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_MIXER_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = mixer_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_DTMF_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_DTMF_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = dtmf_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_REMOVE_L23_1;
+  case ADJUST_B_REMOVE_L23_1:
+    if ((plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
+     && plci->NL.Id && !plci->nl_remove_id)
+    {
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->adjust_b_ncci != 0)
+      {
+        ncci_ptr = &(plci->adapter->ncci[plci->adjust_b_ncci]);
+        while (ncci_ptr->data_pending)
+        {
+          plci->data_sent_ptr = ncci_ptr->DBuffer[ncci_ptr->data_out].P;
+          data_rc (plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
+        }
+        while (ncci_ptr->data_ack_pending)
+          data_ack (plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
+      }
+      nl_req_ncci (plci, REMOVE,
+        (byte)((plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) ? plci->adjust_b_ncci : 0));
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
+    Rc = OK;
+  case ADJUST_B_REMOVE_L23_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B remove failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
+    {
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_EC_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_EC_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = ec_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_DTMF_PARAMETER_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_DTMF_PARAMETER_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = dtmf_parameter_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_VOICE_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_VOICE_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+      Info = adv_voice_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+    }
+    plci->adjust_b_state = ADJUST_B_SWITCH_L1_1;
+  case ADJUST_B_SWITCH_L1_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
+    {
+      if (plci->sig_req)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+      if (plci->adjust_b_parms_msg != NULL)
+        api_load_msg (plci->adjust_b_parms_msg, bp);
+      else
+        api_load_msg (&plci->B_protocol, bp);
+      Info = add_b1 (plci, bp,
+        (word)((plci->adjust_b_mode & ADJUST_B_MODE_NO_RESOURCE) ? 2 : 0),
+        plci->adjust_b_facilities);
+      if (Info != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B invalid L1 parameters %d %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__,
+          plci->B1_resource, plci->adjust_b_facilities));
+        break;
+      }
+      plci->internal_command = plci->adjust_b_command;
+      sig_req (plci, RESOURCES, 0);
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
+    Rc = OK;
+  case ADJUST_B_SWITCH_L1_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B switch failed %02x %d %04x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__,
+        Rc, plci->B1_resource, plci->adjust_b_facilities));
+      Info = _WRONG_STATE;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_VOICE_1:
+  case ADJUST_B_RESTORE_VOICE_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+      Info = adv_voice_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
+  case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = dtmf_parameter_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_EC_1:
+  case ADJUST_B_RESTORE_EC_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = ec_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_ASSIGN_L23_1;
+  case ADJUST_B_ASSIGN_L23_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
+    {
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+      if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
+        plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
+      if (plci->adjust_b_parms_msg != NULL)
+        api_load_msg (plci->adjust_b_parms_msg, bp);
+      else
+        api_load_msg (&plci->B_protocol, bp);
+      Info = add_b23 (plci, bp);
+      if (Info != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B invalid L23 parameters %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Info));
+        break;
+      }
+      plci->internal_command = plci->adjust_b_command;
+      nl_req_ncci (plci, ASSIGN, 0);
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
+    Rc = ASSIGN_OK;
+  case ADJUST_B_ASSIGN_L23_2:
+    if ((Rc != OK) && (Rc != OK_FC) && (Rc != ASSIGN_OK))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B assign failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
+    {
+      if (Rc != ASSIGN_OK)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_USER_CONNECT)
+    {
+      plci->adjust_b_restore = TRUE;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_CONNECT_1;
+  case ADJUST_B_CONNECT_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
+    {
+      plci->internal_command = plci->adjust_b_command;
+      if (plci_nl_busy (plci))
+        break;
+      nl_req_ncci (plci, N_CONNECT, 0);
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_CONNECT_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+    Rc = OK;
+  case ADJUST_B_CONNECT_2:
+  case ADJUST_B_CONNECT_3:
+  case ADJUST_B_CONNECT_4:
+    if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B connect failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (Rc == OK)
+    {
+      if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
+      {
+        get_ncci (plci, (byte)(Id >> 16), plci->adjust_b_ncci);
+        Id = (Id & 0xffff) | (((dword)(plci->adjust_b_ncci)) << 16);
+      }
+      if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
+        plci->adjust_b_state = ADJUST_B_CONNECT_3;
+      else if (plci->adjust_b_state == ADJUST_B_CONNECT_4)
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+    }
+    else if (Rc == 0)
+    {
+      if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
+        plci->adjust_b_state = ADJUST_B_CONNECT_4;
+      else if (plci->adjust_b_state == ADJUST_B_CONNECT_3)
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+    }
+    if (plci->adjust_b_state != ADJUST_B_RESTORE_DTMF_1)
+    {
+      plci->internal_command = plci->adjust_b_command;
+      break;
+    }
+    Rc = OK;
+  case ADJUST_B_RESTORE_DTMF_1:
+  case ADJUST_B_RESTORE_DTMF_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = dtmf_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_MIXER_1:
+  case ADJUST_B_RESTORE_MIXER_2:
+  case ADJUST_B_RESTORE_MIXER_3:
+  case ADJUST_B_RESTORE_MIXER_4:
+  case ADJUST_B_RESTORE_MIXER_5:
+  case ADJUST_B_RESTORE_MIXER_6:
+  case ADJUST_B_RESTORE_MIXER_7:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = mixer_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_END;
+  case ADJUST_B_END:
+    break;
+  }
+  return (Info);
+}
+
+
+static void adjust_b1_resource (dword Id, PLCI   *plci, API_SAVE   *bp_msg, word b1_facilities, word internal_command)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b1_resource %d %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__,
+    plci->B1_resource, b1_facilities));
+
+  plci->adjust_b_parms_msg = bp_msg;
+  plci->adjust_b_facilities = b1_facilities;
+  plci->adjust_b_command = internal_command;
+  plci->adjust_b_ncci = (word)(Id >> 16);
+  if ((bp_msg == NULL) && (plci->B1_resource == 0))
+    plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_SWITCH_L1;
+  else
+    plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 | ADJUST_B_MODE_RESTORE;
+  plci->adjust_b_state = ADJUST_B_START;
+  dbug (1, dprintf ("[%06lx] %s,%d: Adjust B1 resource %d %04x...",
+    UnMapId (Id), (char   *)(FILE_), __LINE__,
+    plci->B1_resource, b1_facilities));
+}
+
+
+static void adjust_b_restore (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_restore %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    if (plci->req_in != 0)
+    {
+      plci->internal_command = ADJUST_B_RESTORE_1;
+      break;
+    }
+    Rc = OK;
+  case ADJUST_B_RESTORE_1:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B enqueued failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+    }
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = ADJUST_B_RESTORE_2;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_RESTORE;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: Adjust B restore...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case ADJUST_B_RESTORE_2:
+    if (adjust_b_process (Id, plci, Rc) != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B restore failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+    }
+    if (plci->internal_command)
+      break;
+    break;
+  }
+}
+
+
+static void reset_b3_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: reset_b3_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = RESET_B3_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_CONNECT;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: Reset B3...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case RESET_B3_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Reset failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+    break;
+  }
+/*  sendf (plci->appl, _RESET_B3_R | CONFIRM, Id, plci->number, "w", Info);*/
+  sendf(plci->appl,_RESET_B3_I,Id,0,"s","");
+}
+
+
+static void select_b_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+  byte esc_chi[3];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: select_b_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = &plci->saved_msg;
+    if ((plci->tel == ADV_VOICE) && (plci == plci->adapter->AdvSignalPLCI))
+      plci->adjust_b_facilities = plci->B1_facilities | B1_FACILITY_VOICE;
+    else
+      plci->adjust_b_facilities = plci->B1_facilities & ~B1_FACILITY_VOICE;
+    plci->adjust_b_command = SELECT_B_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    if (plci->saved_msg.parms[0].length == 0)
+    {
+      plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
+        ADJUST_B_MODE_NO_RESOURCE;
+    }
+    else
+    {
+      plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
+        ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
+    }
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: Select B protocol...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case SELECT_B_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Select B protocol failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+    if (plci->tel == ADV_VOICE)
+    {
+      esc_chi[0] = 0x02;
+      esc_chi[1] = 0x18;
+      esc_chi[2] = plci->b_channel;
+      SetVoiceChannel (plci->adapter->AdvCodecPLCI, esc_chi, plci->adapter);
+    }
+    break;
+  }
+  sendf (plci->appl, _SELECT_B_REQ | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void fax_connect_ack_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_ack_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case FAX_CONNECT_ACK_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_CONNECT_ACK_COMMAND_1;
+      return;
+    }
+    plci->internal_command = FAX_CONNECT_ACK_COMMAND_2;
+    plci->NData[0].P = plci->fax_connect_info_buffer;
+    plci->NData[0].PLength = plci->fax_connect_info_length;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_CONNECT_ACK;
+    plci->adapter->request (&plci->NL);
+    return;
+  case FAX_CONNECT_ACK_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX issue CONNECT ACK failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      break;
+    }
+  }
+  if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+   && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+  {
+    if (plci->B3_prot == 4)
+      sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+    else
+      sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+    plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+  }
+}
+
+
+static void fax_edata_ack_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_edata_ack_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case FAX_EDATA_ACK_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_EDATA_ACK_COMMAND_1;
+      return;
+    }
+    plci->internal_command = FAX_EDATA_ACK_COMMAND_2;
+    plci->NData[0].P = plci->fax_connect_info_buffer;
+    plci->NData[0].PLength = plci->fax_edata_ack_length;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_EDATA;
+    plci->adapter->request (&plci->NL);
+    return;
+  case FAX_EDATA_ACK_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX issue EDATA ACK failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      break;
+    }
+  }
+}
+
+
+static void fax_connect_info_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_info_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case FAX_CONNECT_INFO_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_CONNECT_INFO_COMMAND_1;
+      return;
+    }
+    plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
+    plci->NData[0].P = plci->fax_connect_info_buffer;
+    plci->NData[0].PLength = plci->fax_connect_info_length;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_EDATA;
+    plci->adapter->request (&plci->NL);
+    return;
+  case FAX_CONNECT_INFO_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX setting connect info failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
+      return;
+    }
+    plci->command = _CONNECT_B3_R;
+    nl_req_ncci (plci, N_CONNECT, 0);
+    send_req (plci);
+    return;
+  }
+  sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void fax_adjust_b23_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_adjust_b23_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = FAX_ADJUST_B23_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: FAX adjust B23...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case FAX_ADJUST_B23_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX adjust failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+  case FAX_ADJUST_B23_COMMAND_2:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_ADJUST_B23_COMMAND_2;
+      return;
+    }
+    plci->command = _CONNECT_B3_R;
+    nl_req_ncci (plci, N_CONNECT, 0);
+    send_req (plci);
+    return;
+  }
+  sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void fax_disconnect_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_disconnect_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->internal_command = FAX_DISCONNECT_COMMAND_1;
+    return;
+  case FAX_DISCONNECT_COMMAND_1:
+  case FAX_DISCONNECT_COMMAND_2:
+  case FAX_DISCONNECT_COMMAND_3:
+    if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX disconnect EDATA failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      break;
+    }
+    if (Rc == OK)
+    {
+      if ((internal_command == FAX_DISCONNECT_COMMAND_1)
+       || (internal_command == FAX_DISCONNECT_COMMAND_2))
+      {
+        plci->internal_command = FAX_DISCONNECT_COMMAND_2;
+      }
+    }
+    else if (Rc == 0)
+    {
+      if (internal_command == FAX_DISCONNECT_COMMAND_1)
+        plci->internal_command = FAX_DISCONNECT_COMMAND_3;
+    }
+    return;
+  }
+}
+
+
+
+static void rtp_connect_b3_req_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_req_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case RTP_CONNECT_B3_REQ_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_1;
+      return;
+    }
+    plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
+    nl_req_ncci (plci, N_CONNECT, 0);
+    send_req (plci);
+    return;
+  case RTP_CONNECT_B3_REQ_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect info failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
+      return;
+    }
+    plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_3;
+    plci->NData[0].PLength = plci->internal_req_buffer[0];
+    plci->NData[0].P = plci->internal_req_buffer + 1;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+    plci->adapter->request (&plci->NL);
+    break;
+  case RTP_CONNECT_B3_REQ_COMMAND_3:
+    return;
+  }
+  sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void rtp_connect_b3_res_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case RTP_CONNECT_B3_RES_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_1;
+      return;
+    }
+    plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
+    nl_req_ncci (plci, N_CONNECT_ACK, (byte)(Id >> 16));
+    send_req (plci);
+    return;
+  case RTP_CONNECT_B3_RES_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect resp info failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
+      return;
+    }
+    sendf (plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
+    plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_3;
+    plci->NData[0].PLength = plci->internal_req_buffer[0];
+    plci->NData[0].P = plci->internal_req_buffer + 1;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+    plci->adapter->request (&plci->NL);
+    return;
+  case RTP_CONNECT_B3_RES_COMMAND_3:
+    return;
+  }
+}
+
+
+
+static void hold_save_command (dword Id, PLCI   *plci, byte Rc)
+{
+    byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: hold_save_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    if (!plci->NL.Id)
+      break;
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = HOLD_SAVE_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: HOLD save...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case HOLD_SAVE_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: HOLD save failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+  }
+  sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
+}
+
+
+static void retrieve_restore_command (dword Id, PLCI   *plci, byte Rc)
+{
+    byte SS_Ind[] = "\x05\x03\x00\x02\x00\x00"; /* Retrieve_Ind struct*/
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: retrieve_restore_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = RETRIEVE_RESTORE_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: RETRIEVE restore...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case RETRIEVE_RESTORE_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: RETRIEVE restore failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+  }
+  sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
+}
+
+
+static void init_b1_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: init_b1_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->B1_resource = 0;
+  plci->B1_facilities = 0;
+
+  plci->li_bchannel_id = 0;
+  mixer_clear_config (plci);
+
+
+  ec_clear_config (plci);
+
+
+  dtmf_rec_clear_config (plci);
+  dtmf_send_clear_config (plci);
+  dtmf_parameter_clear_config (plci);
+
+  adv_voice_clear_config (plci);
+  adjust_b_clear (plci);
+}
+
+
+static void clear_b1_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: clear_b1_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  adv_voice_clear_config (plci);
+  adjust_b_clear (plci);
+
+  ec_clear_config (plci);
+
+
+  dtmf_rec_clear_config (plci);
+  dtmf_send_clear_config (plci);
+  dtmf_parameter_clear_config (plci);
+
+
+  if ((plci->li_bchannel_id != 0)
+   && (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    mixer_clear_config (plci);
+    li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = NULL;
+    plci->li_bchannel_id = 0;
+  }
+
+  plci->B1_resource = 0;
+  plci->B1_facilities = 0;
+}
+
+
+/* -----------------------------------------------------------------
+                XON protocol local helpers
+   ----------------------------------------------------------------- */
+static void channel_flow_control_remove (PLCI   * plci) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  word i;
+  for(i=1;i<MAX_NL_CHANNEL+1;i++) {
+    if (a->ch_flow_plci[i] == plci->Id) {
+      a->ch_flow_plci[i] = 0;
+      a->ch_flow_control[i] = 0;
+    }
+  }
+}
+
+static void channel_x_on (PLCI   * plci, byte ch) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  if (a->ch_flow_control[ch] & N_XON_SENT) {
+    a->ch_flow_control[ch] &= ~N_XON_SENT;
+  }
+}
+
+static void channel_x_off (PLCI   * plci, byte ch, byte flag) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  if ((a->ch_flow_control[ch] & N_RX_FLOW_CONTROL_MASK) == 0) {
+    a->ch_flow_control[ch] |= (N_CH_XOFF | flag);
+    a->ch_flow_plci[ch] = plci->Id;
+    a->ch_flow_control_pending++;
+  }
+}
+
+static void channel_request_xon (PLCI   * plci, byte ch) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+
+  if (a->ch_flow_control[ch] & N_CH_XOFF) {
+    a->ch_flow_control[ch] |= N_XON_REQ;
+    a->ch_flow_control[ch] &= ~N_CH_XOFF;
+    a->ch_flow_control[ch] &= ~N_XON_CONNECT_IND;
+  }
+}
+
+static void channel_xmit_extended_xon (PLCI   * plci) {
+  DIVA_CAPI_ADAPTER   * a;
+  int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
+  int i, one_requested = 0;
+
+  if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) {
+    return;
+  }
+
+  for (i = 0; i < max_ch; i++) {
+    if ((a->ch_flow_control[i] & N_CH_XOFF) &&
+        (a->ch_flow_control[i] & N_XON_CONNECT_IND) &&
+        (plci->Id == a->ch_flow_plci[i])) {
+      channel_request_xon (plci, (byte)i);
+      one_requested = 1;
+    }
+  }
+
+  if (one_requested) {
+    channel_xmit_xon (plci);
+  }
+}
+
+/*
+  Try to xmit next X_ON
+  */
+static int find_channel_with_pending_x_on (DIVA_CAPI_ADAPTER   * a, PLCI   * plci) {
+  int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
+  int i;
+
+  if (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)) {
+    return (0);
+  }
+
+  if (a->last_flow_control_ch >= max_ch) {
+    a->last_flow_control_ch = 1;
+  }
+  for (i=a->last_flow_control_ch; i < max_ch; i++) {
+    if ((a->ch_flow_control[i] & N_XON_REQ) &&
+        (plci->Id == a->ch_flow_plci[i])) {
+      a->last_flow_control_ch = i+1;
+      return (i);
+    }
+  }
+
+  for (i = 1; i < a->last_flow_control_ch; i++) {
+    if ((a->ch_flow_control[i] & N_XON_REQ) &&
+        (plci->Id == a->ch_flow_plci[i])) {
+      a->last_flow_control_ch = i+1;
+      return (i);
+    }
+  }
+
+  return (0);
+}
+
+static void channel_xmit_xon (PLCI   * plci) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  byte ch;
+
+  if (plci->nl_req || !plci->NL.Id || plci->nl_remove_id) {
+    return;
+  }
+  if ((ch = (byte)find_channel_with_pending_x_on (a, plci)) == 0) {
+    return;
+  }
+  a->ch_flow_control[ch] &= ~N_XON_REQ;
+  a->ch_flow_control[ch] |= N_XON_SENT;
+
+  plci->NL.Req = plci->nl_req = (byte)N_XON;
+  plci->NL.ReqCh         = ch;
+  plci->NL.X             = plci->NData;
+  plci->NL.XNum          = 1;
+  plci->NData[0].P       = &plci->RBuffer[0];
+  plci->NData[0].PLength = 0;
+
+  plci->adapter->request(&plci->NL);
+}
+
+static int channel_can_xon (PLCI   * plci, byte ch) {
+  APPL   * APPLptr;
+  DIVA_CAPI_ADAPTER   * a;
+  word NCCIcode;
+  dword count;
+  word Num;
+  word i;
+
+  APPLptr = plci->appl;
+  a = plci->adapter;
+
+  if (!APPLptr)
+    return (0);
+
+  NCCIcode = a->ch_ncci[ch] | (((word) a->Id) << 8);
+
+                /* count all buffers within the Application pool    */
+                /* belonging to the same NCCI. XON if a first is    */
+                /* used.                                            */
+  count = 0;
+  Num = 0xffff;
+  for(i=0; i<APPLptr->MaxBuffer; i++) {
+    if(NCCIcode==APPLptr->DataNCCI[i]) count++;
+    if(!APPLptr->DataNCCI[i] && Num==0xffff) Num = i;
+  }
+  if ((count > 2) || (Num == 0xffff)) {
+    return (0);
+  }
+  return (1);
+}
+
+
+/*------------------------------------------------------------------*/
+
+/* to be completed */
+void disable_adapter(byte adapter_number)
+{
+  word j, ncci;
+  DIVA_CAPI_ADAPTER   *a;
+  PLCI   *plci;
+  dword Id;
+
+  if ((adapter_number == 0) || (adapter_number > max_adapter) || !adapter[adapter_number-1].request)
+  {
+    dbug(1,dprintf("disable adapter: number %d invalid",adapter_number));
+    return;
+  }
+  dbug(1,dprintf("disable adapter number %d",adapter_number));
+    /* Capi20 starts with Nr. 1, internal field starts with 0 */
+  a = &adapter[adapter_number-1];
+  a->adapter_disabled = TRUE;
+  for(j=0;j<a->max_plci;j++)
+  {
+    if(a->plci[j].Id) /* disconnect logical links */
+    {
+      plci = &a->plci[j];
+      if(plci->channels)
+      {
+        for(ncci=1;ncci<MAX_NCCI+1 && plci->channels;ncci++)
+        {
+          if(a->ncci_plci[ncci]==plci->Id)
+          {
+            Id = (((dword)ncci)<<16)|((word)plci->Id<<8)|a->Id;
+            sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"ws",0,"");
+            plci->channels--;
+          }
+        }
+      }
+
+      if(plci->State!=LISTENING) /* disconnect physical links */
+      {
+        Id = ((word)plci->Id<<8)|a->Id;
+        sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR);
+        plci_remove(plci);
+        plci->Sig.Id = 0;
+        plci->NL.Id = 0;
+        plci_remove(plci);
+      }
+    }
+  }
+}
+
+void enable_adapter(byte adapter_number)
+{
+  DIVA_CAPI_ADAPTER   *a;
+
+  if ((adapter_number == 0) || (adapter_number > max_adapter) || !adapter[adapter_number-1].request)
+  {
+    dbug(1,dprintf("enable adapter: number %d invalid",adapter_number));
+    return;
+  }
+  dbug(1,dprintf("enable adapter number %d",adapter_number));
+    /* Capi20 starts with Nr. 1, internal field starts with 0 */
+  a = &adapter[adapter_number-1];
+  a->adapter_disabled = FALSE;
+  listen_check(a);
+}
+
+
+static word CPN_filter_ok(byte   *cpn,DIVA_CAPI_ADAPTER   * a,word offset)
+{
+  return 1;
+}
+
+
+
+/**********************************************************************************/
+/* function groups the listening applications according to the CIP mask and the   */
+/* Info_Mask. Each group gets just one Connect_Ind. Some application manufacturer */
+/* are not multi-instance capable, so they start e.g. 30 applications what causes */
+/* big problems on application level (one call, 30 Connect_Ind, ect). The         */
+/* function must be enabled by setting "a->group_optimization_enabled" from the   */
+/* OS specific part (per adapter).                                                */
+/**********************************************************************************/
+void group_optimization(DIVA_CAPI_ADAPTER   * a, PLCI   * plci)
+{
+  word i,j,k,busy,group_found;
+  dword info_mask_group[MAX_CIP_TYPES];
+  dword cip_mask_group[MAX_CIP_TYPES];
+  word appl_number_group_type[MAX_APPL];
+  PLCI   *auxplci;
+
+  set_group_ind_mask (plci); /* all APPLs within this inc. call are allowed to dial in */
+
+  if(!a->group_optimization_enabled)
+  {
+    dbug(1,dprintf("No group optimization"));
+    return;
+  }
+
+  dbug(1,dprintf("Group optimization = 0x%x...", a->group_optimization_enabled));
+
+  for(i=0;i<MAX_CIP_TYPES;i++)
+  {
+    info_mask_group[i] = 0;
+    cip_mask_group [i] = 0;;
+  }
+  for(i=0;i<MAX_APPL;i++)
+  {
+    appl_number_group_type[i] = 0;
+  }
+  for(i=0; i<max_appl; i++) /* check if any multi instance capable application is present */
+  {  /* group_optimization set to 1 means not to optimize multi-instance capable applications (default) */
+    if(application[i].Id && (application[i].MaxNCCI) > 1 && (a->CIP_Mask[i])  && (a->group_optimization_enabled ==1) )
+    {
+      dbug(1,dprintf("Multi-Instance capable, no optimization required"));
+      return; /* allow good application unfiltered access */
+    }
+  }
+  for(i=0; i<max_appl; i++) /* Build CIP Groups */
+  {
+    if(application[i].Id && a->CIP_Mask[i] )
+    {
+      for(k=0,busy=FALSE; k<a->max_plci; k++)
+      {
+        if(a->plci[k].Id) 
+        {
+          auxplci = &a->plci[k];
+          if(auxplci->appl == &application[i]) /* application has a busy PLCI */
+          {
+            busy = TRUE;
+            dbug(1,dprintf("Appl 0x%x is busy",i+1));
+          }
+          else if(test_c_ind_mask_bit (auxplci, i)) /* application has an incoming call pending */
+          {
+            busy = TRUE;
+            dbug(1,dprintf("Appl 0x%x has inc. call pending",i+1));
+          }
+        }
+      }
+
+      for(j=0,group_found=0; j<=(MAX_CIP_TYPES) && !busy &&!group_found; j++)     /* build groups with free applications only */
+      {
+        if(j==MAX_CIP_TYPES)       /* all groups are in use but group still not found */
+        {                           /* the MAX_CIP_TYPES group enables all calls because of field overflow */
+          appl_number_group_type[i] = MAX_CIP_TYPES;
+          group_found=TRUE;
+          dbug(1,dprintf("Field overflow appl 0x%x",i+1));
+        }
+        else if( (info_mask_group[j]==a->CIP_Mask[i]) && (cip_mask_group[j]==a->Info_Mask[i]) )  
+        {                                      /* is group already present ?                  */
+          appl_number_group_type[i] = j|0x80;  /* store the group number for each application */
+          group_found=TRUE;
+          dbug(1,dprintf("Group 0x%x found with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
+        }
+        else if(!info_mask_group[j])
+        {                                      /* establish a new group                       */
+          appl_number_group_type[i] = j|0x80;  /* store the group number for each application */
+          info_mask_group[j] = a->CIP_Mask[i]; /* store the new CIP mask for the new group    */
+          cip_mask_group[j] = a->Info_Mask[i]; /* store the new Info_Mask for this new group  */
+          group_found=TRUE;
+          dbug(1,dprintf("New Group 0x%x established with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
+        }
+      }
+    }
+  }
+        
+  for(i=0; i<max_appl; i++) /* Build group_optimization_mask_table */
+  {
+    if(appl_number_group_type[i]) /* application is free, has listens and is member of a group */
+    {
+      if(appl_number_group_type[i] == MAX_CIP_TYPES)
+      {
+        dbug(1,dprintf("OverflowGroup 0x%x, valid appl = 0x%x, call enabled",appl_number_group_type[i],i+1));
+      }
+      else
+      {
+        dbug(1,dprintf("Group 0x%x, valid appl = 0x%x",appl_number_group_type[i],i+1));
+        for(j=i+1; j<max_appl; j++)   /* search other group members and mark them as busy        */
+        {
+          if(appl_number_group_type[i] == appl_number_group_type[j]) 
+          {
+            dbug(1,dprintf("Appl 0x%x is member of group 0x%x, no call",j+1,appl_number_group_type[j]));
+            clear_group_ind_mask_bit (plci, j);           /* disable call on other group members */
+            appl_number_group_type[j] = 0;       /* remove disabled group member from group list */
+          }
+        }
+      }
+    }
+    else                                                 /* application should not get a call */
+    {
+      clear_group_ind_mask_bit (plci, i);
+    }
+  }
+
+}
+
+
+
+/* OS notifies the driver about a application Capi_Register */
+word CapiRegister(word id)
+{
+  word i,j,appls_found;
+
+  PLCI   *plci;
+  DIVA_CAPI_ADAPTER   *a;
+
+  for(i=0,appls_found=0; i<max_appl; i++)
+  {
+    if( application[i].Id && (application[i].Id!=id) )
+    {
+      appls_found++;                       /* an application has been found */
+    }
+  }
+
+  if(appls_found) return TRUE;
+  for(i=0; i<max_adapter; i++)                   /* scan all adapters...    */
+  {
+    a = &adapter[i];
+    if(a->request)
+    {
+      if(a->flag_dynamic_l1_down)  /* remove adapter from L1 tristate (Huntgroup) */
+      {
+        if(!appls_found)           /* first application does a capi register   */
+        {
+          if((j=get_plci(a)))                    /* activate L1 of all adapters */
+          {
+            plci = &a->plci[j-1];
+            plci->command = 0;
+            add_p(plci,OAD,"\x01\xfd");
+            add_p(plci,CAI,"\x01\x80");
+            add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            add_p(plci,SHIFT|6,0);
+            add_p(plci,SIN,"\x02\x00\x00");
+            plci->internal_command = START_L1_SIG_ASSIGN_PEND;
+            sig_req(plci,ASSIGN,DSIG_ID);
+            add_p(plci,FTY,"\x02\xff\x07"); /* l1 start */
+            sig_req(plci,SIG_CTRL,0);
+            send_req(plci);
+          }
+        }
+      }
+    }
+  }
+  return FALSE;
+}
+
+/*------------------------------------------------------------------*/
+
+/* Functions for virtual Switching e.g. Transfer by join, Conference */
+
+void VSwitchReqInd(PLCI   *plci, dword Id, byte   **parms)
+{
+ word i;
+ /* Format of vswitch_t:
+ 0 byte length
+ 1 byte VSWITCHIE
+ 2 byte VSWITCH_REQ/VSWITCH_IND
+ 3 byte reserved
+ 4 word VSwitchcommand
+ 6 word returnerror
+ 8... Params
+ */
+ if(!plci ||
+  !plci->appl ||
+  !plci->State ||
+  plci->Sig.Ind==NCR_FACILITY
+  )
+  return;
+ 
+ for(i=0;i<MAX_MULTI_IE;i++)
+ {
+        if(!parms[i][0]) continue;
+  if(parms[i][0]<7)
+  {
+   parms[i][0]=0; /* kill it */
+   continue;
+  }
+  dbug(1,dprintf("VSwitchReqInd(%d)",parms[i][4]));
+  switch(parms[i][4])
+  {
+  case VSJOIN:
+   if(!plci->relatedPTYPLCI ||
+    (plci->ptyState!=S_ECT && plci->relatedPTYPLCI->ptyState!=S_ECT))
+   { /* Error */
+    break;
+   }
+   /* remember all necessary informations */
+   if(parms[i][0]!=11 || parms[i][8]!=3) /* Length Test */
+   {
+    break;
+   }
+   if(parms[i][2]==VSWITCH_IND && parms[i][9]==1)
+   {   /* first indication after ECT-Request on Consultation Call */
+    plci->vswitchstate=parms[i][9];
+    parms[i][9]=2; /* State */
+    /* now ask first Call to join */
+   }
+   else if(parms[i][2]==VSWITCH_REQ && parms[i][9]==3)
+   { /* Answer of VSWITCH_REQ from first Call */
+    plci->vswitchstate=parms[i][9];
+    /* tell consultation call to join
+    and the protocol capabilities of the first call */
+   }
+   else
+   { /* Error */
+    break;
+   }    
+   plci->vsprot=parms[i][10]; /* protocol */
+   plci->vsprotdialect=parms[i][11]; /* protocoldialect */
+   /* send join request to related PLCI */
+   parms[i][1]=VSWITCHIE;
+   parms[i][2]=VSWITCH_REQ;
+   
+   plci->relatedPTYPLCI->command = 0;
+   plci->relatedPTYPLCI->internal_command = VSWITCH_REQ_PEND;
+   add_p(plci->relatedPTYPLCI,ESC,&parms[i][0]);
+   sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
+   send_req(plci->relatedPTYPLCI);
+   break;
+  case VSTRANSPORT:
+  default:
+   if(plci->relatedPTYPLCI &&
+    plci->vswitchstate==3 &&
+    plci->relatedPTYPLCI->vswitchstate==3)
+   {
+    add_p(plci->relatedPTYPLCI,ESC,&parms[i][0]);
+    sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
+    send_req(plci->relatedPTYPLCI);
+   }
+   break;
+  }  
+  parms[i][0]=0; /* kill it */
+ }
+}
+
+
+/*------------------------------------------------------------------*/
+
+static int diva_get_dma_descriptor (PLCI   *plci, dword   *dma_magic) {
+  ENTITY e;
+  IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
+
+  if (!(diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_RX_DMA)) {
+    return (-1);
+  }
+
+  pReq->xdi_dma_descriptor_operation.Req = 0;
+  pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
+
+  pReq->xdi_dma_descriptor_operation.info.operation =     IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_number  = -1;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_address = 0;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
+
+  e.user[0] = plci->adapter->Id - 1;
+  plci->adapter->request((ENTITY*)pReq);
+
+  if (!pReq->xdi_dma_descriptor_operation.info.operation &&
+      (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
+      pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
+    *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
+    dbug(3,dprintf("dma_alloc, a:%d (%d-%08x)",
+         plci->adapter->Id,
+         pReq->xdi_dma_descriptor_operation.info.descriptor_number,
+         *dma_magic));
+    return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
+  } else {
+    dbug(1,dprintf("dma_alloc failed"));
+    return (-1);
+  }
+}
+
+static void diva_free_dma_descriptor (PLCI   *plci, int nr) {
+  ENTITY e;
+  IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
+
+  if (nr < 0) {
+    return;
+  }
+
+  pReq->xdi_dma_descriptor_operation.Req = 0;
+  pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
+
+  pReq->xdi_dma_descriptor_operation.info.operation =                                                IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_number  = nr;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_address = 0;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
+
+  e.user[0] = plci->adapter->Id - 1;
+  plci->adapter->request((ENTITY*)pReq);
+
+  if (!pReq->xdi_dma_descriptor_operation.info.operation) {
+    dbug(1,dprintf("dma_free(%d)", nr));
+  } else {
+    dbug(1,dprintf("dma_free failed (%d)", nr));
+  }
+}
+
+/*------------------------------------------------------------------*/
diff -Nru a/drivers/isdn/hardware/eicon/mi_pc.h b/drivers/isdn/hardware/eicon/mi_pc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/mi_pc.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,204 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+/*----------------------------------------------------------------------------
+// MAESTRA ISA PnP */
+#define BRI_MEMORY_BASE                 0x1f700000
+#define BRI_MEMORY_SIZE                 0x00100000  /* 1MB on the BRI                         */
+#define BRI_SHARED_RAM_SIZE             0x00010000  /* 64k shared RAM                         */
+#define BRI_RAY_TAYLOR_DSP_CODE_SIZE    0x00020000  /* max 128k DSP-Code (Ray Taylor's code)  */
+#define BRI_ORG_MAX_DSP_CODE_SIZE       0x00050000  /* max 320k DSP-Code (Telindus)           */
+#define BRI_V90D_MAX_DSP_CODE_SIZE      0x00060000  /* max 384k DSP-Code if V.90D included    */
+#define BRI_CACHED_ADDR(x)              (((x) & 0x1fffffffL) | 0x80000000L)
+#define BRI_UNCACHED_ADDR(x)            (((x) & 0x1fffffffL) | 0xa0000000L)
+#define ADDR  4
+#define ADDRH 6
+#define DATA  0
+#define RESET 7
+#define DEFAULT_ADDRESS 0x240
+#define DEFAULT_IRQ     3
+#define M_PCI_ADDR   0x04  /* MAESTRA BRI PCI */
+#define M_PCI_ADDRH  0x0c  /* MAESTRA BRI PCI */
+#define M_PCI_DATA   0x00  /* MAESTRA BRI PCI */
+#define M_PCI_RESET  0x10  /* MAESTRA BRI PCI */
+/*----------------------------------------------------------------------------
+// MAESTRA PRI PCI */
+#define MP_IRQ_RESET                    0xc18       /* offset of isr in the CONFIG memory bar */
+#define MP_IRQ_RESET_VAL                0xfe        /* value to clear an interrupt            */
+#define MP_MEMORY_SIZE                  0x00400000  /* 4MB on standard PRI                    */
+#define MP2_MEMORY_SIZE                 0x00800000  /* 8MB on PRI Rev. 2                      */
+#define MP_SHARED_RAM_OFFSET            0x00001000  /* offset of shared RAM base in the DRAM memory bar */
+#define MP_SHARED_RAM_SIZE              0x00010000  /* 64k shared RAM                         */
+#define MP_PROTOCOL_OFFSET              (MP_SHARED_RAM_OFFSET + MP_SHARED_RAM_SIZE)
+#define MP_RAY_TAYLOR_DSP_CODE_SIZE     0x00040000  /* max 256k DSP-Code (Ray Taylor's code)  */
+#define MP_ORG_MAX_DSP_CODE_SIZE        0x00060000  /* max 384k DSP-Code (Telindus)           */
+#define MP_V90D_MAX_DSP_CODE_SIZE       0x00070000  /* max 448k DSP-Code if V.90D included)   */
+#define MP_VOIP_MAX_DSP_CODE_SIZE       0x00090000  /* max 576k DSP-Code if voice over IP included */
+#define MP_CACHED_ADDR(x)               (((x) & 0x1fffffffL) | 0x80000000L)
+#define MP_UNCACHED_ADDR(x)             (((x) & 0x1fffffffL) | 0xa0000000L)
+#define MP_RESET         0x20        /* offset of RESET register in the DEVICES memory bar */
+/* RESET register bits */
+#define _MP_S2M_RESET    0x10        /* active lo   */
+#define _MP_LED2         0x08        /* 1 = on      */
+#define _MP_LED1         0x04        /* 1 = on      */
+#define _MP_DSP_RESET    0x02        /* active lo   */
+#define _MP_RISC_RESET   0x81        /* active hi, bit 7 for compatibility with old boards */
+/* CPU exeption context structure in MP shared ram after trap */
+typedef struct mp_xcptcontext_s MP_XCPTC;
+struct mp_xcptcontext_s {
+    dword       sr;
+    dword       cr;
+    dword       epc;
+    dword       vaddr;
+    dword       regs[32];
+    dword       mdlo;
+    dword       mdhi;
+    dword       reseverd;
+    dword       xclass;
+};
+/* boot interface structure for PRI */
+struct mp_load {
+  dword     volatile cmd;
+  dword     volatile addr;
+  dword     volatile len;
+  dword     volatile err;
+  dword     volatile live;
+  dword     volatile res1[0x1b];
+  dword     volatile TrapId;    /* has value 0x999999XX on a CPU trap */
+  dword     volatile res2[0x03];
+  MP_XCPTC  volatile xcpt;      /* contains register dump */
+  dword     volatile rest[((0x1020>>2)-6) - 0x1b - 1 - 0x03 - (sizeof(MP_XCPTC)>>2)];
+  dword     volatile signature;
+  dword data[60000]; /* real interface description */
+};
+/*----------------------------------------------------------------------------*/
+/* SERVER 4BRI (Quattro PCI)                                                  */
+#define MQ_BOARD_REG_OFFSET             0x800000    /* PC relative On board registers offset  */
+#define MQ_BREG_RISC                    0x1200      /* RISC Reset ect                         */
+#define MQ_RISC_COLD_RESET_MASK         0x0001      /* RISC Cold reset                        */
+#define MQ_RISC_WARM_RESET_MASK         0x0002      /* RISC Warm reset                        */
+#define MQ_BREG_IRQ_TEST                0x0608      /* Interrupt request, no CPU interaction  */
+#define MQ_IRQ_REQ_ON                   0x1
+#define MQ_IRQ_REQ_OFF                  0x0
+#define MQ_BOARD_DSP_OFFSET             0xa00000    /* PC relative On board DSP regs offset   */
+#define MQ_DSP1_ADDR_OFFSET             0x0008      /* Addr register offset DSP 1 subboard 1  */
+#define MQ_DSP2_ADDR_OFFSET             0x0208      /* Addr register offset DSP 2 subboard 1  */
+#define MQ_DSP1_DATA_OFFSET             0x0000      /* Data register offset DSP 1 subboard 1  */
+#define MQ_DSP2_DATA_OFFSET             0x0200      /* Data register offset DSP 2 subboard 1  */
+#define MQ_DSP_JUNK_OFFSET              0x0400      /* DSP Data/Addr regs subboard offset     */
+#define MQ_ISAC_DSP_RESET               0x0028      /* ISAC and DSP reset address offset      */
+#define MQ_BOARD_ISAC_DSP_RESET         0x800028    /* ISAC and DSP reset address offset      */
+#define MQ_INSTANCE_COUNT               4           /* 4BRI consists of four instances        */
+#define MQ_MEMORY_SIZE                  0x00400000  /* 4MB on standard 4BRI                   */
+#define MQ_CTRL_SIZE                    0x00002000  /* 8K memory mapped registers             */
+#define MQ_SHARED_RAM_SIZE              0x00010000  /* 64k shared RAM                         */
+#define MQ_ORG_MAX_DSP_CODE_SIZE        0x00050000  /* max 320k DSP-Code (Telindus) */
+#define MQ_V90D_MAX_DSP_CODE_SIZE       0x00060000  /* max 384K DSP-Code if V.90D included */
+#define MQ_VOIP_MAX_DSP_CODE_SIZE       0x00028000  /* max 4*160k = 640K DSP-Code if voice over IP included */
+#define MQ_CACHED_ADDR(x)               (((x) & 0x1fffffffL) | 0x80000000L)
+#define MQ_UNCACHED_ADDR(x)             (((x) & 0x1fffffffL) | 0xa0000000L)
+/*--------------------------------------------------------------------------------------------*/
+/* Additional definitions reflecting the different adress map of the  SERVER 4BRI V2          */
+#define MQ2_BREG_RISC                   0x0200      /* RISC Reset ect                         */
+#define MQ2_BREG_IRQ_TEST               0x0400      /* Interrupt request, no CPU interaction  */
+#define MQ2_BOARD_DSP_OFFSET            0x800000    /* PC relative On board DSP regs offset   */
+#define MQ2_DSP1_DATA_OFFSET            0x1800      /* Data register offset DSP 1 subboard 1  */
+#define MQ2_DSP1_ADDR_OFFSET            0x1808      /* Addr register offset DSP 1 subboard 1  */
+#define MQ2_DSP2_DATA_OFFSET            0x1810      /* Data register offset DSP 2 subboard 1  */
+#define MQ2_DSP2_ADDR_OFFSET            0x1818      /* Addr register offset DSP 2 subboard 1  */
+#define MQ2_DSP_JUNK_OFFSET             0x1000      /* DSP Data/Addr regs subboard offset     */
+#define MQ2_ISAC_DSP_RESET              0x0000      /* ISAC and DSP reset address offset      */
+#define MQ2_BOARD_ISAC_DSP_RESET        0x800000    /* ISAC and DSP reset address offset      */
+#define MQ2_IPACX_CONFIG                0x0300      /* IPACX Configuration TE(0)/NT(1)        */
+#define MQ2_BOARD_IPACX_CONFIG          0x800300    /*     ""                                 */
+#define MQ2_MEMORY_SIZE                 0x01000000  /* 16MB code/data memory                  */
+#define MQ2_CTRL_SIZE                   0x00008000  /* 32K memory mapped registers            */
+/*----------------------------------------------------------------------------*/
+/* SERVER BRI 2M/2F as derived from 4BRI V2                                   */
+#define BRI2_MEMORY_SIZE                0x00800000  /* 8MB code/data memory                   */
+#define BRI2_PROTOCOL_MEMORY_SIZE       (MQ2_MEMORY_SIZE >> 2) /*  same as one 4BRI Rev.2 task */
+#define BRI2_CTRL_SIZE                  0x00008000  /* 32K memory mapped registers            */
+#define M_INSTANCE_COUNT                1           /*  BRI consists of one instance          */
+/*
+ * Some useful constants for proper initialization of the GT6401x
+ */
+#define ID_REG        0x0000      /*Pci reg-contain the Dev&Ven ID of the card*/
+#define RAS0_BASEREG  0x0010      /*Ras0 register - contain the base addr Ras0*/
+#define RAS2_BASEREG  0x0014
+#define CS_BASEREG    0x0018
+#define BOOT_BASEREG  0x001c
+#define GTREGS_BASEREG 0x0024   /*GTRegsBase reg-contain the base addr where*/
+                                /*the GT64010 internal regs where mapped    */
+/*
+ *  GT64010 internal registers
+ */
+        /* DRAM device coding  */
+#define LOW_RAS0_DREG 0x0400    /*Ras0 low decode address*/
+#define HI_RAS0_DREG  0x0404    /*Ras0 high decode address*/
+#define LOW_RAS1_DREG 0x0408    /*Ras1 low decode address*/
+#define HI_RAS1_DREG  0x040c    /*Ras1 high decode address*/
+#define LOW_RAS2_DREG 0x0410    /*Ras2 low decode address*/
+#define HI_RAS2_DREG  0x0414    /*Ras2 high decode address*/
+#define LOW_RAS3_DREG 0x0418    /*Ras3 low decode address*/
+#define HI_RAS3_DREG  0x041c    /*Ras3 high decode address*/
+        /* I/O CS device coding  */
+#define LOW_CS0_DREG  0x0420 /* CS0* low decode register */
+#define HI_CS0_DREG   0x0424 /* CS0* high decode register */
+#define LOW_CS1_DREG  0x0428 /* CS1* low decode register */
+#define HI_CS1_DREG   0x042c /* CS1* high decode register */
+#define LOW_CS2_DREG  0x0430 /* CS2* low decode register */
+#define HI_CS2_DREG   0x0434 /* CS2* high decode register */
+#define LOW_CS3_DREG  0x0438 /* CS3* low decode register */
+#define HI_CS3_DREG   0x043c /* CS3* high decode register */
+        /* Boot PROM device coding */
+#define LOW_BOOTCS_DREG 0x0440 /* Boot CS low decode register */
+#define HI_BOOTCS_DREG 0x0444 /* Boot CS High decode register */
+        /* DRAM group coding (for CPU)  */
+#define LO_RAS10_GREG 0x0008    /*Ras1..0 group low decode address*/
+#define HI_RAS10_GREG 0x0010    /*Ras1..0 group high decode address*/
+#define LO_RAS32_GREG 0x0018    /*Ras3..2 group low decode address  */
+#define HI_RAS32_GREG 0x0020    /*Ras3..2 group high decode address  */
+        /* I/O CS group coding for (CPU)  */
+#define LO_CS20_GREG  0x0028 /* CS2..0 group low decode register */
+#define HI_CS20_GREG  0x0030 /* CS2..0 group high decode register */
+#define LO_CS3B_GREG  0x0038 /* CS3 & PROM group low decode register */
+#define HI_CS3B_GREG  0x0040 /* CS3 & PROM group high decode register */
+        /* Galileo specific PCI config. */
+#define PCI_TIMEOUT_RET 0x0c04 /* Time Out and retry register */
+#define RAS10_BANKSIZE 0x0c08 /* RAS 1..0 group PCI bank size */
+#define RAS32_BANKSIZE 0x0c0c /* RAS 3..2 group PCI bank size */
+#define CS20_BANKSIZE 0x0c10 /* CS 2..0 group PCI bank size */
+#define CS3B_BANKSIZE 0x0c14 /* CS 3 & Boot group PCI bank size */
+#define DRAM_SIZE     0x0001      /*Dram size in mega bytes*/
+#define PROM_SIZE     0x08000     /*Prom size in bytes*/
+/*--------------------------------------------------------------------------*/
+#define OFFS_DIVA_INIT_TASK_COUNT 0x68
+#define OFFS_DSP_CODE_BASE_ADDR   0x6c
+#define OFFS_XLOG_BUF_ADDR        0x70
+#define OFFS_XLOG_COUNT_ADDR      0x74
+#define OFFS_XLOG_OUT_ADDR        0x78
+#define OFFS_PROTOCOL_END_ADDR    0x7c
+#define OFFS_PROTOCOL_ID_STRING   0x80
+/*--------------------------------------------------------------------------*/
diff -Nru a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/mntfunc.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,332 @@
+/* $Id: mntfunc.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * Maint module
+ *
+ * Copyright 2000,2001 by Armin Schindler (mac@melware.de)
+ * Copyright 2000,2001 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "di_defs.h"
+#include "debug_if.h"
+
+extern char *DRIVERRELEASE;
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+extern void DIVA_DIDD_Read (void *, int);
+
+#define MAX_DESCRIPTORS  32
+
+static dword notify_handle;
+static DESCRIPTOR DAdapter;
+static DESCRIPTOR MAdapter;
+static DESCRIPTOR MaintDescriptor = { IDI_DIMAINT, 0, 0, (IDI_CALL)diva_maint_prtComp };
+
+extern void *diva_os_malloc_tbuffer(unsigned long flags, unsigned long size);
+extern void diva_os_free_tbuffer(unsigned long flags, void* ptr);
+extern int diva_os_copy_to_user(void* os_handle, void* dst, const void* src, int length);
+extern int diva_os_copy_from_user(void* os_handle, void* dst, const void* src, int length);
+
+static void no_printf (unsigned char * x ,...)
+{
+  /* dummy debug function */
+}
+DIVA_DI_PRINTF dprintf = no_printf;
+
+#include "debuglib.c"
+
+/*
+ * stop debug
+ */
+static void stop_dbg(void)
+{
+  DbgDeregister();
+  memset(&MAdapter, 0, sizeof(MAdapter));
+  dprintf = no_printf;
+}
+
+/*
+ *  DIDD callback function
+ */
+static void * didd_callback (void *context, DESCRIPTOR* adapter, int removal)
+{
+  if (adapter->type == IDI_DADAPTER) {
+    DBG_ERR(("cb: Change in DAdapter ? Oops ?."));
+  } else if (adapter->type == IDI_DIMAINT) {
+    if (removal) {
+      stop_dbg();
+    } else {
+      memcpy(&MAdapter, adapter, sizeof(MAdapter));
+      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
+      DbgRegister("MAINT", DRIVERRELEASE, DBG_DEFAULT);
+    }
+  } else if ((adapter->type > 0) && (adapter->type < 16)) {
+    if (removal) {
+      diva_mnt_remove_xdi_adapter(adapter);
+    } else {
+      diva_mnt_add_xdi_adapter(adapter);
+    }
+  }
+	return(NULL);
+}
+
+/*
+ * connect to didd
+ */
+static int DIVA_INIT_FUNCTION connect_didd(void)
+{
+  int x = 0;
+  int dadapter = 0;
+  IDI_SYNC_REQ req;
+  DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+  DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+  for (x = 0; x < MAX_DESCRIPTORS; x++)
+  {
+    if (DIDD_Table[x].type == IDI_DADAPTER)
+    {  /* DADAPTER found */
+      dadapter = 1;
+      memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+      req.didd_notify.e.Req = 0;
+      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+      req.didd_notify.info.callback = didd_callback;
+      req.didd_notify.info.context = 0;
+      DAdapter.request((ENTITY *)&req);
+      if (req.didd_notify.e.Rc != 0xff)
+        return(0);
+      notify_handle = req.didd_notify.info.handle;
+      /* Register MAINT (me) */
+      req.didd_add_adapter.e.Req = 0;
+      req.didd_add_adapter.e.Rc = IDI_SYNC_REQ_DIDD_ADD_ADAPTER;
+      req.didd_add_adapter.info.descriptor = (void *)&MaintDescriptor;
+      DAdapter.request((ENTITY *)&req);
+      if (req.didd_add_adapter.e.Rc != 0xff)
+        return(0);
+    } else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) {
+      diva_mnt_add_xdi_adapter(&DIDD_Table[x]);
+    }
+  }
+  return(dadapter);
+}
+
+/*
+ * disconnect from didd
+ */
+static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+{
+  IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+  req.didd_notify.e.Req = 0;
+  req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+  req.didd_notify.info.handle = notify_handle;
+  DAdapter.request((ENTITY *)&req);
+
+  req.didd_remove_adapter.e.Req = 0;
+  req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER;
+  req.didd_remove_adapter.info.p_request = (IDI_CALL)MaintDescriptor.request;
+  DAdapter.request((ENTITY *)&req);
+}
+
+/*
+ * read/write maint
+ */
+int maint_read_write(void * buf)
+{
+  byte data[128];
+  dword cmd, id, mask;
+  int ret = 0;
+
+  if (diva_os_copy_from_user(NULL, (void *)&data[0], buf, 3*sizeof(dword))) {
+    return(-EFAULT);
+  }
+
+  cmd  = *(dword *)&data[0]; /* command */
+  id   = *(dword *)&data[4]; /* driver id */
+  mask = *(dword *)&data[8]; /* mask or size */
+
+  switch (cmd) {
+    case DITRACE_CMD_GET_DRIVER_INFO:
+      if ((ret = diva_get_driver_info (id, data, sizeof(data))) > 0) {
+        if (diva_os_copy_to_user(NULL, buf, (void*)&data[0], ret))
+          ret = -EFAULT;
+      } else {
+        ret = -EINVAL;
+      }
+      break;
+
+    case DITRACE_READ_DRIVER_DBG_MASK:
+      if ((ret = diva_get_driver_dbg_mask (id, (byte*)data)) > 0) {
+        if (diva_os_copy_to_user(NULL, buf, (void*)&data[0], ret))
+          ret = -EFAULT;
+      } else {
+        ret = -ENODEV;
+      }
+      break;
+
+    case DITRACE_WRITE_DRIVER_DBG_MASK:
+      if ((ret = diva_set_driver_dbg_mask (id, mask)) <= 0) {
+        ret = -ENODEV;
+      }
+      break;
+
+    case DITRACE_READ_TRACE_ENTRY: {
+      diva_os_spin_lock_magic_t old_irql;
+      word size;
+      diva_dbg_entry_head_t* pmsg;
+      byte* pbuf;
+
+      if ((pmsg = diva_maint_get_message (&size, &old_irql))) {
+        if (size > mask) {
+          diva_maint_ack_message (0, &old_irql);
+          ret = -EINVAL;
+        } else {
+          if (!(pbuf = diva_os_malloc_tbuffer(0, size))) {
+            diva_maint_ack_message (0, &old_irql);
+            ret = -ENOMEM;
+          } else {
+            ret = size;
+            memcpy (pbuf, pmsg, size);
+            diva_maint_ack_message (1, &old_irql);
+            if (diva_os_copy_to_user(NULL, buf, (void*)pbuf, size))
+              ret = -EFAULT;
+            diva_os_free_tbuffer(0, pbuf);
+          }
+        }
+      } else {
+        ret = 0;
+      }
+    } break;
+
+    case DITRACE_READ_TRACE_ENTRYS: {
+      diva_os_spin_lock_magic_t old_irql;
+      word size;
+      diva_dbg_entry_head_t* pmsg;
+      byte* pbuf = 0;
+      int written = 0;
+
+      if (mask < 4096) {
+        ret = -EINVAL;
+        break;
+      }
+      if (!(pbuf = diva_os_malloc_tbuffer(0, mask))) {
+        return (-ENOMEM);
+      }
+
+      for (;;) {
+        if (!(pmsg = diva_maint_get_message (&size, &old_irql))) {
+          break;
+        }
+        if ((size+8) > mask) {
+          diva_maint_ack_message (0, &old_irql);
+          break;
+        }
+        /*
+          Write entry length
+          */
+        pbuf[written++] = (byte)size;
+        pbuf[written++] = (byte)(size >> 8);
+        pbuf[written++] = 0;
+        pbuf[written++] = 0;
+        /*
+          Write message
+          */
+        memcpy (&pbuf[written], pmsg, size);
+        diva_maint_ack_message (1, &old_irql);
+        written += size;
+        mask -= (size+4);
+      }
+      pbuf[written++] = 0;
+      pbuf[written++] = 0;
+      pbuf[written++] = 0;
+      pbuf[written++] = 0;
+
+      if (diva_os_copy_to_user(NULL, buf, (void*)pbuf, written)) {
+        ret = -EFAULT;
+      } else {
+        ret = written;
+      }
+      diva_os_free_tbuffer(0, pbuf);
+    } break;
+
+    default:
+      ret = -EINVAL;
+  }
+  return (ret);
+}
+
+/*
+ *  init
+ */
+int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer, unsigned long diva_dbg_mem)
+{
+  if (*buffer_length < 64) {
+    *buffer_length = 64;
+  }
+  if (*buffer_length > 512) {
+    *buffer_length = 512;
+  }
+  *buffer_length *= 1024;
+
+  if (diva_dbg_mem) {
+    *buffer = (void*)diva_dbg_mem;
+  } else {
+    while ((*buffer_length >= (64*1024)) && (!(*buffer = diva_os_malloc_tbuffer(0, *buffer_length)))) {
+      *buffer_length -= 1024;
+    }
+  
+    if (!*buffer) {
+      DBG_ERR(("init: Can not alloc trace buffer"));
+      return(0);
+    }
+  }
+
+  if (diva_maint_init (*buffer, *buffer_length, (diva_dbg_mem == 0))) {
+    if (!diva_dbg_mem) {
+      diva_os_free_tbuffer(0, *buffer);
+    }
+		DBG_ERR(("init: maint init failed"));
+    return(0);
+  }
+
+  if (!connect_didd()) {
+    DBG_ERR(("init: failed to connect to DIDD."));
+    diva_maint_finit();
+    if (!diva_dbg_mem) {
+      diva_os_free_tbuffer(0, *buffer);
+    }
+		return(0);
+  }
+  return(1);  
+}
+
+/*
+ *  exit
+ */
+void DIVA_EXIT_FUNCTION mntfunc_finit(void)
+{
+  void* buffer;
+  int i = 100;
+
+  while (diva_mnt_shutdown_xdi_adapters () && i--) {
+			diva_os_sleep(10);
+  }
+
+  disconnect_didd();
+
+  if ((buffer = diva_maint_finit ())) {
+		diva_os_free_tbuffer(0, buffer);
+  }
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/os_4bri.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1014 @@
+/* $Id: os_4bri.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "dlist.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "dsp_defs.h"
+#include "di.h" 
+#include "io.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "os_4bri.h"
+#include "diva_pci.h"
+#include "mi_pc.h"
+#include "dsrv4bri.h"
+
+void* diva_xdiLoadFileFile   = 0;
+dword diva_xdiLoadFileLength = 0;
+
+/*
+**  IMPORTS
+*/
+extern void prepare_qBri_functions (PISDN_ADAPTER IoAdapter);
+extern void prepare_qBri2_functions (PISDN_ADAPTER IoAdapter);
+extern void diva_xdi_display_adapter_features (int card);
+extern void diva_add_slave_adapter (diva_os_xdi_adapter_t* a);
+
+extern int qBri_FPGA_download (PISDN_ADAPTER IoAdapter);
+extern void start_qBri_hardware (PISDN_ADAPTER IoAdapter);
+
+extern int diva_card_read_xlog (diva_os_xdi_adapter_t* a);
+
+/*
+**  LOCALS
+*/
+static unsigned long _4bri_bar_length[4] = {
+  0x100,
+  0x100, /* I/O */
+  MQ_MEMORY_SIZE,
+  0x2000
+};
+static unsigned long _4bri_v2_bar_length[4] = {
+  0x100,
+  0x100, /* I/O */
+  MQ2_MEMORY_SIZE,
+  0x10000
+};
+static unsigned long _4bri_v2_bri_bar_length[4] = {
+  0x100,
+  0x100, /* I/O */
+  BRI2_MEMORY_SIZE,
+  0x10000
+};
+
+
+static int diva_4bri_cleanup_adapter (diva_os_xdi_adapter_t* a);
+static int _4bri_get_serial_number (diva_os_xdi_adapter_t* a);
+static int diva_4bri_cmd_card_proc (struct _diva_os_xdi_adapter* a,
+                                    diva_xdi_um_cfg_cmd_t* cmd,
+                                    int length);
+static int diva_4bri_cleanup_slave_adapters (diva_os_xdi_adapter_t* a);
+static int diva_4bri_write_fpga_image (diva_os_xdi_adapter_t* a,
+                                       byte* data,
+                                       dword length);
+static int diva_4bri_reset_adapter (PISDN_ADAPTER IoAdapter);
+static int diva_4bri_write_sdram_block (PISDN_ADAPTER IoAdapter,
+                                        dword address,
+                                        const byte* data,
+                                        dword length,
+                                        dword limit);
+static int diva_4bri_start_adapter (PISDN_ADAPTER IoAdapter,
+                                    dword start_address,
+                                    dword features);
+static int check_qBri_interrupt (PISDN_ADAPTER IoAdapter);
+static int diva_4bri_stop_adapter (diva_os_xdi_adapter_t* a);
+
+static int
+_4bri_is_rev_2_card (int card_ordinal)
+{
+  switch (card_ordinal) {
+    case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
+    case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
+    case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+    case CARDTYPE_DIVASRV_B_2F_PCI:
+    case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+      return (1);
+  }
+  return (0);
+}
+
+static int
+_4bri_is_rev_2_bri_card (int card_ordinal) {
+  switch (card_ordinal) {
+    case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+    case CARDTYPE_DIVASRV_B_2F_PCI:
+    case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+      return (1);
+	}
+	return (0);
+}
+
+/*
+**  BAR0 - MEM - 0x100    - CONFIG MEM
+**  BAR1 - I/O - 0x100    - UNUSED
+**  BAR2 - MEM - MQ_MEMORY_SIZE (MQ2_MEMORY_SIZE on Rev.2) - SDRAM
+**  BAR3 - MEM - 0x2000 (0x10000 on Rev.2)   - CNTRL
+**
+**  Called by master adapter, that will initialize and add slave adapters
+*/
+int
+diva_4bri_init_card (diva_os_xdi_adapter_t* a)
+{
+  int bar, i;
+  PADAPTER_LIST_ENTRY quadro_list;
+  diva_os_xdi_adapter_t* diva_current;
+  diva_os_xdi_adapter_t* adapter_list[4];
+  PISDN_ADAPTER Slave;
+  dword offset;
+  unsigned long bar_length[sizeof(_4bri_bar_length)/sizeof(_4bri_bar_length[0])];
+  int v2 = _4bri_is_rev_2_card (a->CardOrdinal);
+  int tasks = _4bri_is_rev_2_bri_card (a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT;
+  int factor = (tasks == 1) ? 1 : 2;
+
+  if (v2) {
+    if (_4bri_is_rev_2_bri_card (a->CardOrdinal)) {
+      memcpy (bar_length, _4bri_v2_bri_bar_length, sizeof(bar_length));
+    } else {
+      memcpy (bar_length, _4bri_v2_bar_length, sizeof(bar_length));
+    }
+  } else {
+    memcpy (bar_length, _4bri_bar_length, sizeof(bar_length));
+  }
+  DBG_TRC(("SDRAM_LENGTH=%08x, tasks=%d, factor=%d",
+           bar_length[2], tasks, factor))
+
+  /*
+    Get Serial Number
+    The serial number of 4BRI is accessible in accordance with PCI spec
+    via command register located in configuration space, also we do not
+    have to map any BAR before we can access it
+  */
+  if (!_4bri_get_serial_number (a)) {
+    DBG_ERR(("A: 4BRI can't ger Serial Number"))
+    diva_4bri_cleanup_adapter (a);
+    return (-1);
+  }
+
+  /*
+    Set properties
+  */
+  a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+  DBG_LOG(("Load %s, SN:%ld, bus:%02x, func:%02x",
+            a->xdi_adapter.Properties.Name,
+            a->xdi_adapter.serialNo,
+            a->resources.pci.bus,
+            a->resources.pci.func))
+
+  /*
+    First initialization step: get and check hardware resoures.
+    Do not map resources and do not access card at this step
+  */
+
+  for (bar = 0; bar < 4; bar++) {
+    a->resources.pci.bar[bar] = divasa_get_pci_bar (a->resources.pci.bus,
+                                                    a->resources.pci.func,
+                                                    bar,
+                                                    a->resources.pci.hdev);
+    if (!a->resources.pci.bar[bar] ||
+        (a->resources.pci.bar[bar] == 0xFFFFFFF0)) {
+      DBG_ERR(("A: invalid bar[%d]=%08x", bar, a->resources.pci.bar[bar]))
+      return (-1);
+    }
+  }
+  a->resources.pci.irq = (byte)divasa_get_pci_irq (a->resources.pci.bus,
+                                                   a->resources.pci.func,
+                                                   a->resources.pci.hdev);
+  if (!a->resources.pci.irq) {
+    DBG_ERR(("A: invalid irq"));
+    return (-1);
+  }
+
+  a->xdi_adapter.sdram_bar = a->resources.pci.bar [2];
+
+  /*
+    Map all MEMORY BAR's
+  */
+  for (bar = 0; bar < 4; bar++) {
+    if (bar != 1) { /* ignore I/O */
+      a->resources.pci.addr[bar] = divasa_remap_pci_bar (a->resources.pci.bar[bar],
+                                                         bar_length[bar]);
+      if (!a->resources.pci.addr[bar]) {
+        DBG_ERR(("A: 4BRI: can't map bar[%d]", bar))
+        diva_4bri_cleanup_adapter (a);
+        return (-1);
+      }
+    }
+  }
+
+  /*
+    Register I/O port
+  */
+  sprintf (&a->port_name[0], "DIVA 4BRI %ld", (long)a->xdi_adapter.serialNo);
+
+  if (diva_os_register_io_port (1, a->resources.pci.bar[1],
+                                bar_length[1],
+                                &a->port_name[0])) {
+    DBG_ERR(("A: 4BRI: can't register bar[1]"))
+    diva_4bri_cleanup_adapter (a);
+    return (-1);
+  }
+
+  a->resources.pci.addr[1] = (void*)(unsigned long)a->resources.pci.bar[1];
+
+  /*
+    Set cleanup pointer for base adapter only, so slave adapter
+    will be unable to get cleanup
+  */
+  a->interface.cleanup_adapter_proc = diva_4bri_cleanup_adapter;
+
+  /*
+    Create slave adapters
+  */
+  if (tasks > 1) {
+    if (!(a->slave_adapters[0] = (diva_os_xdi_adapter_t*)diva_os_malloc (0, sizeof(*a)))) {
+      diva_4bri_cleanup_adapter (a);
+      return (-1);
+    }
+    if (!(a->slave_adapters[1] = (diva_os_xdi_adapter_t*)diva_os_malloc (0, sizeof(*a)))) {
+      diva_os_free (0, a->slave_adapters[0]);
+      a->slave_adapters[0] = 0;
+      diva_4bri_cleanup_adapter (a);
+      return (-1);
+    }
+    if (!(a->slave_adapters[2] = (diva_os_xdi_adapter_t*)diva_os_malloc (0, sizeof(*a)))) {
+      diva_os_free (0, a->slave_adapters[0]);
+      diva_os_free (0, a->slave_adapters[1]);
+      a->slave_adapters[0] = 0;
+      a->slave_adapters[1] = 0;
+      diva_4bri_cleanup_adapter (a);
+      return (-1);
+    }
+    memset (a->slave_adapters[0], 0x00, sizeof(*a));
+    memset (a->slave_adapters[1], 0x00, sizeof(*a));
+    memset (a->slave_adapters[2], 0x00, sizeof(*a));
+  }
+
+  adapter_list[0] = a;
+  adapter_list[1] = a->slave_adapters[0];
+  adapter_list[2] = a->slave_adapters[1];
+  adapter_list[3] = a->slave_adapters[2];
+
+  /*
+    Allocate slave list
+  */
+  quadro_list = (PADAPTER_LIST_ENTRY)diva_os_malloc (0, sizeof(*quadro_list));
+  if (!(a->slave_list = quadro_list)) {
+    for (i = 0; i < (tasks-1); i++) {
+      diva_os_free (0, a->slave_adapters[bar]);
+      a->slave_adapters[bar] = 0;
+    }
+    diva_4bri_cleanup_adapter (a);
+    return (-1);
+  }
+  memset (quadro_list, 0x00, sizeof(*quadro_list));
+
+  /*
+    Set interfaces
+  */
+  a->xdi_adapter.QuadroList = quadro_list;
+  for (i = 0; i < tasks; i++) {
+    adapter_list[i]->xdi_adapter.ControllerNumber = i;
+    adapter_list[i]->xdi_adapter.tasks = tasks;
+    quadro_list->QuadroAdapter[i] = &adapter_list[i]->xdi_adapter;
+  }
+
+  for (i = 0; i < tasks; i++) {
+    diva_current = adapter_list[i];
+
+    diva_current->dsp_mask = 0x00000003;
+
+    diva_current->xdi_adapter.a.io = &diva_current->xdi_adapter;
+    diva_current->xdi_adapter.DIRequest = request;
+    diva_current->interface.cmd_proc = diva_4bri_cmd_card_proc;
+    diva_current->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+    diva_current->CardOrdinal = a->CardOrdinal;
+
+    diva_current->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
+    diva_current->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
+    diva_current->xdi_adapter.e_tbl = diva_os_malloc (0, diva_current->xdi_adapter.e_max * sizeof(E_INFO)); 
+
+    if (!diva_current->xdi_adapter.e_tbl) {
+      diva_4bri_cleanup_slave_adapters (a);
+      diva_4bri_cleanup_adapter (a);
+      for (i = 1; i < (tasks-1); i++) { diva_os_free (0, adapter_list[i]); }
+      return (-1);
+    }
+    memset (diva_current->xdi_adapter.e_tbl, 0x00, diva_current->xdi_adapter.e_max * sizeof(E_INFO));
+
+    if (diva_os_initialize_spin_lock (&diva_current->xdi_adapter.isr_spin_lock, "isr")) {
+      diva_4bri_cleanup_slave_adapters (a);
+      diva_4bri_cleanup_adapter (a);
+      for (i = 1; i < (tasks-1); i++) { diva_os_free (0, adapter_list[i]); }
+      return (-1);
+    }
+    if (diva_os_initialize_spin_lock (&diva_current->xdi_adapter.data_spin_lock, "data")) {
+      diva_4bri_cleanup_slave_adapters (a);
+      diva_4bri_cleanup_adapter (a);
+      for (i = 1; i < (tasks-1); i++) { diva_os_free (0, adapter_list[i]); }
+      return (-1);
+    }
+
+    strcpy (diva_current->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivas4brid");
+
+    if (diva_os_initialize_soft_isr (&diva_current->xdi_adapter.req_soft_isr,
+                                     DIDpcRoutine,
+                                     &diva_current->xdi_adapter)) {
+      diva_4bri_cleanup_slave_adapters (a);
+      diva_4bri_cleanup_adapter (a);
+      for (i = 1; i < (tasks-1); i++) { diva_os_free (0, adapter_list[i]); }
+      return (-1);
+    }
+
+    /*
+     Do not initialize second DPC - only one thread will be created
+    */
+    diva_current->xdi_adapter.isr_soft_isr.object = diva_current->xdi_adapter.req_soft_isr.object;
+  }
+
+  if (v2) {
+       prepare_qBri2_functions (&a->xdi_adapter);
+  } else {
+       prepare_qBri_functions (&a->xdi_adapter);
+  }
+
+  /*
+    Set up hardware related pointers
+  */
+  a->xdi_adapter.cfg = (void*)(unsigned long)a->resources.pci.bar[0]; /* BAR0 CONFIG */
+  a->xdi_adapter.port = (void*)(unsigned long)a->resources.pci.bar[1]; /* BAR1        */
+  a->xdi_adapter.Address = a->resources.pci.addr[2];        /* BAR2 SDRAM  */
+  a->xdi_adapter.ctlReg = (void*)(unsigned long)a->resources.pci.bar[3]; /* BAR3 CNTRL  */
+
+  a->xdi_adapter.reset = a->resources.pci.addr[0]; /* BAR0 CONFIG */
+  a->xdi_adapter.ram = a->resources.pci.addr[2]; /* BAR2 SDRAM  */
+  /*
+    ctlReg contains the register address for the MIPS CPU reset control
+  */
+  a->xdi_adapter.ctlReg = a->resources.pci.addr[3];  /* BAR3 CNTRL  */
+  /*
+    prom contains the register address for FPGA and EEPROM programming
+  */
+  a->xdi_adapter.prom = &a->xdi_adapter.reset[0x6E];
+  /*
+    reset contains the base address for the PLX 9054 register set
+  */
+  a->xdi_adapter.reset[PLX9054_INTCSR] = 0x00 ;	/* disable PCI interrupts */
+
+  /*
+    Replicate addresses to all instances, set shared memory
+    address for all instances
+  */
+  for (i = 0; i < tasks; i++) {
+    Slave = a->xdi_adapter.QuadroList->QuadroAdapter[i];
+    offset = Slave->ControllerNumber * (a->xdi_adapter.MemorySize>>factor);
+    Slave->Address = &a->xdi_adapter.Address[offset];
+    Slave->ram	= &a->xdi_adapter.ram[offset];
+    Slave->reset = a->xdi_adapter.reset;
+    Slave->ctlReg = a->xdi_adapter.ctlReg;
+    Slave->prom	= a->xdi_adapter.prom;
+    Slave->reset = a->xdi_adapter.reset;
+    Slave->sdram_bar = a->xdi_adapter.sdram_bar;
+  }
+  for (i = 0; i < tasks; i++) {
+    Slave = a->xdi_adapter.QuadroList->QuadroAdapter[i];
+    Slave->ram += ((a->xdi_adapter.MemorySize >> factor) - MQ_SHARED_RAM_SIZE);
+  }
+  for (i = 1; i < tasks; i++) {
+    Slave = a->xdi_adapter.QuadroList->QuadroAdapter[i];
+    Slave->serialNo = ((dword)(Slave->ControllerNumber << 24)) | a->xdi_adapter.serialNo;
+    Slave->cardType = a->xdi_adapter.cardType;
+  }
+
+  /*
+    Set IRQ handler
+  */
+  a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
+  sprintf (a->xdi_adapter.irq_info.irq_name, "DIVA 4BRI %ld", (long)a->xdi_adapter.serialNo);
+
+  if (diva_os_register_irq (a, a->xdi_adapter.irq_info.irq_nr,
+                            a->xdi_adapter.irq_info.irq_name)) {
+    diva_4bri_cleanup_slave_adapters (a);
+    diva_4bri_cleanup_adapter (a);
+    for (i = 1; i < (tasks-1); i++) { diva_os_free (0, adapter_list[i]); }
+    return (-1);
+  }
+
+  a->xdi_adapter.irq_info.registered = 1;
+
+  /*
+    Add three slave adapters
+  */
+  if (tasks > 1) {
+    diva_add_slave_adapter (adapter_list[1]);
+    diva_add_slave_adapter (adapter_list[2]);
+    diva_add_slave_adapter (adapter_list[3]);
+  }
+
+  diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
+                                      a->resources.pci.irq,
+                                      a->xdi_adapter.serialNo);
+
+  return (0);
+}
+
+/*
+**  Cleanup function will be called for master adapter only
+**  this is garanteed by design: cleanup callback is set
+**  by master adapter only
+*/
+static int
+diva_4bri_cleanup_adapter (diva_os_xdi_adapter_t* a)
+{
+  int bar;
+
+  /*
+    Stop adapter if running
+  */
+  if (a->xdi_adapter.Initialized) {
+    diva_4bri_stop_adapter (a);
+  }
+
+  /*
+    Remove IRQ handler
+  */
+  if (a->xdi_adapter.irq_info.registered) {
+    diva_os_remove_irq (a, a->xdi_adapter.irq_info.irq_nr);
+  }
+  a->xdi_adapter.irq_info.registered = 0;
+
+  /*
+    Free DPC's and spin locks on all adapters
+  */
+  diva_4bri_cleanup_slave_adapters (a);
+
+  /*
+    Unmap all BARS
+  */
+  for (bar = 0; bar < 4; bar++) {
+    if (bar != 1) {
+      if (a->resources.pci.bar[bar] && a->resources.pci.addr[bar]) {
+        divasa_unmap_pci_bar (a->resources.pci.addr[bar]);
+        a->resources.pci.bar[bar]  = 0;
+        a->resources.pci.addr[bar] = 0;
+      }
+    }
+  }
+
+  /*
+    Unregister I/O
+  */
+  if (a->resources.pci.bar[1] && a->resources.pci.addr[1]) {
+    diva_os_register_io_port (0, a->resources.pci.bar[1], 
+      _4bri_is_rev_2_card (a->CardOrdinal) ? _4bri_v2_bar_length[1] : _4bri_bar_length[1],
+      &a->port_name[0]);
+    a->resources.pci.bar[1]  = 0;
+    a->resources.pci.addr[1] = 0;
+  }
+
+  if (a->slave_list) {
+    diva_os_free (0, a->slave_list);
+    a->slave_list = 0;
+  }
+
+  return (0);
+}
+
+static int
+_4bri_get_serial_number (diva_os_xdi_adapter_t* a)
+{
+  dword data[64] ;
+  dword serNo ;
+  word addr, status, i, j ;
+  byte Bus, Slot;
+  void* hdev;
+
+  Bus = a->resources.pci.bus;
+  Slot = a->resources.pci.func;
+  hdev = a->resources.pci.hdev;
+
+  for ( i = 0 ; i < 64 ; ++i )
+  {
+    addr = i * 4 ;
+    for ( j = 0 ; j < 5; ++j )
+    {
+      PCIwrite (Bus, Slot, 0x4E, &addr, sizeof(addr), hdev) ;
+      diva_os_wait (1) ;
+      PCIread (Bus, Slot, 0x4E, &status, sizeof(status), hdev) ;
+      if (status & 0x8000)
+        break ;
+    }
+    if (j >= 5){
+      DBG_ERR(("EEPROM[%d] read failed (0x%x)", i * 4, addr))
+      return(0) ;
+    }
+    PCIread (Bus, Slot, 0x50, &data[i], sizeof (data[i]), hdev) ;
+  }
+  DBG_BLK(( (char *)&data[0], sizeof(data) ))
+
+  serNo  = data[32] ;
+  if (serNo == 0 || serNo == 0xffffffff)
+    serNo  = data[63] ;
+
+  if (!serNo) {
+    DBG_LOG(("W: Serial Number == 0, create one serial number"));
+    serNo  = a->resources.pci.bar[1] & 0xffff0000;
+    serNo |= a->resources.pci.bus << 8;
+    serNo |= a->resources.pci.func;
+  }
+	
+  a->xdi_adapter.serialNo = serNo;
+
+  DBG_REG(("Serial No.          : %ld", a->xdi_adapter.serialNo))
+
+  return (serNo) ;
+}
+
+/*
+**  Release resources of slave adapters
+*/
+static int
+diva_4bri_cleanup_slave_adapters (diva_os_xdi_adapter_t* a)
+{
+  diva_os_xdi_adapter_t* adapter_list[4];
+  diva_os_xdi_adapter_t* diva_current;
+  int i;
+
+  adapter_list[0] = a;
+  adapter_list[1] = a->slave_adapters[0];
+  adapter_list[2] = a->slave_adapters[1];
+  adapter_list[3] = a->slave_adapters[2];
+
+  for (i = 0; i < a->xdi_adapter.tasks; i++) {
+    diva_current = adapter_list[i];
+    if (diva_current) {
+      diva_os_destroy_spin_lock (&diva_current->xdi_adapter.isr_spin_lock, "unload");
+      diva_os_destroy_spin_lock (&diva_current->xdi_adapter.data_spin_lock,"unload");
+
+      diva_os_cancel_soft_isr (&diva_current->xdi_adapter.req_soft_isr);
+      diva_os_cancel_soft_isr (&diva_current->xdi_adapter.isr_soft_isr);
+
+      diva_os_remove_soft_isr (&diva_current->xdi_adapter.req_soft_isr);
+      diva_current->xdi_adapter.isr_soft_isr.object = 0;
+
+      if (diva_current->xdi_adapter.e_tbl) {
+        diva_os_free (0, diva_current->xdi_adapter.e_tbl);
+      }
+      diva_current->xdi_adapter.e_tbl   = 0;
+      diva_current->xdi_adapter.e_max   = 0;
+      diva_current->xdi_adapter.e_count = 0;
+    }
+  }
+
+  return (0);
+}
+
+static int
+diva_4bri_cmd_card_proc (struct _diva_os_xdi_adapter* a,
+                         diva_xdi_um_cfg_cmd_t* cmd,
+                         int length)
+{
+  int ret = -1;
+
+  if (cmd->adapter != a->controller) {
+    DBG_ERR(("A: 4bri_cmd, invalid controller=%d != %d",
+                  cmd->adapter, a->controller))
+    return (-1);
+  }
+
+  switch (cmd->command) {
+    case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        *(dword*)a->xdi_mbox.data = (dword)a->CardOrdinal;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        *(dword*)a->xdi_mbox.data = (dword)a->xdi_adapter.serialNo;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
+      if (!a->xdi_adapter.ControllerNumber) {
+        /*
+          Only master adapter can access hardware config
+        */
+        a->xdi_mbox.data_length = sizeof(dword)*9;
+        a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+        if (a->xdi_mbox.data) {
+          int i;
+          dword* data = (dword*)a->xdi_mbox.data;
+
+          for (i = 0; i < 8; i++) {
+            *data++ = a->resources.pci.bar[i];
+          }
+          *data++ = (dword)a->resources.pci.irq;
+          a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+          ret = 0;
+        }
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_CARD_STATE:
+      if (!a->xdi_adapter.ControllerNumber) {
+        a->xdi_mbox.data_length = sizeof(dword);
+        a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+        if (a->xdi_mbox.data) {
+          dword* data = (dword*)a->xdi_mbox.data;
+          if (!a->xdi_adapter.ram || !a->xdi_adapter.reset ||
+              !a->xdi_adapter.cfg) {
+            *data = 3;
+          } else if (a->xdi_adapter.trapped) {
+            *data = 2;
+          } else if (a->xdi_adapter.Initialized) {
+            *data = 1;
+          } else {
+            *data = 0;
+          }
+          a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+          ret = 0;
+        }
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_WRITE_FPGA:
+      if (!a->xdi_adapter.ControllerNumber) {
+        ret = diva_4bri_write_fpga_image (a, (byte*)&cmd[1], 
+                                          cmd->command_data.write_fpga.image_length);
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_RESET_ADAPTER:
+      if (!a->xdi_adapter.ControllerNumber) {
+        ret = diva_4bri_reset_adapter (&a->xdi_adapter);
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
+      if (!a->xdi_adapter.ControllerNumber) {
+        ret = diva_4bri_write_sdram_block (&a->xdi_adapter,
+                                           cmd->command_data.write_sdram.offset,
+                                           (byte*)&cmd[1],
+                                           cmd->command_data.write_sdram.length,
+                                           a->xdi_adapter.MemorySize);
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_START_ADAPTER:
+      if (!a->xdi_adapter.ControllerNumber) {
+        ret = diva_4bri_start_adapter (&a->xdi_adapter,
+                                       cmd->command_data.start.offset,
+                                       cmd->command_data.start.features);
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
+      if (!a->xdi_adapter.ControllerNumber) {
+        a->xdi_adapter.features = cmd->command_data.features.features;
+        a->xdi_adapter.a.protocol_capabilities = a->xdi_adapter.features;
+        DBG_TRC(("Set raw protocol features (%08x)", a->xdi_adapter.features))
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_STOP_ADAPTER:
+      if (!a->xdi_adapter.ControllerNumber) {
+        ret = diva_4bri_stop_adapter (a);
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
+      ret = diva_card_read_xlog (a);
+      break;
+
+    case DIVA_XDI_UM_CMD_READ_SDRAM:
+      if (!a->xdi_adapter.ControllerNumber && a->xdi_adapter.Address) {
+        if ((a->xdi_mbox.data_length = cmd->command_data.read_sdram.length)) {
+          if ((a->xdi_mbox.data_length+cmd->command_data.read_sdram.offset) < a->xdi_adapter.MemorySize) {
+            a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+            if (a->xdi_mbox.data) {
+              byte* src = a->xdi_adapter.Address;
+              byte* dst = a->xdi_mbox.data;
+              dword len = a->xdi_mbox.data_length;
+
+              src += cmd->command_data.read_sdram.offset;
+
+              while (len--) {
+                *dst++ = *src++;
+              }
+              a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+              ret = 0;
+            }
+          }
+        }
+      }
+      break;
+
+    default:
+      DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller, cmd->command))
+  }
+
+  return (ret);
+}
+
+void *
+xdiLoadFile (char *FileName, unsigned long *FileLength, unsigned long lim)
+{
+  void* ret = diva_xdiLoadFileFile;
+
+  if (FileLength) {
+    *FileLength = diva_xdiLoadFileLength;
+  }
+  diva_xdiLoadFileFile	 = 0;
+  diva_xdiLoadFileLength = 0;
+
+  return (ret);
+}
+
+void
+diva_os_set_qBri_functions (PISDN_ADAPTER IoAdapter)
+{
+}
+
+void
+diva_os_set_qBri2_functions (PISDN_ADAPTER IoAdapter)
+{
+}
+
+static int
+diva_4bri_write_fpga_image (diva_os_xdi_adapter_t* a, byte* data, dword length)
+{
+  int ret;
+
+  diva_xdiLoadFileFile = data;
+  diva_xdiLoadFileLength = length;
+
+  ret = qBri_FPGA_download (&a->xdi_adapter);
+
+  diva_xdiLoadFileFile = 0;
+  diva_xdiLoadFileLength = 0;
+
+  return (ret ? 0 : -1);
+}
+
+static int
+diva_4bri_reset_adapter (PISDN_ADAPTER IoAdapter)
+{
+  PISDN_ADAPTER Slave;
+  int i;
+
+  if (!IoAdapter->Address || !IoAdapter->reset) {
+    return (-1);
+  }
+  if (IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) can't reset 4BRI adapter - please stop first", IoAdapter->ANum))
+    return (-1);
+  }
+
+  /*
+    Forget all entities on all adapters
+  */
+  for (i = 0; ((i < IoAdapter->tasks) && IoAdapter->QuadroList); i++) {
+    Slave = IoAdapter->QuadroList->QuadroAdapter[i];
+    Slave->e_count =  0;
+    if (Slave->e_tbl) {
+      memset (Slave->e_tbl, 0x00, Slave->e_max * sizeof(E_INFO));
+    }
+    Slave->head	= 0;
+    Slave->tail = 0;
+    Slave->assign = 0;
+    Slave->trapped = 0;
+
+    memset (&Slave->a.IdTable[0],              0x00, sizeof(Slave->a.IdTable));
+    memset (&Slave->a.IdTypeTable[0],          0x00, sizeof(Slave->a.IdTypeTable));
+    memset (&Slave->a.FlowControlIdTable[0],   0x00, sizeof(Slave->a.FlowControlIdTable));
+    memset (&Slave->a.FlowControlSkipTable[0], 0x00, sizeof(Slave->a.FlowControlSkipTable));
+    memset (&Slave->a.misc_flags_table[0],     0x00, sizeof(Slave->a.misc_flags_table));
+    memset (&Slave->a.rx_stream[0],            0x00, sizeof(Slave->a.rx_stream));
+    memset (&Slave->a.tx_stream[0],            0x00, sizeof(Slave->a.tx_stream));
+    memset (&Slave->a.tx_pos[0],               0x00, sizeof(Slave->a.tx_pos));
+    memset (&Slave->a.rx_pos[0],               0x00, sizeof(Slave->a.rx_pos));
+  }
+
+  return (0);
+}
+
+
+static int
+diva_4bri_write_sdram_block (PISDN_ADAPTER IoAdapter,
+                             dword address,
+                             const byte* data,
+                             dword length,
+                             dword limit)
+{
+  byte* mem = IoAdapter->Address;
+
+  if (((address + length) >= limit) || !mem) {
+    DBG_ERR(("A: A(%d) write PRI address=0x%08lx", IoAdapter->ANum, address+length))
+    return (-1);
+  }
+  mem += address;
+
+  while (length--) {
+    *mem++ = *data++;
+  }
+
+  return (0);
+}
+
+static int
+diva_4bri_start_adapter (PISDN_ADAPTER IoAdapter,
+                         dword start_address,
+                         dword features)
+{
+  volatile word *signature;
+  int started = 0;
+  int i;
+
+  /*
+    start adapter
+  */
+  start_qBri_hardware (IoAdapter);
+
+  /*
+    wait for signature in shared memory (max. 3 seconds)
+  */
+  signature = (volatile word *)(&IoAdapter->ram[0x1E]) ;
+
+  for ( i = 0 ; i < 300 ; ++i ) {
+    diva_os_wait (10) ;
+    if (READ_WORD(&signature[0]) == 0x4447) {
+      DBG_TRC(("Protocol startup time %d.%02d seconds", (i / 100), (i % 100) ))
+      started = 1;
+      break;
+    }
+  }
+
+  for (i = 1; i < IoAdapter->tasks; i++) {
+    IoAdapter->QuadroList->QuadroAdapter[i]->features = IoAdapter->features;
+    IoAdapter->QuadroList->QuadroAdapter[i]->a.protocol_capabilities =
+                          IoAdapter->features;
+  }
+
+  if (!started) {
+    DBG_FTL(("%s: Adapter selftest failed, signature=%04x",
+              IoAdapter->Properties.Name, READ_WORD(&signature[0])))
+      (*(IoAdapter->trapFnc))(IoAdapter);
+    IoAdapter->stop(IoAdapter);
+    return (-1);
+  }
+
+  for (i = 0; i < IoAdapter->tasks; i++) {
+    IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 1;
+    IoAdapter->QuadroList->QuadroAdapter[i]->IrqCount = 0;
+  }
+
+  if (check_qBri_interrupt (IoAdapter)) {
+    DBG_ERR(("A: A(%d) interrupt test failed", IoAdapter->ANum))
+    for (i = 0; i < IoAdapter->tasks; i++) {
+      IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
+    }
+    IoAdapter->stop(IoAdapter);
+    return (-1);
+  }
+
+  IoAdapter->Properties.Features = (word)features;
+  diva_xdi_display_adapter_features (IoAdapter->ANum);
+
+  for (i = 0; i < IoAdapter->tasks; i++) {
+    DBG_LOG(("A(%d) %s adapter successfull started",
+              IoAdapter->QuadroList->QuadroAdapter[i]->ANum,
+              (IoAdapter->tasks == 1) ? "BRI 2.0" : "4BRI"))
+    diva_xdi_didd_register_adapter (IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
+    IoAdapter->QuadroList->QuadroAdapter[i]->Properties.Features = (word)features;
+  }
+
+  return (0);
+}
+
+static int
+check_qBri_interrupt (PISDN_ADAPTER IoAdapter)
+{
+#ifdef	SUPPORT_INTERRUPT_TEST_ON_4BRI
+  int i ;
+  ADAPTER *a = &IoAdapter->a ;
+
+  IoAdapter->IrqCount = 0 ;
+
+  if ( IoAdapter->ControllerNumber > 0 )
+    return (-1) ;
+
+  IoAdapter->reset[PLX9054_INTCSR] = PLX9054_INT_ENABLE ;
+  /*
+    interrupt test
+  */
+  a->ReadyInt = 1 ;
+  a->ram_out (a, &PR_RAM->ReadyInt, 1) ;
+
+  for ( i = 100 ; !IoAdapter->IrqCount && (i-- > 0) ; diva_os_wait(10)) ;
+
+  return ((IoAdapter->IrqCount > 0) ? 0 : -1);
+#else
+  dword volatile *qBriIrq ;
+  /*
+    Reset on-board interrupt register
+  */
+  IoAdapter->IrqCount = 0 ;
+  qBriIrq = (dword volatile *)(&IoAdapter->ctlReg[_4bri_is_rev_2_card (IoAdapter->cardType) ? (MQ2_BREG_IRQ_TEST) : (MQ_BREG_IRQ_TEST)]);
+
+  WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF);
+
+  IoAdapter->reset[PLX9054_INTCSR] = PLX9054_INT_ENABLE ;
+
+  diva_os_wait(100);
+
+  return (0) ;
+#endif	/* SUPPORT_INTERRUPT_TEST_ON_4BRI */
+}
+
+static void
+diva_4bri_clear_interrupts (diva_os_xdi_adapter_t* a)
+{
+  PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+
+  /*
+    clear any pending interrupt
+  */
+  IoAdapter->disIrq (IoAdapter) ;
+
+  IoAdapter->tst_irq (&IoAdapter->a) ;
+  IoAdapter->clr_irq (&IoAdapter->a) ;
+  IoAdapter->tst_irq (&IoAdapter->a) ;
+
+  /*
+    kill pending dpcs
+  */
+  diva_os_cancel_soft_isr (&IoAdapter->req_soft_isr);
+  diva_os_cancel_soft_isr (&IoAdapter->isr_soft_isr);
+}
+
+static int
+diva_4bri_stop_adapter (diva_os_xdi_adapter_t* a)
+{
+  PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+  int i;
+
+  if (!IoAdapter->ram) {
+    return (-1);
+  }
+
+  if (!IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) can't stop PRI adapter - not running", IoAdapter->ANum))
+    return (-1); /* nothing to stop */
+  }
+
+  for (i = 0; i < IoAdapter->tasks; i++) {
+    IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
+  }
+
+  /*
+    Disconnect Adapters from DIDD
+  */
+  for (i = 0; i < IoAdapter->tasks; i++) {
+    diva_xdi_didd_remove_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
+  }
+
+  i = 100;
+
+  /*
+    Stop interrupts
+  */
+  a->clear_interrupts_proc = diva_4bri_clear_interrupts;
+  IoAdapter->a.ReadyInt = 1;
+  IoAdapter->a.ram_inc (&IoAdapter->a, &PR_RAM->ReadyInt) ;
+  do {
+    diva_os_sleep (10);
+  } while (i-- && a->clear_interrupts_proc);
+  if (a->clear_interrupts_proc) {
+    diva_4bri_clear_interrupts (a);
+    a->clear_interrupts_proc = 0;
+    DBG_ERR(("A: A(%d) no final interrupt from 4BRI adapter", IoAdapter->ANum))
+  }
+  IoAdapter->a.ReadyInt = 0;
+
+  /*
+    Stop and reset adapter
+  */
+  IoAdapter->stop (IoAdapter) ;
+
+  return (0);
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/os_4bri.h b/drivers/isdn/hardware/eicon/os_4bri.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/os_4bri.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,8 @@
+/* $Id: os_4bri.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_OS_4_BRI_H__
+#define __DIVA_OS_4_BRI_H__
+
+int diva_4bri_init_card (diva_os_xdi_adapter_t* a);
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/os_bri.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,745 @@
+/* $Id: os_bri.c,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "dlist.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "dsp_defs.h"
+#include "di.h"
+#include "io.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "os_bri.h"
+#include "diva_pci.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+
+/*
+**  IMPORTS
+*/
+extern void prepare_maestra_functions (PISDN_ADAPTER IoAdapter);
+extern void diva_xdi_display_adapter_features (int card);
+extern int diva_card_read_xlog (diva_os_xdi_adapter_t* a);
+
+/*
+**  LOCALS
+*/
+static int bri_bar_length[3] = {
+  0x80,
+  0x80,
+  0x20
+};
+static int diva_bri_cleanup_adapter (diva_os_xdi_adapter_t* a);
+static dword diva_bri_get_serial_number (diva_os_xdi_adapter_t* a);
+static int diva_bri_cmd_card_proc (struct _diva_os_xdi_adapter* a,
+                                   diva_xdi_um_cfg_cmd_t* cmd,
+                                   int length);
+static int diva_bri_reregister_io (diva_os_xdi_adapter_t* a);
+static int diva_bri_reset_adapter (PISDN_ADAPTER IoAdapter);
+static int diva_bri_write_sdram_block (PISDN_ADAPTER IoAdapter,
+                                       dword  address,
+                                       const byte* data,
+                                       dword length);
+static int diva_bri_start_adapter (PISDN_ADAPTER IoAdapter,
+                                   dword start_address,
+                                   dword features);
+static int diva_bri_stop_adapter (diva_os_xdi_adapter_t* a);
+
+/*
+**  BAR0 - MEM Addr  - 0x80  - NOT USED
+**  BAR1 - I/O Addr  - 0x80
+**  BAR2 - I/O Addr  - 0x20
+*/
+int
+diva_bri_init_card (diva_os_xdi_adapter_t* a)
+{
+  int  bar;
+  dword bar2 = 0, bar2_length = 0xffffffff;
+  word cmd = 0, cmd_org;
+  byte Bus, Slot;
+	void* hdev;
+
+  /*
+    Set properties
+  */
+  a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+  DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name))
+
+  /*
+    Get resources
+  */
+  for (bar = 0; bar < 3; bar++) {
+    a->resources.pci.bar[bar] = divasa_get_pci_bar (a->resources.pci.bus,
+                                                    a->resources.pci.func,
+                                                    bar,
+                                                    a->resources.pci.hdev);
+    if (!a->resources.pci.bar[bar]) {
+      DBG_ERR(("A: can't get BAR[%d]", bar))
+      return (-1);
+    }
+  }
+
+  a->resources.pci.irq = (byte)divasa_get_pci_irq (a->resources.pci.bus,
+                                                   a->resources.pci.func,
+                                                   a->resources.pci.hdev);
+  if (!a->resources.pci.irq) {
+    DBG_ERR(("A: invalid irq"));
+    return (-1);
+  }
+
+  /*
+    Get length of I/O bar 2 - it is different by older
+    EEPROM version
+  */
+  Bus  = a->resources.pci.bus;
+  Slot = a->resources.pci.func;
+  hdev = a->resources.pci.hdev;
+
+  /*
+    Get plain original values of the BAR2 CDM registers
+  */
+  PCIread (Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev) ;
+  PCIread (Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+  /*
+    Disable device and get BAR2 length
+  */
+  PCIwrite (Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev);
+  PCIwrite (Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
+  PCIread  (Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
+  /*
+    Restore BAR2 and CMD registers
+  */
+  PCIwrite (Bus, Slot, 0x18, &bar2 ,sizeof(bar2), hdev) ;
+  PCIwrite (Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+
+  /*
+    Calculate BAR2 length
+  */
+  bar2_length = (~(bar2_length & ~7)) + 1;
+  DBG_LOG(("BAR[2] length=%lx", bar2_length))
+
+  /*
+    Map and register resources
+  */
+  if (!(a->resources.pci.addr[0] = divasa_remap_pci_bar (a->resources.pci.bar[0],
+                                                         bri_bar_length[0])))
+  {
+    DBG_ERR(("A: BRI, can't map BAR[0]"))
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+
+  sprintf (&a->port_name[0], "BRI %02x:%02x",
+                              a->resources.pci.bus,
+                              a->resources.pci.func);
+
+  if (diva_os_register_io_port (1, a->resources.pci.bar[1],
+                                bri_bar_length[1],
+                                &a->port_name[0])) {
+    DBG_ERR(("A: BRI, can't register BAR[1]"))
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+  a->resources.pci.addr[1]   = (void*)(unsigned long)a->resources.pci.bar[1];
+  a->resources.pci.length[1] = bri_bar_length[1];
+
+  if (diva_os_register_io_port (1, a->resources.pci.bar[2],
+                                bar2_length,
+                                &a->port_name[0])) {
+    DBG_ERR(("A: BRI, can't register BAR[2]"))
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+  a->resources.pci.addr[2]   = (void*)(unsigned long)a->resources.pci.bar[2];
+  a->resources.pci.length[2] = bar2_length;
+
+  /*
+    Get Serial Number
+  */
+  a->xdi_adapter.serialNo = diva_bri_get_serial_number (a);
+
+  /*
+    Register I/O ports with correct name now
+  */
+  if (diva_bri_reregister_io (a)) {
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+
+  /*
+    Initialize OS dependent objects
+  */
+  if (diva_os_initialize_spin_lock (&a->xdi_adapter.isr_spin_lock, "isr")) {
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+  if (diva_os_initialize_spin_lock (&a->xdi_adapter.data_spin_lock, "data")) {
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+
+  strcpy (a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasbrid");
+
+  if (diva_os_initialize_soft_isr (&a->xdi_adapter.req_soft_isr,
+                                   DIDpcRoutine, &a->xdi_adapter)) {
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+  /*
+    Do not initialize second DPC - only one thread will be created
+  */
+  a->xdi_adapter.isr_soft_isr.object = a->xdi_adapter.req_soft_isr.object;
+
+  /*
+    Create entity table
+  */
+  a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
+  a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
+  a->xdi_adapter.e_tbl = diva_os_malloc (0, a->xdi_adapter.e_max * sizeof(E_INFO));
+  if (!a->xdi_adapter.e_tbl) {
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+  memset (a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO));
+
+  /*
+    Set up interface
+  */
+  a->xdi_adapter.a.io = &a->xdi_adapter;
+  a->xdi_adapter.DIRequest = request;
+  a->interface.cleanup_adapter_proc = diva_bri_cleanup_adapter;
+  a->interface.cmd_proc = diva_bri_cmd_card_proc;
+
+  a->xdi_adapter.cfg = a->resources.pci.addr[1];
+  a->xdi_adapter.Address = a->resources.pci.addr[2];
+
+  a->xdi_adapter.reset = a->xdi_adapter.cfg;
+  a->xdi_adapter.port = a->xdi_adapter.Address;
+
+  a->xdi_adapter.ctlReg = a->xdi_adapter.port + M_PCI_RESET ;
+  a->xdi_adapter.reset += 0x4C ;	/* PLX 9050 !! */
+  outpp (a->xdi_adapter.reset, 0x41) ;
+
+  prepare_maestra_functions (&a->xdi_adapter);
+
+  a->dsp_mask = 0x00000003;
+
+  /*
+    Set IRQ handler
+  */
+  a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
+  sprintf (a->xdi_adapter.irq_info.irq_name, "DIVA BRI %ld",
+                                            (long)a->xdi_adapter.serialNo);
+  if (diva_os_register_irq (a, a->xdi_adapter.irq_info.irq_nr,
+                            a->xdi_adapter.irq_info.irq_name)) {
+    diva_bri_cleanup_adapter (a);
+    return (-1);
+  }
+  a->xdi_adapter.irq_info.registered = 1;
+
+  diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
+                                      a->resources.pci.irq,
+                                      a->xdi_adapter.serialNo);
+
+  return (0);
+}
+
+
+static int
+diva_bri_cleanup_adapter (diva_os_xdi_adapter_t* a)
+{
+  int i;
+
+  if (a->xdi_adapter.Initialized) {
+    diva_bri_stop_adapter (a);
+  }
+
+  /*
+    Remove ISR Handler
+  */
+  if (a->xdi_adapter.irq_info.registered) {
+    diva_os_remove_irq (a, a->xdi_adapter.irq_info.irq_nr);
+  }
+  a->xdi_adapter.irq_info.registered = 0;
+
+  if (a->resources.pci.addr[0] && a->resources.pci.bar[0]) {
+    divasa_unmap_pci_bar (a->resources.pci.addr[0]);
+    a->resources.pci.addr[0] = 0;
+    a->resources.pci.bar [0] = 0;
+  }
+
+  for (i = 1; i < 3; i++) {
+    if (a->resources.pci.addr[i] && a->resources.pci.bar[i]) {
+      diva_os_register_io_port (0, a->resources.pci.bar[i],
+                                   a->resources.pci.length[i],
+                                   &a->port_name[0]);
+      a->resources.pci.addr[i] = 0;
+      a->resources.pci.bar [i] = 0;
+    }
+  }
+
+  /*
+    Free OS objects
+  */
+  diva_os_cancel_soft_isr (&a->xdi_adapter.req_soft_isr);
+  diva_os_cancel_soft_isr (&a->xdi_adapter.isr_soft_isr);
+
+  diva_os_remove_soft_isr (&a->xdi_adapter.req_soft_isr);
+  a->xdi_adapter.isr_soft_isr.object = 0;
+
+  diva_os_destroy_spin_lock (&a->xdi_adapter.isr_spin_lock, "rm");
+  diva_os_destroy_spin_lock (&a->xdi_adapter.data_spin_lock, "rm");
+
+  /*
+    Free memory
+  */
+  if (a->xdi_adapter.e_tbl) {
+    diva_os_free (0, a->xdi_adapter.e_tbl);
+    a->xdi_adapter.e_tbl = 0;
+  }  
+
+  return (0);
+}
+
+void
+diva_os_prepare_maestra_functions (PISDN_ADAPTER IoAdapter)
+{
+}
+
+/*
+**  Get serial number
+*/
+static dword
+diva_bri_get_serial_number (diva_os_xdi_adapter_t* a)
+{
+  dword serNo = 0;
+  byte*	confIO;
+  word  serHi, serLo, *confMem;
+
+  confIO = (byte*)a->resources.pci.addr[1];
+  serHi  = (word)(inppw(&confIO[0x22]) & 0x0FFF) ;
+  serLo  = (word)(inppw(&confIO[0x26]) & 0x0FFF) ;
+  serNo  = ((dword)serHi << 16) | (dword)serLo ;
+
+  if ((serNo == 0) || (serNo == 0xFFFFFFFF)) {
+    DBG_FTL(("W: BRI use BAR[0] to get card serial number"))
+
+    confMem = (word*)a->resources.pci.addr[0];
+    serHi   = (word)(READ_WORD(&confMem[0x11]) & 0x0FFF) ;
+    serLo   = (word)(READ_WORD(&confMem[0x13]) & 0x0FFF) ;
+    serNo   = (((dword)serHi) << 16) | ((dword)serLo) ;
+  }
+
+  DBG_LOG(("Serial Number=%ld", serNo))
+
+  return (serNo);
+}
+
+/*
+**  Unregister I/O and register it with new name,
+**  based on Serial Number
+*/
+static int
+diva_bri_reregister_io (diva_os_xdi_adapter_t* a)
+{
+  int i;
+
+  for (i = 1; i < 3; i++) {
+    diva_os_register_io_port (0, a->resources.pci.bar[i],
+                                 a->resources.pci.length[i],
+                                &a->port_name[0]);
+    a->resources.pci.addr[i] = 0;
+  }
+
+  sprintf (a->port_name, "DIVA BRI %ld", (long)a->xdi_adapter.serialNo);
+
+  for (i = 1; i < 3; i++) {
+    if (diva_os_register_io_port (1, a->resources.pci.bar[i],
+                                     a->resources.pci.length[i],
+                                    &a->port_name[0])) {
+      DBG_ERR(("A: failed to reregister BAR[%d]", i))
+      return (-1);
+    }
+    a->resources.pci.addr[i] = (void*)(unsigned long)a->resources.pci.bar[i];
+  }
+
+  return (0);
+}
+
+/*
+**  Process command from user mode
+*/
+static int
+diva_bri_cmd_card_proc (struct _diva_os_xdi_adapter* a,
+                        diva_xdi_um_cfg_cmd_t* cmd,
+                        int length)
+{
+  int ret = -1;
+
+  if (cmd->adapter != a->controller) {
+    DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
+            cmd->adapter, a->controller))
+    return (-1);
+  }
+
+  switch (cmd->command) {
+    case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        *(dword*)a->xdi_mbox.data = (dword)a->CardOrdinal;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        *(dword*)a->xdi_mbox.data = (dword)a->xdi_adapter.serialNo;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
+      a->xdi_mbox.data_length = sizeof(dword)*9;
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        int i;
+        dword* data = (dword*)a->xdi_mbox.data;
+
+        for (i = 0; i < 8; i++) {
+          *data++ = a->resources.pci.bar[i];
+        }
+        *data++ = (dword)a->resources.pci.irq;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_CARD_STATE:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        dword* data = (dword*)a->xdi_mbox.data;
+        if (!a->xdi_adapter.port) {
+          *data = 3;
+        } else if (a->xdi_adapter.trapped) {
+          *data = 2;
+        } else if (a->xdi_adapter.Initialized) {
+          *data = 1;
+        } else {
+          *data = 0;
+        }
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_RESET_ADAPTER:
+      ret = diva_bri_reset_adapter (&a->xdi_adapter);
+      break;
+
+    case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
+      ret = diva_bri_write_sdram_block (&a->xdi_adapter,
+                                        cmd->command_data.write_sdram.offset,
+                                        (byte*)&cmd[1],
+                                        cmd->command_data.write_sdram.length);
+      break;
+
+    case DIVA_XDI_UM_CMD_START_ADAPTER:
+      ret = diva_bri_start_adapter (&a->xdi_adapter,
+                                    cmd->command_data.start.offset,
+                                    cmd->command_data.start.features);
+      break;
+
+    case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
+      a->xdi_adapter.features = cmd->command_data.features.features;
+      a->xdi_adapter.a.protocol_capabilities = a->xdi_adapter.features;
+      DBG_TRC(("Set raw protocol features (%08x)", a->xdi_adapter.features))
+      ret = 0;
+      break;
+
+    case DIVA_XDI_UM_CMD_STOP_ADAPTER:
+      ret = diva_bri_stop_adapter (a);
+      break;
+
+    case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
+      ret = diva_card_read_xlog (a);
+      break;
+
+    default:
+      DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller, cmd->command))
+  }
+
+  return (ret);
+}
+
+static int
+diva_bri_reset_adapter (PISDN_ADAPTER IoAdapter)
+{
+  byte*  addrHi, *addrLo, *ioaddr ;
+  dword i;
+
+  if (!IoAdapter->port) {
+    return (-1);
+  }
+  if (IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) can't reset BRI adapter - please stop first",
+              IoAdapter->ANum))
+    return (-1);
+  }
+  addrHi = IoAdapter->port + ((IoAdapter->Properties.Bus==BUS_PCI) ? M_PCI_ADDRH : ADDRH);
+  addrLo = IoAdapter->port + ADDR ;
+  ioaddr = IoAdapter->port + DATA ;
+  (*(IoAdapter->rstFnc))(IoAdapter);
+  diva_os_wait(100);
+  /*
+    recover
+  */
+  outpp  (addrHi, (byte) 0) ;
+  outppw (addrLo, (word) 0) ;
+  outppw (ioaddr, (word) 0) ;
+  /*
+    clear shared memory
+  */
+  outpp  (addrHi, (byte)((IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                          BRI_SHARED_RAM_SIZE) >> 16)) ;
+  outppw (addrLo, 0) ;
+  for ( i = 0; i < 0x8000; outppw (ioaddr, 0), ++i);
+  diva_os_wait (100) ;
+
+  /*
+    clear signature
+  */
+  outpp  (addrHi, (byte)((IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                          BRI_SHARED_RAM_SIZE) >> 16)) ;
+  outppw (addrLo, 0x1e) ;
+  outpp (ioaddr, 0) ;
+  outpp (ioaddr, 0) ;
+
+  outpp  (addrHi, (byte) 0) ;
+  outppw (addrLo, (word) 0) ;
+  outppw (ioaddr, (word) 0) ;
+
+  /*
+    Forget all outstanding entities
+  */
+  IoAdapter->e_count =  0;
+  if (IoAdapter->e_tbl) {
+    memset (IoAdapter->e_tbl, 0x00, IoAdapter->e_max * sizeof(E_INFO));
+  }
+  IoAdapter->head = 0;
+  IoAdapter->tail = 0;
+  IoAdapter->assign = 0;
+  IoAdapter->trapped = 0;
+
+  memset (&IoAdapter->a.IdTable[0],              0x00, sizeof(IoAdapter->a.IdTable));
+  memset (&IoAdapter->a.IdTypeTable[0],          0x00, sizeof(IoAdapter->a.IdTypeTable));
+  memset (&IoAdapter->a.FlowControlIdTable[0],   0x00, sizeof(IoAdapter->a.FlowControlIdTable));
+  memset (&IoAdapter->a.FlowControlSkipTable[0], 0x00, sizeof(IoAdapter->a.FlowControlSkipTable));
+  memset (&IoAdapter->a.misc_flags_table[0],     0x00, sizeof(IoAdapter->a.misc_flags_table));
+  memset (&IoAdapter->a.rx_stream[0],            0x00, sizeof(IoAdapter->a.rx_stream));
+  memset (&IoAdapter->a.tx_stream[0],            0x00, sizeof(IoAdapter->a.tx_stream));
+  memset (&IoAdapter->a.tx_pos[0],               0x00, sizeof(IoAdapter->a.tx_pos));
+  memset (&IoAdapter->a.rx_pos[0],               0x00, sizeof(IoAdapter->a.rx_pos));
+
+  return (0);
+}
+
+static int
+diva_bri_write_sdram_block (PISDN_ADAPTER IoAdapter,
+                            dword address,
+                            const byte* data,
+                            dword length)
+{
+  byte*  addrHi, *addrLo, *ioaddr;
+
+  if (!IoAdapter->port) {
+    return (-1);
+  }
+
+  addrHi = IoAdapter->port + ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH) ;
+  addrLo = IoAdapter->port + ADDR ;
+  ioaddr = IoAdapter->port + DATA ;
+
+  while (length--) {
+    outpp  (addrHi, (word)(address >> 16)) ;
+    outppw (addrLo, (word)(address & 0x0000ffff));
+    outpp (ioaddr, *data++);
+    address++;
+  }
+
+  return (0);
+}
+
+static int
+diva_bri_start_adapter (PISDN_ADAPTER IoAdapter,
+                        dword start_address,
+                        dword features)
+{
+  dword i, test;
+  byte*  addrHi, *addrLo, *ioaddr;
+  int started = 0;
+  ADAPTER *a = &IoAdapter->a ;
+
+  if (IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) bri_start_adapter, adapter already running",
+              IoAdapter->ANum))
+    return (-1);
+  }
+  if (!IoAdapter->port) {
+    DBG_ERR(("A: A(%d) bri_start_adapter, adapter not mapped",
+              IoAdapter->ANum))
+    return (-1);
+  }
+
+  sprintf (IoAdapter->Name, "A(%d)", (int)IoAdapter->ANum);
+  DBG_LOG(("A(%d) start BRI", IoAdapter->ANum))
+
+  addrHi =   IoAdapter->port + ((IoAdapter->Properties.Bus==BUS_PCI) ? M_PCI_ADDRH : ADDRH);
+  addrLo = IoAdapter->port + ADDR ;
+  ioaddr = IoAdapter->port + DATA ;
+
+  outpp  (addrHi, (byte)((IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                          BRI_SHARED_RAM_SIZE) >> 16)) ;
+  outppw (addrLo, 0x1e) ;
+  outppw (ioaddr, 0x00) ;
+
+  /*
+    start the protocol code
+  */
+  outpp (IoAdapter->ctlReg, 0x08) ;
+
+  /*
+    wait for signature (max. 3 seconds)
+  */
+  for (i = 0; i < 300; ++i) {
+    diva_os_wait (10);
+    outpp (addrHi, (byte)((IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                           BRI_SHARED_RAM_SIZE) >> 16)) ;
+    outppw (addrLo, 0x1e) ;
+    test = (dword)inppw (ioaddr) ;
+    if (test == 0x4447) {
+      DBG_LOG(("Protocol startup time %d.%02d seconds", (i / 100), (i % 100)))
+      started = 1;
+      break;
+    }
+  }
+
+  if (!started) {
+    DBG_FTL(("A: A(%d) %s: Adapter selftest failed 0x%04X",
+              IoAdapter->ANum, IoAdapter->Properties.Name, test))
+    (*(IoAdapter->trapFnc))(IoAdapter);
+    return (-1);
+  }
+
+  IoAdapter->Initialized = 1;
+
+  /*
+    Check Interrupt
+  */
+  IoAdapter->IrqCount = 0 ;
+  a->ReadyInt = 1 ;
+
+  if (IoAdapter->reset) {
+    outpp (IoAdapter->reset, 0x41) ;
+  }
+
+  a->ram_out (a, &PR_RAM->ReadyInt, 1);
+  for (i = 0; ((!IoAdapter->IrqCount) && (i < 100)); i++) {
+    diva_os_wait (10);
+  }
+  if (!IoAdapter->IrqCount) {
+    DBG_ERR(("A: A(%d) interrupt test failed", IoAdapter->ANum))
+    IoAdapter->Initialized = 0;
+    IoAdapter->stop(IoAdapter);
+    return (-1);
+  }
+
+  IoAdapter->Properties.Features = (word)features;
+  diva_xdi_display_adapter_features (IoAdapter->ANum);
+  DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum))
+  /*
+    Register with DIDD
+  */
+  diva_xdi_didd_register_adapter (IoAdapter->ANum);
+
+  return (0);
+}
+
+static void
+diva_bri_clear_interrupts (diva_os_xdi_adapter_t* a)
+{
+  PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+
+  /*
+    clear any pending interrupt
+  */
+  IoAdapter->disIrq (IoAdapter) ;
+
+  IoAdapter->tst_irq (&IoAdapter->a) ;
+  IoAdapter->clr_irq (&IoAdapter->a) ;
+  IoAdapter->tst_irq (&IoAdapter->a) ;
+
+  /*
+    kill pending dpcs
+  */
+  diva_os_cancel_soft_isr (&IoAdapter->req_soft_isr);
+  diva_os_cancel_soft_isr (&IoAdapter->isr_soft_isr);
+}
+
+/*
+**  Stop card
+*/
+static int
+diva_bri_stop_adapter (diva_os_xdi_adapter_t* a)
+{
+  PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+  int i = 100;
+
+  if (!IoAdapter->port) {
+    return (-1);
+  }
+  if (!IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) can't stop BRI adapter - not running",
+              IoAdapter->ANum))
+    return (-1); /* nothing to stop */
+  }
+  IoAdapter->Initialized = 0;
+
+  /*
+    Disconnect Adapter from DIDD
+  */
+  diva_xdi_didd_remove_adapter (IoAdapter->ANum);
+
+  /*
+    Stop interrupts
+  */
+  a->clear_interrupts_proc = diva_bri_clear_interrupts;
+  IoAdapter->a.ReadyInt = 1 ;
+  IoAdapter->a.ram_inc (&IoAdapter->a, &PR_RAM->ReadyInt);
+  do {
+    diva_os_sleep (10);
+  } while (i-- && a->clear_interrupts_proc);
+  if (a->clear_interrupts_proc) {
+    diva_bri_clear_interrupts (a);
+    a->clear_interrupts_proc = 0;
+    DBG_ERR(("A: A(%d) no final interrupt from BRI adapter", IoAdapter->ANum))
+  }
+  IoAdapter->a.ReadyInt = 0 ;
+
+  /*
+    Stop and reset adapter
+  */
+  IoAdapter->stop (IoAdapter) ;
+
+  return (0);
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/os_bri.h b/drivers/isdn/hardware/eicon/os_bri.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/os_bri.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,8 @@
+/* $Id: os_bri.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_OS_BRI_REV_1_H__
+#define __DIVA_OS_BRI_REV_1_H__
+
+int diva_bri_init_card (diva_os_xdi_adapter_t* a);
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/os_capi.h b/drivers/isdn/hardware/eicon/os_capi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/os_capi.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,21 @@
+/* $Id: os_capi.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface OS include files 
+ * 
+ * Copyright 2000-2002 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2002 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef __OS_CAPI_H__ 
+#define __OS_CAPI_H__
+
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+#include <linux/isdn/capiutil.h>
+#include <linux/isdn/capilli.h>
+
+#endif /* __OS_CAPI_H__ */
diff -Nru a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/os_pri.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,945 @@
+/* $Id: os_pri.c,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "dlist.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "dsp_defs.h"
+#include "di.h"
+#include "io.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "os_pri.h"
+#include "diva_pci.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "dsp_tst.h"
+#include "diva_dma.h"
+
+/* --------------------------------------------------------------------------
+   OS Dependent part of XDI driver for DIVA PRI Adapter
+
+   DSP detection/validation by Anthony Booth (Eicon Networks, www.eicon.com)
+-------------------------------------------------------------------------- */ 
+
+#define DIVA_PRI_NO_PCI_BIOS_WORKAROUND 1
+
+extern int diva_card_read_xlog (diva_os_xdi_adapter_t* a);
+
+/*
+**  IMPORTS
+*/
+extern void prepare_pri_functions  (PISDN_ADAPTER IoAdapter);
+extern void prepare_pri2_functions (PISDN_ADAPTER IoAdapter);
+extern void diva_xdi_display_adapter_features (int card);
+
+static int diva_pri_cleanup_adapter (diva_os_xdi_adapter_t* a);
+static int diva_pri_cmd_card_proc (struct _diva_os_xdi_adapter* a,
+                                   diva_xdi_um_cfg_cmd_t* cmd,
+                                   int length);
+static int pri_get_serial_number (diva_os_xdi_adapter_t* a);
+static int diva_pri_stop_adapter (diva_os_xdi_adapter_t* a);
+static dword diva_pri_detect_dsps (diva_os_xdi_adapter_t* a);
+
+/*
+**  Check card revision
+*/
+static int
+pri_is_rev_2_card (int card_ordinal)
+{
+  switch (card_ordinal) {
+    case CARDTYPE_DIVASRV_P_30M_V2_PCI:
+    case CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI:
+      return (1);
+  }
+  return (0);
+}
+
+/*
+**  BAR0 - SDRAM, MP_MEMORY_SIZE, MP2_MEMORY_SIZE by Rev.2
+**  BAR1 - DEVICES,				0x1000
+**  BAR2 - CONTROL (REG), 0x2000
+**  BAR3 - FLASH (REG),		0x8000
+**  BAR4 - CONFIG (CFG),	0x1000
+*/
+int
+diva_pri_init_card (diva_os_xdi_adapter_t* a)
+{
+  int bar = 0;
+  int pri_rev_2;
+  unsigned long bar_length[5] = {
+    MP_MEMORY_SIZE,
+    0x1000,
+    0x2000,
+    0x8000,
+    0x1000
+  };
+
+  pri_rev_2 = pri_is_rev_2_card (a->CardOrdinal);
+
+  if (pri_rev_2) {
+    bar_length[0] = MP2_MEMORY_SIZE;
+  }
+  /*
+    Set properties
+  */
+  a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+  DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name))
+
+  /*
+    First initialization step: get and check hardware resoures.
+    Do not map resources and do not acecess card at this step
+  */
+
+  for (bar = 0; bar < 5; bar++) {
+    a->resources.pci.bar[bar] = divasa_get_pci_bar (a->resources.pci.bus,
+                                                    a->resources.pci.func,
+                                                    bar,
+                                                    a->resources.pci.hdev);
+    if (!a->resources.pci.bar[bar] ||
+        (a->resources.pci.bar[bar] == 0xFFFFFFF0)) {
+      DBG_ERR(("A: invalid bar[%d]=%08x", bar, a->resources.pci.bar[bar]))
+      return (-1);
+    }
+  }
+  a->resources.pci.irq = (byte)divasa_get_pci_irq (a->resources.pci.bus,
+                                                   a->resources.pci.func,
+                                                   a->resources.pci.hdev);
+  if (!a->resources.pci.irq) {
+    DBG_ERR(("A: invalid irq"));
+    return (-1);
+  }
+
+  /*
+    Map all BAR's
+  */
+  for (bar = 0; bar < 5; bar++) {
+    a->resources.pci.addr[bar] = divasa_remap_pci_bar (a->resources.pci.bar[bar], bar_length[bar]);
+    if (!a->resources.pci.addr[bar]) {
+      DBG_ERR(("A: A(%d), can't map bar[%d]", a->controller, bar))
+      diva_pri_cleanup_adapter (a);
+      return (-1);
+    }
+  }
+
+  /*
+    Get Serial Number of this adapter
+  */
+  if (pri_get_serial_number (a)) {
+    dword serNo;
+    serNo  = a->resources.pci.bar[1] & 0xffff0000;
+    serNo |= ((dword)a->resources.pci.bus) << 8;
+    serNo += (a->resources.pci.func + a->controller + 1);
+    a->xdi_adapter.serialNo = serNo & ~0xFF000000;
+    DBG_ERR(("A: A(%d) can't get Serial Number, generated serNo=%ld",
+              a->controller, a->xdi_adapter.serialNo))
+  }
+
+
+  /*
+    Initialize os objects
+  */
+  if (diva_os_initialize_spin_lock (&a->xdi_adapter.isr_spin_lock, "isr")) {
+    diva_pri_cleanup_adapter (a);
+    return (-1);
+  }
+  if (diva_os_initialize_spin_lock (&a->xdi_adapter.data_spin_lock, "data")) {
+    diva_pri_cleanup_adapter (a);
+    return (-1);
+  }
+
+  strcpy (a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasprid");
+
+  if (diva_os_initialize_soft_isr (&a->xdi_adapter.req_soft_isr,
+                                    DIDpcRoutine,
+                                    &a->xdi_adapter)) {
+    diva_pri_cleanup_adapter (a);
+    return (-1);
+  }
+
+  /*
+    Do not initialize second DPC - only one thread will be created
+  */
+  a->xdi_adapter.isr_soft_isr.object = a->xdi_adapter.req_soft_isr.object;
+
+  /*
+    Next step of card initialization:
+    set up all interface pointers
+  */
+  a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
+  a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
+
+  a->xdi_adapter.e_tbl =diva_os_malloc (0, a->xdi_adapter.e_max * sizeof(E_INFO)); 
+  if (!a->xdi_adapter.e_tbl) {
+    diva_pri_cleanup_adapter (a);
+    return (-1);
+  }
+  memset (a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO));
+
+  a->xdi_adapter.a.io = &a->xdi_adapter;
+  a->xdi_adapter.DIRequest = request;
+  a->interface.cleanup_adapter_proc = diva_pri_cleanup_adapter;
+  a->interface.cmd_proc	= diva_pri_cmd_card_proc;
+
+  if (pri_rev_2) {
+    prepare_pri2_functions (&a->xdi_adapter);
+  } else {
+    prepare_pri_functions  (&a->xdi_adapter);
+  }
+
+  /*
+    Set all memory areas
+  */
+  a->xdi_adapter.Address = a->resources.pci.addr[0];
+  a->xdi_adapter.sdram_bar = a->resources.pci.bar [0];
+  a->xdi_adapter.ram = a->resources.pci.addr[0];
+  a->xdi_adapter.ram += MP_SHARED_RAM_OFFSET;
+
+  a->xdi_adapter.reset = a->resources.pci.addr[2];
+  a->xdi_adapter.reset += MP_RESET;
+
+  a->xdi_adapter.prom = (byte*)(unsigned long)a->resources.pci.bar [3];
+
+  a->xdi_adapter.cfg = a->resources.pci.addr[4];
+  a->xdi_adapter.cfg += MP_IRQ_RESET;
+
+  a->dsp_mask = diva_pri_detect_dsps (a);
+
+  /*
+    Allocate DMA map
+    */
+  if (pri_rev_2) {
+    diva_init_dma_map (a->resources.pci.hdev,
+                       (struct _diva_dma_map_entry**)&a->xdi_adapter.dma_map,
+                       32);
+  }
+
+  /*
+    Set IRQ handler
+  */
+  a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
+  sprintf (a->xdi_adapter.irq_info.irq_name,
+            "DIVA PRI %ld", 
+            (long)a->xdi_adapter.serialNo);
+
+  if (diva_os_register_irq (a, a->xdi_adapter.irq_info.irq_nr,
+                            a->xdi_adapter.irq_info.irq_name)) {
+    diva_pri_cleanup_adapter (a);
+    return (-1);
+  }
+  a->xdi_adapter.irq_info.registered = 1;
+
+  diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
+                                      a->resources.pci.irq,
+                                      a->xdi_adapter.serialNo);
+
+  return (0);
+}
+
+static int
+diva_pri_cleanup_adapter (diva_os_xdi_adapter_t* a)
+{
+  int bar = 0;
+
+  /*
+    Stop Adapter if adapter is running
+  */
+  if (a->xdi_adapter.Initialized) {
+    diva_pri_stop_adapter (a);
+  }
+
+  /*
+    Remove ISR Handler
+  */
+  if (a->xdi_adapter.irq_info.registered) {
+    diva_os_remove_irq (a, a->xdi_adapter.irq_info.irq_nr);
+  }
+  a->xdi_adapter.irq_info.registered = 0;
+
+  /*
+    Step 1: unmap all BAR's, if any was mapped
+  */
+  for (bar = 0; bar < 5; bar++) {
+    if (a->resources.pci.bar[bar] && a->resources.pci.addr[bar]) {
+      divasa_unmap_pci_bar (a->resources.pci.addr[bar]);
+      a->resources.pci.bar[bar]  = 0;
+      a->resources.pci.addr[bar] = 0;
+    }
+  }
+
+  /*
+    Free OS objects
+  */
+  diva_os_cancel_soft_isr (&a->xdi_adapter.isr_soft_isr);
+  diva_os_cancel_soft_isr (&a->xdi_adapter.req_soft_isr);
+
+  diva_os_remove_soft_isr (&a->xdi_adapter.req_soft_isr);
+  a->xdi_adapter.isr_soft_isr.object = 0;
+
+  diva_os_destroy_spin_lock (&a->xdi_adapter.isr_spin_lock, "rm");
+  diva_os_destroy_spin_lock (&a->xdi_adapter.data_spin_lock, "rm");
+
+  /*
+    Free memory accupied by XDI adapter
+  */
+  if (a->xdi_adapter.e_tbl) {
+    diva_os_free (0, a->xdi_adapter.e_tbl);
+    a->xdi_adapter.e_tbl = 0;
+  }
+  a->xdi_adapter.Channels = 0;
+  a->xdi_adapter.e_max = 0;
+
+
+  /*
+    Free adapter DMA map
+    */
+  diva_free_dma_map (a->resources.pci.hdev,
+                     (struct _diva_dma_map_entry*)a->xdi_adapter.dma_map);
+  a->xdi_adapter.dma_map = 0;
+
+
+  /*
+    Detach this adapter from debug driver
+  */
+
+  return (0);
+}
+
+/*
+**  Activate On Board Boot Loader
+*/
+static int
+diva_pri_reset_adapter (PISDN_ADAPTER IoAdapter)
+{
+  dword  i;
+  struct mp_load *boot = (struct mp_load *)IoAdapter->Address;
+
+  if (!IoAdapter->Address || !IoAdapter->reset) {
+    return (-1);
+  }
+  if (IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) can't reset PRI adapter - please stop first",
+                IoAdapter->ANum))
+    return (-1);
+  }
+
+	WRITE_DWORD(&boot->err, 0);
+  IoAdapter->rstFnc (IoAdapter) ;
+  diva_os_wait (10) ;
+  i = READ_DWORD(&boot->live);
+  diva_os_wait (10) ;
+  if (i == READ_DWORD(&boot->live)) {
+    DBG_ERR(("A: A(%d) CPU on PRI %ld is not alive!",
+              IoAdapter->ANum, IoAdapter->serialNo))
+    return (-1);
+  }
+  if (READ_DWORD(&boot->err)) {
+    DBG_ERR(("A: A(%d) PRI %ld Board Selftest failed, error=%08lx",
+              IoAdapter->ANum, IoAdapter->serialNo, READ_DWORD(&boot->err)))
+    return (-1);
+  }
+
+  /*
+    Forget all outstanding entities
+  */
+  IoAdapter->e_count =  0;
+  if (IoAdapter->e_tbl) {
+    memset (IoAdapter->e_tbl, 0x00, IoAdapter->e_max * sizeof(E_INFO));
+  }
+  IoAdapter->head = 0;
+  IoAdapter->tail = 0;
+  IoAdapter->assign = 0;
+  IoAdapter->trapped = 0;
+
+  memset (&IoAdapter->a.IdTable[0],              0x00, sizeof(IoAdapter->a.IdTable));
+  memset (&IoAdapter->a.IdTypeTable[0],          0x00, sizeof(IoAdapter->a.IdTypeTable));
+  memset (&IoAdapter->a.FlowControlIdTable[0],   0x00, sizeof(IoAdapter->a.FlowControlIdTable));
+  memset (&IoAdapter->a.FlowControlSkipTable[0], 0x00, sizeof(IoAdapter->a.FlowControlSkipTable));
+  memset (&IoAdapter->a.misc_flags_table[0],     0x00, sizeof(IoAdapter->a.misc_flags_table));
+  memset (&IoAdapter->a.rx_stream[0],            0x00, sizeof(IoAdapter->a.rx_stream));
+  memset (&IoAdapter->a.tx_stream[0],            0x00, sizeof(IoAdapter->a.tx_stream));
+  memset (&IoAdapter->a.tx_pos[0],               0x00, sizeof(IoAdapter->a.tx_pos));
+  memset (&IoAdapter->a.rx_pos[0],               0x00, sizeof(IoAdapter->a.rx_pos));
+
+  return (0);
+}
+
+static int
+diva_pri_write_sdram_block (PISDN_ADAPTER IoAdapter,
+                            dword address,
+                            const byte* data,
+                            dword length,
+                            dword limit)
+{
+  byte* mem = IoAdapter->Address;
+
+  if (((address + length) >= limit) || !mem) {
+    DBG_ERR(("A: A(%d) write PRI address=0x%08lx",
+               IoAdapter->ANum, address+length))
+    return (-1);
+  }
+  mem += address;
+
+  while (length--) {
+    *mem++ = *data++;
+  }
+
+  return (0);
+}
+
+static int
+diva_pri_start_adapter (PISDN_ADAPTER IoAdapter,
+                        dword start_address,
+                        dword features)
+{
+  dword i;
+  int started = 0;
+  struct mp_load *boot = (struct mp_load *)IoAdapter->Address;
+  ADAPTER *a = &IoAdapter->a ;
+
+  if (IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) pri_start_adapter, adapter already running",
+              IoAdapter->ANum))
+    return (-1);
+  }
+  if (!boot) {
+    DBG_ERR(("A: PRI %ld can't start, adapter not mapped",
+              IoAdapter->serialNo))
+    return (-1);
+  }
+
+  sprintf (IoAdapter->Name, "A(%d)", (int)IoAdapter->ANum);
+  DBG_LOG(("A(%d) start PRI at 0x%08lx", IoAdapter->ANum, start_address))
+
+  WRITE_DWORD(&boot->addr, start_address);
+  WRITE_DWORD(&boot->cmd, 3);
+
+  for (i = 0; i < 300; ++i) {
+    diva_os_wait (10);
+    if ((READ_DWORD(&boot->signature) >> 16) == 0x4447) {
+      DBG_LOG(("A(%d) Protocol startup time %d.%02d seconds",
+                IoAdapter->ANum, (i / 100), (i % 100)))
+      started = 1;
+      break;
+    }
+  }
+
+  if (!started) {
+    dword TrapId = READ_DWORD(&IoAdapter->Address[0x80]);
+    dword debug  = READ_DWORD(&IoAdapter->Address[0x1c]);
+    DBG_ERR(("A(%d) Adapter start failed 0x%08lx, TrapId=%08lx, debug=%08lx",
+              IoAdapter->ANum, READ_DWORD(&boot->signature), TrapId, debug))
+    if (IoAdapter->trapFnc) {
+      (*(IoAdapter->trapFnc))(IoAdapter);
+    }
+    IoAdapter->stop(IoAdapter);
+    return (-1);
+  }
+
+  IoAdapter->Initialized = TRUE;
+
+  /*
+    Check Interrupt
+  */
+  IoAdapter->IrqCount = 0;
+  WRITE_DWORD(((dword volatile *)IoAdapter->cfg), (dword)~0x03E00000) ;
+  a->ReadyInt = 1 ;
+  a->ram_out (a, &PR_RAM->ReadyInt, 1) ;
+
+  for (i = 100; !IoAdapter->IrqCount && (i-- > 0); diva_os_wait (10));
+
+  if (!IoAdapter->IrqCount) {
+    DBG_ERR(("A: A(%d) interrupt test failed", IoAdapter->ANum))
+    IoAdapter->Initialized = FALSE;
+    IoAdapter->stop(IoAdapter);
+    return (-1);
+  }
+
+  IoAdapter->Properties.Features = (word)features;
+
+  diva_xdi_display_adapter_features (IoAdapter->ANum);
+
+  DBG_LOG(("A(%d) PRI adapter successfull started", IoAdapter->ANum))
+  /*
+    Register with DIDD
+  */
+  diva_xdi_didd_register_adapter (IoAdapter->ANum);
+
+  return (0);
+}
+
+static void
+diva_pri_clear_interrupts (diva_os_xdi_adapter_t* a)
+{
+  PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+
+  /*
+    clear any pending interrupt
+  */
+  IoAdapter->disIrq (IoAdapter) ;
+
+  IoAdapter->tst_irq (&IoAdapter->a) ;
+  IoAdapter->clr_irq (&IoAdapter->a) ;
+  IoAdapter->tst_irq (&IoAdapter->a) ;
+
+  /*
+    kill pending dpcs
+  */
+  diva_os_cancel_soft_isr (&IoAdapter->req_soft_isr);
+  diva_os_cancel_soft_isr (&IoAdapter->isr_soft_isr);
+}
+
+/*
+**  Stop Adapter, but do not unmap/unregister - adapter
+**  will be restarted later
+*/
+static int
+diva_pri_stop_adapter (diva_os_xdi_adapter_t* a)
+{
+  PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+  int i = 100;
+
+  if (!IoAdapter->ram) {
+    return (-1);
+  }
+  if (!IoAdapter->Initialized) {
+    DBG_ERR(("A: A(%d) can't stop PRI adapter - not running",
+              IoAdapter->ANum))
+    return (-1); /* nothing to stop */
+  }
+  IoAdapter->Initialized = 0;
+
+  /*
+    Disconnect Adapter from DIDD
+  */
+  diva_xdi_didd_remove_adapter (IoAdapter->ANum);
+
+  /*
+    Stop interrupts
+  */
+  a->clear_interrupts_proc = diva_pri_clear_interrupts;
+  IoAdapter->a.ReadyInt = 1;
+  IoAdapter->a.ram_inc (&IoAdapter->a, &PR_RAM->ReadyInt) ;
+  do {
+    diva_os_sleep (10);
+  } while (i-- && a->clear_interrupts_proc);
+  if (a->clear_interrupts_proc) {
+    diva_pri_clear_interrupts (a);
+    a->clear_interrupts_proc = 0;
+    DBG_ERR(("A: A(%d) no final interrupt from PRI adapter", IoAdapter->ANum))
+  }
+  IoAdapter->a.ReadyInt = 0;
+
+  /*
+    Stop and reset adapter
+  */
+  IoAdapter->stop (IoAdapter) ;
+
+  return (0);
+}
+
+/*
+**  Process commands form configuration/download framework and from
+**  user mode
+**
+**  return 0 on success
+*/
+static int
+diva_pri_cmd_card_proc (struct _diva_os_xdi_adapter* a,
+                        diva_xdi_um_cfg_cmd_t* cmd,
+                        int length)
+{
+  int ret = -1;
+
+  if (cmd->adapter != a->controller) {
+    DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
+              cmd->adapter, a->controller))
+    return (-1);
+  }
+
+  switch (cmd->command) {
+    case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        *(dword*)a->xdi_mbox.data = (dword)a->CardOrdinal;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        *(dword*)a->xdi_mbox.data = (dword)a->xdi_adapter.serialNo;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
+      a->xdi_mbox.data_length = sizeof(dword)*9;
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        int i;
+        dword* data = (dword*)a->xdi_mbox.data;
+
+        for (i = 0; i < 8; i++) {
+          *data++ = a->resources.pci.bar[i];
+        }
+        *data++ = (dword)a->resources.pci.irq;
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_RESET_ADAPTER:
+      ret = diva_pri_reset_adapter (&a->xdi_adapter);
+      break;
+
+    case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
+      ret = diva_pri_write_sdram_block (&a->xdi_adapter,
+                                        cmd->command_data.write_sdram.offset,
+                                        (byte*)&cmd[1],
+                                        cmd->command_data.write_sdram.length,
+                                        pri_is_rev_2_card (a->CardOrdinal) ? 
+                                        MP2_MEMORY_SIZE : MP_MEMORY_SIZE);
+      break;
+
+    case DIVA_XDI_UM_CMD_STOP_ADAPTER:
+      ret = diva_pri_stop_adapter (a);
+      break;
+
+    case DIVA_XDI_UM_CMD_START_ADAPTER:
+      ret = diva_pri_start_adapter (&a->xdi_adapter,
+                                    cmd->command_data.start.offset,
+                                    cmd->command_data.start.features);
+      break;
+
+    case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
+      a->xdi_adapter.features = cmd->command_data.features.features;
+      a->xdi_adapter.a.protocol_capabilities = a->xdi_adapter.features;
+      DBG_TRC(("Set raw protocol features (%08x)", a->xdi_adapter.features))
+      ret = 0;
+      break;
+
+    case DIVA_XDI_UM_CMD_GET_CARD_STATE:
+      a->xdi_mbox.data_length = sizeof(dword);
+      a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+      if (a->xdi_mbox.data) {
+        dword* data = (dword*)a->xdi_mbox.data;
+        if (!a->xdi_adapter.ram || !a->xdi_adapter.reset ||
+            !a->xdi_adapter.cfg) {
+          *data = 3;
+        } else if (a->xdi_adapter.trapped) {
+          *data = 2;
+        } else if (a->xdi_adapter.Initialized) {
+          *data = 1;
+        } else {
+          *data = 0;
+        }
+        a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+        ret = 0;
+      }
+      break;
+
+    case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
+      ret = diva_card_read_xlog (a);
+      break;
+
+    case DIVA_XDI_UM_CMD_READ_SDRAM:
+      if (a->xdi_adapter.Address) {
+        if ((a->xdi_mbox.data_length = cmd->command_data.read_sdram.length)) {
+          if ((a->xdi_mbox.data_length+cmd->command_data.read_sdram.offset) < a->xdi_adapter.MemorySize) { 
+            a->xdi_mbox.data = diva_os_malloc (0, a->xdi_mbox.data_length);
+            if (a->xdi_mbox.data) {
+              byte* src = a->xdi_adapter.Address;
+              byte* dst = a->xdi_mbox.data;
+              dword len = a->xdi_mbox.data_length;
+
+              src += cmd->command_data.read_sdram.offset;
+
+              while (len--) {
+                *dst++ = *src++;
+              }
+              a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+              ret = 0;
+            }
+          }
+        }
+      }
+      break;
+
+    default:
+      DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller, cmd->command))
+  }
+
+  return (ret);
+}
+
+/*
+**  Get Serial Number
+*/
+static int
+pri_get_serial_number (diva_os_xdi_adapter_t* a)
+{
+  byte data[64];
+  int i;
+  dword len = sizeof(data);
+  volatile byte* config = (byte*)a->resources.pci.addr[4];
+  volatile byte* flash  = (byte*)a->resources.pci.addr[3];
+
+/*
+ *  First set some GT6401x config registers before accessing the BOOT-ROM
+ */
+  if ( !(config[0xc3c] & 0x08) )
+  {
+    config[0xc3c] |= 0x08 ;  /* Base Address enable register */
+  }
+  config[LOW_BOOTCS_DREG] = 0x00 ;
+  config[HI_BOOTCS_DREG]  = 0xFF ;
+/*
+ *  Read only the last 64 bytes of manufacturing data
+ */
+  memset (data, '\0', len) ;
+  for (i = 0; i < len; i++) { data[i] = flash[0x8000 - len + i]; }
+
+  config[LOW_BOOTCS_DREG] = 0xFC ;	/* Disable FLASH EPROM access */
+  config[HI_BOOTCS_DREG]  = 0xFF ;
+
+  if (memcmp (&data[48], "DIVAserverPR", 12)) {
+#if !defined(DIVA_PRI_NO_PCI_BIOS_WORKAROUND) /* { */
+    word cmd = 0, cmd_org;
+    void* addr;
+    dword addr1, addr3, addr4;
+    byte Bus, Slot;
+    void* hdev;
+    addr4  = a->resources.pci.bar[4];
+    addr3  = a->resources.pci.bar[3]; /* flash  */
+    addr1  = a->resources.pci.bar[1]; /* unused */
+
+    DBG_ERR(("A: apply Compaq BIOS workaround"))
+    DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+              data[0], data[1], data[2], data[3],
+              data[4], data[5], data[6], data[7]))
+
+    Bus = a->resources.pci.bus;
+    Slot = a->resources.pci.func;
+    hdev = a->resources.pci.hdev;
+    PCIread (Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+    PCIwrite (Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev);
+
+    PCIwrite (Bus, Slot, 0x14, &addr4, sizeof(addr4), hdev);
+    PCIwrite (Bus, Slot, 0x20, &addr1, sizeof(addr1), hdev) ;
+
+    PCIwrite (Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+
+    addr = a->resources.pci.addr[1];
+    a->resources.pci.addr[1] = a->resources.pci.addr[4];
+    a->resources.pci.addr[4] = addr;
+
+    addr1 = a->resources.pci.bar[1];
+    a->resources.pci.bar[1] = a->resources.pci.bar[4];
+    a->resources.pci.bar[4] = addr1;
+
+    /*
+      Try to read Flash again
+    */
+    config = (byte*)a->resources.pci.addr[4];
+    flash  = (byte*)a->resources.pci.addr[3];
+    len = sizeof(data);
+
+    if ( !(config[0xc3c] & 0x08) ) {
+      config[0xc3c] |= 0x08 ;  /* Base Address enable register */
+    }
+    config[LOW_BOOTCS_DREG] = 0x00 ;
+    config[HI_BOOTCS_DREG]  = 0xFF ;
+
+    memset (data, '\0', len) ;
+    for (i = 0; i < len; i++) { data[i] = flash[0x8000 - len + i]; }
+    config[LOW_BOOTCS_DREG] = 0xFC;
+    config[HI_BOOTCS_DREG]  = 0xFF;
+
+    if (memcmp (&data[48], "DIVAserverPR", 12)) {
+      DBG_ERR(("A: failed to read serial number"))
+      DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+                data[0], data[1], data[2], data[3],
+                data[4], data[5], data[6], data[7]))
+      return (-1);
+    }
+#else /* } { */
+    DBG_ERR(("A: failed to read DIVA signature word"))
+    DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+              data[0], data[1], data[2], data[3],
+              data[4], data[5], data[6], data[7]))
+    DBG_LOG(("%02x:%02x:%02x:%02x", data[47], data[46], data[45],  data[44]))
+#endif /* } */
+  }
+
+  a->xdi_adapter.serialNo = (data[47] << 24) | (data[46] << 16) | (data[45] <<  8) |  data[44];
+  if (!a->xdi_adapter.serialNo || (a->xdi_adapter.serialNo == 0xffffffff)) {
+    a->xdi_adapter.serialNo = 0;
+    DBG_ERR(("A: failed to read serial number"))
+    return (-1);
+  }
+
+  DBG_LOG(("Serial No.          : %ld",     a->xdi_adapter.serialNo))
+  DBG_TRC(("Board Revision      : %d.%02d", (int)data[41], (int)data[40]))
+  DBG_TRC(("PLD revision        : %d.%02d", (int)data[33], (int)data[32]))
+  DBG_TRC(("Boot loader version : %d.%02d", (int)data[37], (int)data[36]))
+
+  DBG_TRC(("Manufacturing Date  : %d/%02d/%02d  (yyyy/mm/dd)",
+            (int)((data[28] > 90) ? 1900 : 2000) + (int)data[28],
+            (int)data[29], (int)data[30]))
+
+  return (0);
+}
+
+void
+diva_os_prepare_pri2_functions (PISDN_ADAPTER IoAdapter)
+{
+}
+
+void
+diva_os_prepare_pri_functions (PISDN_ADAPTER IoAdapter)
+{
+}
+
+/*
+**  Checks presence of DSP on board
+*/
+static int
+dsp_check_presence (volatile byte* addr, volatile byte* data, int dsp)
+{
+  word pattern;
+
+	WRITE_WORD(addr, 0x4000);
+	WRITE_WORD(data, DSP_SIGNATURE_PROBE_WORD);
+
+	WRITE_WORD(addr, 0x4000);
+  pattern = READ_WORD(data);
+
+  if (pattern != DSP_SIGNATURE_PROBE_WORD) {
+    DBG_TRC(("W: DSP[%d] %04x(is) != %04x(should)",
+              dsp, pattern, DSP_SIGNATURE_PROBE_WORD))
+    return (-1);
+  }
+
+	WRITE_WORD(addr, 0x4000);
+	WRITE_WORD(data, ~DSP_SIGNATURE_PROBE_WORD);
+
+	WRITE_WORD(addr, 0x4000);
+  pattern = READ_WORD(data);
+
+  if (pattern != (word)~DSP_SIGNATURE_PROBE_WORD) {
+    DBG_ERR(("A: DSP[%d] %04x(is) != %04x(should)",
+              dsp, pattern, (word)~DSP_SIGNATURE_PROBE_WORD))
+    return (-2);
+  }
+
+  DBG_TRC (("DSP[%d] present", dsp))
+
+  return (0);
+}
+
+
+/*
+**  Check if DSP's are present and operating
+**  Information about detected DSP's is returned as bit mask
+**  Bit 0  - DSP1
+**  ...
+**  ...
+**  ...
+**  Bit 29 - DSP30
+*/
+static dword
+diva_pri_detect_dsps (diva_os_xdi_adapter_t* a)
+{
+  byte* base = a->resources.pci.addr[2];
+  dword ret = 0;
+  dword row_offset[7] = {
+    0x00000000,
+    0x00000800, /* 1 - ROW 1 */
+    0x00000840, /* 2 - ROW 2 */
+    0x00001000, /* 3 - ROW 3 */
+    0x00001040, /* 4 - ROW 4 */
+    0x00000000  /* 5 - ROW 0 */
+  };
+
+  byte* dsp_addr_port, *dsp_data_port, row_state;
+  int dsp_row = 0, dsp_index, dsp_num;
+
+  if (!base || !a->xdi_adapter.reset) {
+    return (0);
+  }
+
+  *(volatile byte*)(a->xdi_adapter.reset) = _MP_RISC_RESET | _MP_DSP_RESET;
+  diva_os_wait (5) ;
+
+  for (dsp_num = 0; dsp_num < 30; dsp_num++) {
+    dsp_row   = dsp_num / 7 + 1;
+    dsp_index = dsp_num % 7;
+
+    dsp_data_port = base;
+    dsp_addr_port = base;
+
+    dsp_data_port += row_offset[dsp_row];
+    dsp_addr_port += row_offset[dsp_row];
+
+    dsp_data_port += (dsp_index * 8);
+    dsp_addr_port += (dsp_index * 8) + 0x80;
+
+    if (!dsp_check_presence (dsp_addr_port, dsp_data_port, dsp_num+1)) {
+      ret |= (1 << dsp_num);
+    }
+  }
+
+  *(volatile byte*)(a->xdi_adapter.reset) = _MP_RISC_RESET | _MP_LED1 | _MP_LED2;
+  diva_os_wait (5);
+
+  /*
+    Verify modules
+  */
+  for (dsp_row = 0; dsp_row < 4; dsp_row++) {
+    row_state = ((ret >> (dsp_row*7)) & 0x7F);
+    if (row_state && (row_state != 0x7F)) {
+      for (dsp_index = 0; dsp_index < 7; dsp_index++) {
+        if (!(row_state & (1 << dsp_index))) {
+          DBG_ERR (("A: MODULE[%d]-DSP[%d] failed", dsp_row+1, dsp_index+1))
+        }
+      }
+    }
+  }
+
+  if (!(ret & 0x10000000)) {
+    DBG_ERR (("A: ON BOARD-DSP[1] failed"))
+  }
+  if (!(ret & 0x20000000)) {
+    DBG_ERR (("A: ON BOARD-DSP[2] failed"))
+  }
+
+  /*
+    Print module population now
+  */
+  DBG_LOG(("+-----------------------+"))
+  DBG_LOG(("| DSP MODULE POPULATION |"))
+  DBG_LOG(("+-----------------------+"))
+  DBG_LOG(("|  1  |  2  |  3  |  4  |"))
+  DBG_LOG(("+-----------------------+"))
+  DBG_LOG(("|  %s  |  %s  |  %s  |  %s  |",
+    ((ret >> (0*7)) & 0x7F) ? "Y" : "N",
+    ((ret >> (1*7)) & 0x7F) ? "Y" : "N",
+    ((ret >> (2*7)) & 0x7F) ? "Y" : "N",
+    ((ret >> (3*7)) & 0x7F) ? "Y" : "N"))
+  DBG_LOG(("+-----------------------+"))
+
+  DBG_LOG(("DSP's(present-absent):%08x-%08x", ret, ~ret & 0x3fffffff))
+
+  return (ret);
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/os_pri.h b/drivers/isdn/hardware/eicon/os_pri.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/os_pri.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,8 @@
+/* $Id: os_pri.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_OS_PRI_REV_1_H__
+#define __DIVA_OS_PRI_REV_1_H__
+
+int diva_pri_init_card (diva_os_xdi_adapter_t* a);
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/pc.h b/drivers/isdn/hardware/eicon/pc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/pc.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,651 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef PC_H_INCLUDED  /* { */
+#define PC_H_INCLUDED
+/*------------------------------------------------------------------*/
+/* buffer definition                                                */
+/*------------------------------------------------------------------*/
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} PBUFFER;
+/*------------------------------------------------------------------*/
+/* dual port ram structure                                          */
+/*------------------------------------------------------------------*/
+struct dual
+{
+  byte Req;             /* request register                         */
+  byte ReqId;           /* request task/entity identification       */
+  byte Rc;              /* return code register                     */
+  byte RcId;            /* return code task/entity identification   */
+  byte Ind;             /* Indication register                      */
+  byte IndId;           /* Indication task/entity identification    */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte RNR;             /* Receiver Not Ready (set by PC)           */
+  byte XLock;           /* XBuffer locked Flag                      */
+  byte Int;             /* ISDN-S interrupt                         */
+  byte ReqCh;           /* Channel field for layer-3 Requests       */
+  byte RcCh;            /* Channel field for layer-3 Returncodes    */
+  byte IndCh;           /* Channel field for layer-3 Indications    */
+  byte MInd;            /* more data indication field               */
+  word MLength;         /* more data total packet length            */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte SWReg;           /* Software register for special purposes   */
+  byte Reserved[11];    /* reserved space                           */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-S adapter Signature (GD)            */
+  PBUFFER XBuffer;      /* Transmit Buffer                          */
+  PBUFFER RBuffer;      /* Receive Buffer                           */
+};
+/*------------------------------------------------------------------*/
+/* SWReg Values (0 means no command)                                */
+/*------------------------------------------------------------------*/
+#define SWREG_DIE_WITH_LEDON  0x01
+#define SWREG_HALT_CPU        0x02 /* Push CPU into a while(1) loop */
+/*------------------------------------------------------------------*/
+/* Id Fields Coding                                                 */
+/*------------------------------------------------------------------*/
+#define ID_MASK 0xe0    /* Mask for the ID field                    */
+#define GL_ERR_ID 0x1f  /* ID for error reporting on global requests*/
+#define DSIG_ID  0x00   /* ID for D-channel signaling               */
+#define NL_ID    0x20   /* ID for network-layer access (B or D)     */
+#define BLLC_ID  0x60   /* ID for B-channel link level access       */
+#define TASK_ID  0x80   /* ID for dynamic user tasks                */
+#define TIMER_ID 0xa0   /* ID for timer task                        */
+#define TEL_ID   0xc0   /* ID for telephone support                 */
+#define MAN_ID   0xe0   /* ID for management                        */
+/*------------------------------------------------------------------*/
+/* ASSIGN and REMOVE requests are the same for all entities         */
+/*------------------------------------------------------------------*/
+#define ASSIGN  0x01
+#define UREMOVE 0xfe /* without return code */
+#define REMOVE  0xff
+/*------------------------------------------------------------------*/
+/* Timer Interrupt Task Interface                                   */
+/*------------------------------------------------------------------*/
+#define ASSIGN_TIM 0x01
+#define REMOVE_TIM 0xff
+/*------------------------------------------------------------------*/
+/* dynamic user task interface                                      */
+/*------------------------------------------------------------------*/
+#define ASSIGN_TSK 0x01
+#define REMOVE_TSK 0xff
+#define LOAD 0xf0
+#define RELOCATE 0xf1
+#define START 0xf2
+#define LOAD2 0xf3
+#define RELOCATE2 0xf4
+/*------------------------------------------------------------------*/
+/* dynamic user task messages                                       */
+/*------------------------------------------------------------------*/
+#define TSK_B2          0x0000
+#define TSK_WAKEUP      0x2000
+#define TSK_TIMER       0x4000
+#define TSK_TSK         0x6000
+#define TSK_PC          0xe000
+/*------------------------------------------------------------------*/
+/* LL management primitives                                         */
+/*------------------------------------------------------------------*/
+#define ASSIGN_LL 1     /* assign logical link                      */
+#define REMOVE_LL 0xff  /* remove logical link                      */
+/*------------------------------------------------------------------*/
+/* LL service primitives                                            */
+/*------------------------------------------------------------------*/
+#define LL_UDATA 1      /* link unit data request/indication        */
+#define LL_ESTABLISH 2  /* link establish request/indication        */
+#define LL_RELEASE 3    /* link release request/indication          */
+#define LL_DATA 4       /* data request/indication                  */
+#define LL_LOCAL 5      /* switch to local operation (COM only)     */
+#define LL_DATA_PEND 5  /* data pending indication (SDLC SHM only)  */
+#define LL_REMOTE 6     /* switch to remote operation (COM only)    */
+#define LL_TEST 8       /* link test request                        */
+#define LL_MDATA 9      /* more data request/indication             */
+#define LL_BUDATA 10    /* broadcast unit data request/indication   */
+#define LL_XID 12       /* XID command request/indication           */
+#define LL_XID_R 13     /* XID response request/indication          */
+/*------------------------------------------------------------------*/
+/* NL service primitives                                            */
+/*------------------------------------------------------------------*/
+#define N_MDATA         1       /* more data to come REQ/IND        */
+#define N_CONNECT       2       /* OSI N-CONNECT REQ/IND            */
+#define N_CONNECT_ACK   3       /* OSI N-CONNECT CON/RES            */
+#define N_DISC          4       /* OSI N-DISC REQ/IND               */
+#define N_DISC_ACK      5       /* OSI N-DISC CON/RES               */
+#define N_RESET         6       /* OSI N-RESET REQ/IND              */
+#define N_RESET_ACK     7       /* OSI N-RESET CON/RES              */
+#define N_DATA          8       /* OSI N-DATA REQ/IND               */
+#define N_EDATA         9       /* OSI N-EXPEDITED DATA REQ/IND     */
+#define N_UDATA         10      /* OSI D-UNIT-DATA REQ/IND          */
+#define N_BDATA         11      /* BROADCAST-DATA REQ/IND           */
+#define N_DATA_ACK      12      /* data ack ind for D-bit procedure */
+#define N_EDATA_ACK     13      /* data ack ind for INTERRUPT       */
+#define N_XON           15      /* clear RNR state */
+#define N_Q_BIT         0x10    /* Q-bit for req/ind                */
+#define N_M_BIT         0x20    /* M-bit for req/ind                */
+#define N_D_BIT         0x40    /* D-bit for req/ind                */
+/*------------------------------------------------------------------*/
+/* Signaling management primitives                                  */
+/*------------------------------------------------------------------*/
+#define ASSIGN_SIG  1    /* assign signaling task                    */
+#define UREMOVE_SIG 0xfe /* remove signaling task without return code*/
+#define REMOVE_SIG  0xff /* remove signaling task                    */
+/*------------------------------------------------------------------*/
+/* Signaling service primitives                                     */
+/*------------------------------------------------------------------*/
+#define CALL_REQ 1      /* call request                             */
+#define CALL_CON 1      /* call confirmation                        */
+#define CALL_IND 2      /* incoming call connected                  */
+#define LISTEN_REQ 2    /* listen request                           */
+#define HANGUP 3        /* hangup request/indication                */
+#define SUSPEND 4       /* call suspend request/confirm             */
+#define RESUME 5        /* call resume request/confirm              */
+#define SUSPEND_REJ 6   /* suspend rejected indication              */
+#define USER_DATA 8     /* user data for user to user signaling     */
+#define CONGESTION 9    /* network congestion indication            */
+#define INDICATE_REQ 10 /* request to indicate an incoming call     */
+#define INDICATE_IND 10 /* indicates that there is an incoming call */
+#define CALL_RES 11     /* accept an incoming call                  */
+#define CALL_ALERT 12   /* send ALERT for incoming call             */
+#define INFO_REQ 13     /* INFO request                             */
+#define INFO_IND 13     /* INFO indication                          */
+#define REJECT 14       /* reject an incoming call                  */
+#define RESOURCES 15    /* reserve B-Channel hardware resources     */
+#define HW_CTRL 16      /* B-Channel hardware IOCTL req/ind         */
+#define TEL_CTRL 16     /* Telephone control request/indication     */
+#define STATUS_REQ 17   /* Request D-State (returned in INFO_IND)   */
+#define FAC_REG_REQ 18  /* 1TR6 connection independent fac reg      */
+#define FAC_REG_ACK 19  /* 1TR6 fac registration acknowledge        */
+#define FAC_REG_REJ 20  /* 1TR6 fac registration reject             */
+#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call       */
+#define SW_CTRL 22      /* extended software features               */
+#define REGISTER_REQ 23 /* Q.931 connection independent reg req     */
+#define REGISTER_IND 24 /* Q.931 connection independent reg ind     */
+#define FACILITY_REQ 25 /* Q.931 connection independent fac req     */
+#define FACILITY_IND 26 /* Q.931 connection independent fac ind     */
+#define NCR_INFO_REQ 27 /* INFO_REQ with NULL CR                    */
+#define GCR_MIM_REQ 28  /* MANAGEMENT_INFO_REQ with global CR       */
+#define SIG_CTRL    29  /* Control for Signalling Hardware          */
+#define DSP_CTRL    30  /* Control for DSPs                         */
+#define LAW_REQ      31 /* Law config request for (returns info_i)  */
+#define SPID_CTRL    32 /* Request/indication SPID related          */
+#define NCR_FACILITY 33 /* Request/indication with NULL/DUMMY CR    */
+#define CALL_HOLD    34 /* Request/indication to hold a CALL        */
+#define CALL_RETRIEVE 35 /* Request/indication to retrieve a CALL   */
+#define CALL_HOLD_ACK 36 /* OK of                hold a CALL        */
+#define CALL_RETRIEVE_ACK 37 /* OK of             retrieve a CALL   */
+#define CALL_HOLD_REJ 38 /* Reject of            hold a CALL        */
+#define CALL_RETRIEVE_REJ 39 /* Reject of         retrieve a call   */
+#define GCR_RESTART   40 /* Send/Receive Restart message            */
+#define S_SERVICE     41 /* Send/Receive Supplementary Service      */
+#define S_SERVICE_REJ 42 /* Reject Supplementary Service indication */
+#define S_SUPPORTED   43 /* Req/Ind to get Supported Services       */
+#define STATUS_ENQ    44 /* Req to send the D-ch request if !state0 */
+#define CALL_GUARD    45 /* Req/Ind to use the FLAGS_CALL_OUTCHECK  */
+#define CALL_GUARD_HP 46 /* Call Guard function to reject a call    */
+#define CALL_GUARD_IF 47 /* Call Guard function, inform the appl    */
+#define SSEXT_REQ     48 /* Supplem.Serv./QSIG specific request     */
+#define SSEXT_IND     49 /* Supplem.Serv./QSIG specific indication  */
+/* reserved commands for the US protocols */
+#define INT_3PTY_NIND 50 /* US       specific indication            */
+#define INT_CF_NIND   51 /* US       specific indication            */
+#define INT_3PTY_DROP 52 /* US       specific indication            */
+#define INT_MOVE_CONF 53 /* US       specific indication            */
+#define INT_MOVE_RC   54 /* US       specific indication            */
+#define INT_MOVE_FLIPPED_CONF 55 /* US specific indication          */
+#define INT_X5NI_OK   56 /* internal transfer OK indication         */
+#define INT_XDMS_START 57 /* internal transfer OK indication        */
+#define INT_XDMS_STOP 58 /* internal transfer finish indication     */
+#define INT_XDMS_STOP2 59 /* internal transfer send FA              */
+#define INT_CUSTCONF_REJ 60 /* internal conference reject           */
+#define INT_CUSTXFER 61 /* internal transfer request                */
+#define INT_CUSTX_NIND 62 /* internal transfer ack                  */
+#define INT_CUSTXREJ_NIND 63 /* internal transfer rej               */
+#define INT_X5NI_CF_XFER  64 /* internal transfer OK indication     */
+#define VSWITCH_REQ 65        /* communication between protocol and */
+#define VSWITCH_IND 66        /* capifunctions for D-CH-switching   */
+#define MWI_POLL 67     /* Message Waiting Status Request fkt */
+#define CALL_PEND_NOTIFY 68 /* notify capi to set new listen        */
+/*------------------------------------------------------------------*/
+/* management service primitives                                    */
+/*------------------------------------------------------------------*/
+#define MAN_READ        2
+#define MAN_WRITE       3
+#define MAN_EXECUTE     4
+#define MAN_EVENT_ON    5
+#define MAN_EVENT_OFF   6
+#define MAN_LOCK        7
+#define MAN_UNLOCK      8
+#define MAN_INFO_IND    2
+#define MAN_EVENT_IND   3
+#define MAN_TRACE_IND   4
+#define MAN_ESC         0x80
+/*------------------------------------------------------------------*/
+/* return code coding                                               */
+/*------------------------------------------------------------------*/
+#define UNKNOWN_COMMAND         0x01    /* unknown command          */
+#define WRONG_COMMAND           0x02    /* wrong command            */
+#define WRONG_ID                0x03    /* unknown task/entity id   */
+#define WRONG_CH                0x04    /* wrong task/entity id     */
+#define UNKNOWN_IE              0x05    /* unknown information el.  */
+#define WRONG_IE                0x06    /* wrong information el.    */
+#define OUT_OF_RESOURCES        0x07    /* ISDN-S card out of res.  */
+#define ISDN_GUARD_REJ          0x09    /* ISDN-Guard SuppServ rej  */
+#define N_FLOW_CONTROL          0x10    /* Flow-Control, retry      */
+#define ASSIGN_RC               0xe0    /* ASSIGN acknowledgement   */
+#define ASSIGN_OK               0xef    /* ASSIGN OK                */
+#define OK_FC                   0xfc    /* Flow-Control RC          */
+#define READY_INT               0xfd    /* Ready interrupt          */
+#define TIMER_INT               0xfe    /* timer interrupt          */
+#define OK                      0xff    /* command accepted         */
+/*------------------------------------------------------------------*/
+/* information elements                                             */
+/*------------------------------------------------------------------*/
+#define SHIFT 0x90              /* codeset shift                    */
+#define MORE 0xa0               /* more data                        */
+#define CL 0xb0                 /* congestion level                 */
+        /* codeset 0                                                */
+#define SMSG 0x00               /* segmented message                */
+#define BC  0x04                /* Bearer Capability                */
+#define CAU 0x08                /* cause                            */
+#define CAD 0x0c                /* Connected address                */
+#define CAI 0x10                /* call identity                    */
+#define CHI 0x18                /* channel identification           */
+#define LLI 0x19                /* logical link id                  */
+#define CHA 0x1a                /* charge advice                    */
+#define FTY 0x1c                /* Facility                         */
+#define DT  0x29                /* ETSI date/time                   */
+#define KEY 0x2c                /* keypad information element       */
+#define UID 0x2d                /* User id information element      */
+#define DSP 0x28                /* display                          */
+#define SIG 0x34                /* signalling hardware control      */
+#define OAD 0x6c                /* origination address              */
+#define OSA 0x6d                /* origination sub-address          */
+#define CPN 0x70                /* called party number              */
+#define DSA 0x71                /* destination sub-address          */
+#define RDX 0x73                /* redirecting number extended      */
+#define RDN 0x74                /* redirecting number               */
+#define RIN 0x76                /* redirection number               */
+#define RI  0x79                /* restart indicator                */
+#define MIE 0x7a                /* management info element          */
+#define LLC 0x7c                /* low layer compatibility          */
+#define HLC 0x7d                /* high layer compatibility         */
+#define UUI 0x7e                /* user user information            */
+#define ESC 0x7f                /* escape extension                 */
+#define DLC 0x20                /* data link layer configuration    */
+#define NLC 0x21                /* network layer configuration      */
+        /* codeset 6                                                */
+#define SIN 0x01                /* service indicator                */
+#define CIF 0x02                /* charging information             */
+#define DATE 0x03               /* date                             */
+#define CPS 0x07                /* called party status              */
+/*------------------------------------------------------------------*/
+/* ESC information elements                                         */
+/*------------------------------------------------------------------*/
+#define MSGTYPEIE        0x7a   /* Messagetype info element         */
+#define CRIE             0x7b   /* INFO info element                */
+#define VSWITCHIE        0xed   /* VSwitch info element             */
+#define SSEXTIE          0xee   /* Supplem. Service info element    */
+#define PROFILEIE        0xef   /* Profile info element             */
+/*------------------------------------------------------------------*/
+/* TEL_CTRL contents                                                */
+/*------------------------------------------------------------------*/
+#define RING_ON         0x01
+#define RING_OFF        0x02
+#define HANDS_FREE_ON   0x03
+#define HANDS_FREE_OFF  0x04
+#define ON_HOOK         0x80
+#define OFF_HOOK        0x90
+/* operation values used by ETSI supplementary services */
+#define THREE_PTY_BEGIN           0x04
+#define THREE_PTY_END             0x05
+#define ECT_EXECUTE               0x06
+#define ACTIVATION_DIVERSION      0x07
+#define DEACTIVATION_DIVERSION    0x08
+#define CALL_DEFLECTION           0x0D
+#define INTERROGATION_DIVERSION   0x0B
+#define INTERROGATION_SERV_USR_NR 0x11
+#define ACTIVATION_MWI            0x20
+#define DEACTIVATION_MWI          0x21
+#define MWI_INDICATION            0x22
+#define MWI_RESPONSE              0x23
+#define CONF_BEGIN                0x28
+#define CONF_ADD                  0x29
+#define CONF_SPLIT                0x2a
+#define CONF_DROP                 0x2b
+#define CONF_ISOLATE              0x2c
+#define CONF_REATTACH             0x2d
+#define CONF_PARTYDISC            0x2e
+#define CCBS_INFO_RETAIN          0x2f
+#define CCBS_ERASECALLLINKAGEID   0x30
+#define CCBS_STOP_ALERTING        0x31
+#define CCBS_REQUEST              0x32
+#define CCBS_DEACTIVATE           0x33
+#define CCBS_INTERROGATE          0x34
+#define GET_SUPPORTED_SERVICES    0xff
+#define DIVERSION_PROCEDURE_CFU     0x70
+#define DIVERSION_PROCEDURE_CFB     0x71
+#define DIVERSION_PROCEDURE_CFNR    0x72
+#define DIVERSION_DEACTIVATION_CFU  0x80
+#define DIVERSION_DEACTIVATION_CFB  0x81
+#define DIVERSION_DEACTIVATION_CFNR 0x82
+#define DIVERSION_INTERROGATE_NUM   0x11
+#define DIVERSION_INTERROGATE_CFU   0x60
+#define DIVERSION_INTERROGATE_CFB   0x61
+#define DIVERSION_INTERROGATE_CFNR  0x62
+/* Service Masks */
+#define SMASK_HOLD_RETRIEVE        0x00000001
+#define SMASK_TERMINAL_PORTABILITY 0x00000002
+#define SMASK_ECT                  0x00000004
+#define SMASK_3PTY                 0x00000008
+#define SMASK_CALL_FORWARDING      0x00000010
+#define SMASK_CALL_DEFLECTION      0x00000020
+#define SMASK_CCBS                 0x00000080
+#define SMASK_MWI                  0x00000100
+#define SMASK_CCNR                 0x00000200
+#define SMASK_CONF                 0x00000400
+/* ----------------------------------------------
+    Types of transfers used to transfer the
+    information in the 'struct RC->Reserved2[8]'
+    The information is transferred as 2 dwords
+    (2 4Byte unsigned values)
+    First of them is the transfer type.
+    2^32-1 possible messages are possible in this way.
+    The context of the second one had no meaning
+   ---------------------------------------------- */
+#define DIVA_RC_TYPE_NONE              0x00000000
+#define DIVA_RC_TYPE_REMOVE_COMPLETE   0x00000008
+#define DIVA_RC_TYPE_STREAM_PTR        0x00000009
+#define DIVA_RC_TYPE_CMA_PTR           0x0000000a
+#define DIVA_RC_TYPE_OK_FC             0x0000000b
+#define DIVA_RC_TYPE_RX_DMA            0x0000000c
+/* ------------------------------------------------------
+      IO Control codes for IN BAND SIGNALING
+   ------------------------------------------------------ */
+#define CTRL_L1_SET_SIG_ID        5
+#define CTRL_L1_SET_DAD           6
+#define CTRL_L1_RESOURCES         7
+/* ------------------------------------------------------ */
+/* ------------------------------------------------------
+      Layer 2 types
+   ------------------------------------------------------ */
+#define X75T            1       /* x.75 for ttx                     */
+#define TRF             2       /* transparent with hdlc framing    */
+#define TRF_IN          3       /* transparent with hdlc fr. inc.   */
+#define SDLC            4       /* sdlc, sna layer-2                */
+#define X75             5       /* x.75 for btx                     */
+#define LAPD            6       /* lapd (Q.921)                     */
+#define X25_L2          7       /* x.25 layer-2                     */
+#define V120_L2         8       /* V.120 layer-2 protocol           */
+#define V42_IN          9       /* V.42 layer-2 protocol, incomming */
+#define V42            10       /* V.42 layer-2 protocol            */
+#define MDM_ATP        11       /* AT Parser built in the L2        */
+#define X75_V42BIS     12       /* x.75 with V.42bis                */
+#define RTPL2_IN       13       /* RTP layer-2 protocol, incomming  */
+#define RTPL2          14       /* RTP layer-2 protocol             */
+#define V120_V42BIS    15       /* V.120 asynchronous mode supporting V.42bis compression */
+#define PIAFS_CRC      29       /* PIAFS Layer 2 with CRC calculation at L2 */
+/* ------------------------------------------------------
+   PIAFS DLC DEFINITIONS
+   ------------------------------------------------------ */
+#define PIAFS_64K            0x01
+#define PIAFS_VARIABLE_SPEED 0x02
+#define PIAFS_CHINESE_SPEED    0x04
+#define PIAFS_UDATA_ABILITY_ID    0x80
+#define PIAFS_UDATA_ABILITY_DCDON 0x01
+#define PIAFS_UDATA_ABILITY_DDI   0x80
+/*
+DLC of PIAFS :
+Byte | 8 7 6 5 4 3 2 1
+-----+--------------------------------------------------------
+   0 | 0 0 1 0 0 0 0 0  Data Link Configuration
+   1 | X X X X X X X X  Length of IE (at least 15 Bytes)
+   2 | 0 0 0 0 0 0 0 0  max. information field, LOW  byte (not used, fix 73 Bytes)
+   3 | 0 0 0 0 0 0 0 0  max. information field, HIGH byte (not used, fix 73 Bytes)
+   4 | 0 0 0 0 0 0 0 0  address A (not used)
+   5 | 0 0 0 0 0 0 0 0  address B (not used)
+   6 | 0 0 0 0 0 0 0 0  Mode (not used, fix 128)
+   7 | 0 0 0 0 0 0 0 0  Window Size (not used, fix 127)
+   8 | X X X X X X X X  XID Length, Low Byte (at least 7 Bytes)
+   9 | X X X X X X X X  XID Length, High Byte
+  10 | 0 0 0 0 0 C V S  PIAFS Protocol Speed configuration -> Note(1)
+     |                  S = 0 -> Protocol Speed is 32K
+     |                  S = 1 -> Protocol Speed is 64K
+     |                  V = 0 -> Protocol Speed is fixed
+     |                  V = 1 -> Protocol Speed is variable
+     |                  C = 0 -> speed setting according to standard
+     |                  C = 1 -> speed setting for chinese implementation
+  11 | 0 0 0 0 0 0 R T  P0 - V42bis Compression enable/disable, Low Byte
+     |                  T = 0 -> Transmit Direction enable
+     |                  T = 1 -> Transmit Direction disable
+     |                  R = 0 -> Receive  Direction enable
+     |                  R = 1 -> Receive  Direction disable
+  13 | 0 0 0 0 0 0 0 0  P0 - V42bis Compression enable/disable, High Byte
+  14 | X X X X X X X X  P1 - V42bis Dictionary Size, Low Byte
+  15 | X X X X X X X X  P1 - V42bis Dictionary Size, High Byte
+  16 | X X X X X X X X  P2 - V42bis String Length, Low Byte
+  17 | X X X X X X X X  P2 - V42bis String Length, High Byte
+  18 | X X X X X X X X  PIAFS extension length
+  19 | 1 0 0 0 0 0 0 0  PIAFS extension Id (0x80) - UDATA abilities
+  20 | U 0 0 0 0 0 0 D  UDATA abilities -> Note (2)
+     |                  up to now the following Bits are defined:
+     |                  D - signal DCD ON
+     |                  U - use extensive UDATA control communication
+     |                      for DDI test application
++ Note (1): ----------+------+-----------------------------------------+
+| PIAFS Protocol      | Bit  |                                         |
+| Speed configuration |    S | Bit 1 - Protocol Speed                  |
+|                     |      |         0 - 32K                         |
+|                     |      |         1 - 64K (default)               |
+|                     |    V | Bit 2 - Variable Protocol Speed         |
+|                     |      |         0 - Speed is fix                |
+|                     |      |         1 - Speed is variable (default) |
+|                     |      |             OVERWRITES 32k Bit 1        |
+|                     |    C | Bit 3   0 - Speed Settings according to |
+|                     |      |             PIAFS specification         |
+|                     |      |         1 - Speed setting for chinese   |
+|                     |      |             PIAFS implementation        |
+|                     |      | Explanation for chinese speed settings: |
+|                     |      |         if Bit 3 is set the following   |
+|                     |      |         rules apply:                    |
+|                     |      |         Bit1=0 Bit2=0: 32k fix          |
+|                     |      |         Bit1=1 Bit2=0: 64k fix          |
+|                     |      |         Bit1=0 Bit2=1: PIAFS is trying  |
+|                     |      |             to negotiate 32k is that is |
+|                     |      |             not possible it tries to    |
+|                     |      |             negotiate 64k               |
+|                     |      |         Bit1=1 Bit2=1: PIAFS is trying  |
+|                     |      |             to negotiate 64k is that is |
+|                     |      |             not possible it tries to    |
+|                     |      |             negotiate 32k               |
++ Note (2): ----------+------+-----------------------------------------+
+| PIAFS               | Bit  | this byte defines the usage of UDATA    |
+| Implementation      |      | control communication                   |
+| UDATA usage         |    D | Bit 1 - DCD-ON signalling               |
+|                     |      |         0 - no DCD-ON is signalled      |
+|                     |      |             (default)                   |
+|                     |      |         1 - DCD-ON will be signalled    |
+|                     |    U | Bit 8 - DDI test application UDATA      |
+|                     |      |         control communication           |
+|                     |      |         0 - no UDATA control            |
+|                     |      |             communication (default)     |
+|                     |      |             sets as well the DCD-ON     |
+|                     |      |             signalling                  |
+|                     |      |         1 - UDATA control communication |
+|                     |      |             ATTENTION: Do not use these |
+|                     |      |                        setting if you   |
+|                     |      |                        are not really   |
+|                     |      |                        that you need it |
+|                     |      |                        and you know     |
+|                     |      |                        exactly what you |
+|                     |      |                        are doing.       |
+|                     |      |                        You can easily   |
+|                     |      |                        disable any      |
+|                     |      |                        data transfer.   |
++---------------------+------+-----------------------------------------+
+*/
+/*------------------------------------------------------------------*/
+/* CAPI-like profile to indicate features on LAW_REQ                */
+/*------------------------------------------------------------------*/
+#define GL_INTERNAL_CONTROLLER_SUPPORTED     0x00000001L
+#define GL_EXTERNAL_EQUIPMENT_SUPPORTED      0x00000002L
+#define GL_HANDSET_SUPPORTED                 0x00000004L
+#define GL_DTMF_SUPPORTED                    0x00000008L
+#define GL_SUPPLEMENTARY_SERVICES_SUPPORTED  0x00000010L
+#define GL_CHANNEL_ALLOCATION_SUPPORTED      0x00000020L
+#define GL_BCHANNEL_OPERATION_SUPPORTED      0x00000040L
+#define GL_LINE_INTERCONNECT_SUPPORTED       0x00000080L
+#define B1_HDLC_SUPPORTED                    0x00000001L
+#define B1_TRANSPARENT_SUPPORTED             0x00000002L
+#define B1_V110_ASYNC_SUPPORTED              0x00000004L
+#define B1_V110_SYNC_SUPPORTED               0x00000008L
+#define B1_T30_SUPPORTED                     0x00000010L
+#define B1_HDLC_INVERTED_SUPPORTED           0x00000020L
+#define B1_TRANSPARENT_R_SUPPORTED           0x00000040L
+#define B1_MODEM_ALL_NEGOTIATE_SUPPORTED     0x00000080L
+#define B1_MODEM_ASYNC_SUPPORTED             0x00000100L
+#define B1_MODEM_SYNC_HDLC_SUPPORTED         0x00000200L
+#define B2_X75_SUPPORTED                     0x00000001L
+#define B2_TRANSPARENT_SUPPORTED             0x00000002L
+#define B2_SDLC_SUPPORTED                    0x00000004L
+#define B2_LAPD_SUPPORTED                    0x00000008L
+#define B2_T30_SUPPORTED                     0x00000010L
+#define B2_PPP_SUPPORTED                     0x00000020L
+#define B2_TRANSPARENT_NO_CRC_SUPPORTED      0x00000040L
+#define B2_MODEM_EC_COMPRESSION_SUPPORTED    0x00000080L
+#define B2_X75_V42BIS_SUPPORTED              0x00000100L
+#define B2_V120_ASYNC_SUPPORTED              0x00000200L
+#define B2_V120_ASYNC_V42BIS_SUPPORTED       0x00000400L
+#define B2_V120_BIT_TRANSPARENT_SUPPORTED    0x00000800L
+#define B2_LAPD_FREE_SAPI_SEL_SUPPORTED      0x00001000L
+#define B3_TRANSPARENT_SUPPORTED             0x00000001L
+#define B3_T90NL_SUPPORTED                   0x00000002L
+#define B3_ISO8208_SUPPORTED                 0x00000004L
+#define B3_X25_DCE_SUPPORTED                 0x00000008L
+#define B3_T30_SUPPORTED                     0x00000010L
+#define B3_T30_WITH_EXTENSIONS_SUPPORTED     0x00000020L
+#define B3_RESERVED_SUPPORTED                0x00000040L
+#define B3_MODEM_SUPPORTED                   0x00000080L
+#define MANUFACTURER_FEATURE_SLAVE_CODEC          0x00000001L
+#define MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS   0x00000002L
+#define MANUFACTURER_FEATURE_HARDDTMF             0x00000004L
+#define MANUFACTURER_FEATURE_SOFTDTMF_SEND        0x00000008L
+#define MANUFACTURER_FEATURE_DTMF_PARAMETERS      0x00000010L
+#define MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE     0x00000020L
+#define MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD      0x00000040L
+#define MANUFACTURER_FEATURE_V18                  0x00000080L
+#define MANUFACTURER_FEATURE_MIXER_CH_CH          0x00000100L
+#define MANUFACTURER_FEATURE_MIXER_CH_PC          0x00000200L
+#define MANUFACTURER_FEATURE_MIXER_PC_CH          0x00000400L
+#define MANUFACTURER_FEATURE_MIXER_PC_PC          0x00000800L
+#define MANUFACTURER_FEATURE_ECHO_CANCELLER       0x00001000L
+#define MANUFACTURER_FEATURE_RTP                  0x00002000L
+#define MANUFACTURER_FEATURE_T38                  0x00004000L
+#define MANUFACTURER_FEATURE_TRANSP_DELIVERY_CONF 0x00008000L
+#define MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL  0x00010000L
+#define MANUFACTURER_FEATURE_OOB_CHANNEL          0x00020000L
+#define MANUFACTURER_FEATURE_IN_BAND_CHANNEL      0x00040000L
+#define MANUFACTURER_FEATURE_IN_BAND_FEATURE      0x00080000L
+#define MANUFACTURER_FEATURE_PIAFS                0x00100000L
+#define MANUFACTURER_FEATURE_DTMF_TONE            0x00200000L
+#define MANUFACTURER_FEATURE_FAX_PAPER_FORMATS    0x00400000L
+#define MANUFACTURER_FEATURE_OK_FC_LABEL          0x00800000L
+#define MANUFACTURER_FEATURE_VOWN                 0x01000000L
+#define MANUFACTURER_FEATURE_XCONNECT             0x02000000L
+#define MANUFACTURER_FEATURE_DMACONNECT           0x04000000L
+#define MANUFACTURER_FEATURE_AUDIO_TAP            0x08000000L
+#define MANUFACTURER_FEATURE_FAX_NONSTANDARD      0x10000000L
+#define RTP_PRIM_PAYLOAD_PCMU_8000     0
+#define RTP_PRIM_PAYLOAD_1016_8000     1
+#define RTP_PRIM_PAYLOAD_G726_32_8000  2
+#define RTP_PRIM_PAYLOAD_GSM_8000      3
+#define RTP_PRIM_PAYLOAD_G723_8000     4
+#define RTP_PRIM_PAYLOAD_DVI4_8000     5
+#define RTP_PRIM_PAYLOAD_DVI4_16000    6
+#define RTP_PRIM_PAYLOAD_LPC_8000      7
+#define RTP_PRIM_PAYLOAD_PCMA_8000     8
+#define RTP_PRIM_PAYLOAD_G722_16000    9
+#define RTP_PRIM_PAYLOAD_QCELP_8000    12
+#define RTP_PRIM_PAYLOAD_G728_8000     14
+#define RTP_PRIM_PAYLOAD_G729_8000     18
+#define RTP_PRIM_PAYLOAD_GSM_HR_8000   30
+#define RTP_PRIM_PAYLOAD_GSM_EFR_8000  31
+#define RTP_ADD_PAYLOAD_BASE           32
+#define RTP_ADD_PAYLOAD_RED            32
+#define RTP_ADD_PAYLOAD_CN_8000        33
+#define RTP_ADD_PAYLOAD_DTMF           34
+#define RTP_PRIM_PAYLOAD_PCMU_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_PCMU_8000)
+#define RTP_PRIM_PAYLOAD_1016_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_1016_8000)
+#define RTP_PRIM_PAYLOAD_G726_32_8000_SUPPORTED  (1L << RTP_PRIM_PAYLOAD_G726_32_8000)
+#define RTP_PRIM_PAYLOAD_GSM_8000_SUPPORTED      (1L << RTP_PRIM_PAYLOAD_GSM_8000)
+#define RTP_PRIM_PAYLOAD_G723_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_G723_8000)
+#define RTP_PRIM_PAYLOAD_DVI4_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_DVI4_8000)
+#define RTP_PRIM_PAYLOAD_DVI4_16000_SUPPORTED    (1L << RTP_PRIM_PAYLOAD_DVI4_16000)
+#define RTP_PRIM_PAYLOAD_LPC_8000_SUPPORTED      (1L << RTP_PRIM_PAYLOAD_LPC_8000)
+#define RTP_PRIM_PAYLOAD_PCMA_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_PCMA_8000)
+#define RTP_PRIM_PAYLOAD_G722_16000_SUPPORTED    (1L << RTP_PRIM_PAYLOAD_G722_16000)
+#define RTP_PRIM_PAYLOAD_QCELP_8000_SUPPORTED    (1L << RTP_PRIM_PAYLOAD_QCELP_8000)
+#define RTP_PRIM_PAYLOAD_G728_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_G728_8000)
+#define RTP_PRIM_PAYLOAD_G729_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_G729_8000)
+#define RTP_PRIM_PAYLOAD_GSM_HR_8000_SUPPORTED   (1L << RTP_PRIM_PAYLOAD_GSM_HR_8000)
+#define RTP_PRIM_PAYLOAD_GSM_EFR_8000_SUPPORTED  (1L << RTP_PRIM_PAYLOAD_GSM_EFR_8000)
+#define RTP_ADD_PAYLOAD_RED_SUPPORTED            (1L << (RTP_ADD_PAYLOAD_RED - RTP_ADD_PAYLOAD_BASE))
+#define RTP_ADD_PAYLOAD_CN_8000_SUPPORTED        (1L << (RTP_ADD_PAYLOAD_CN_8000 - RTP_ADD_PAYLOAD_BASE))
+#define RTP_ADD_PAYLOAD_DTMF_SUPPORTED           (1L << (RTP_ADD_PAYLOAD_DTMF - RTP_ADD_PAYLOAD_BASE))
+/* virtual switching definitions */
+#define VSJOIN         1
+#define VSTRANSPORT    2
+#define VSGETPARAMS    3
+#define VSCAD          1
+#define VSRXCPNAME     2
+#define VSCALLSTAT     3
+#define VSINVOKEID    4
+#define VSCLMRKS       5
+#define VSTBCTIDENT    6
+/* -----------------------------------------------------------**
+** The PROTOCOL_FEATURE_STRING in feature.h (included         **
+** in prstart.sx and astart.sx) defines capabilities and      **
+** features of the actual protocol code. It's used as a bit   **
+** mask.                                                      **
+** The following Bits are defined:                            **
+** -----------------------------------------------------------*/
+#define PROTCAP_TELINDUS  0x0001  /* Telindus Variant of protocol code   */
+#define PROTCAP_MAN_IF    0x0002  /* Management interface implemented    */
+#define PROTCAP_V_42      0x0004  /* V42 implemented                     */
+#define PROTCAP_V90D      0x0008  /* V.90D (implies up to 384k DSP code) */
+#define PROTCAP_EXTD_FAX  0x0010  /* Extended FAX (ECM, 2D, T6, Polling) */
+#define PROTCAP_EXTD_RXFC 0x0020  /* RxFC (Extd Flow Control), OOB Chnl  */
+#define PROTCAP_VOIP      0x0040  /* VoIP (implies up to 512k DSP code)  */
+#define PROTCAP_CMA_ALLPR 0x0080  /* CMA support for all NL primitives   */
+#define PROTCAP_FREE8     0x0100  /* not used                            */
+#define PROTCAP_FREE9     0x0200  /* not used                            */
+#define PROTCAP_FREE10    0x0400  /* not used                            */
+#define PROTCAP_FREE11    0x0800  /* not used                            */
+#define PROTCAP_FREE12    0x1000  /* not used                            */
+#define PROTCAP_FREE13    0x2000  /* not used                            */
+#define PROTCAP_FREE14    0x4000  /* not used                            */
+#define PROTCAP_EXTENSION 0x8000  /* used for future extentions          */
+#else
+#endif /* PC_H_INCLUDED  } */
diff -Nru a/drivers/isdn/hardware/eicon/pc_init.h b/drivers/isdn/hardware/eicon/pc_init.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/pc_init.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,267 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef PC_INIT_H_
+#define PC_INIT_H_
+/*------------------------------------------------------------------*/
+/*
+  Initialisation parameters for the card
+  0x0008 <byte> TEI
+  0x0009 <byte> NT2 flag
+  0x000a <byte> Default DID length
+  0x000b <byte> Disable watchdog flag
+  0x000c <byte> Permanent connection flag
+  0x000d <byte> Bit 3-8: L1 Hunt Group/Tristate
+  0x000d <byte> Bit 1: QSig small CR length if set to 1
+  0x000d <byte> Bit 2: QSig small CHI length if set to 1
+  0x000e <byte> Bit 1-3: Stable L2, 0=OnDemand,1=NoDisc,2=permanent
+  0x000e <byte> Bit 4: NT mode
+  0x000e <byte> Bit 5: QSig Channel ID format
+  0x000e <byte> Bit 6: QSig Call Forwarding Allowed Flag
+  0x000e <byte> Bit 7: Disable AutoSPID Flag
+  0x000f <byte> No order check flag
+  0x0010 <byte> Force companding type:0=default,1=a-law,2=u-law
+  0x0012 <byte> Low channel flag
+  0x0013 <byte> Protocol version
+  0x0014 <byte> CRC4 option:0=default,1=double_frm,2=multi_frm,3=auto
+  0x0015 <byte> Bit 0: NoHscx30, Bit 1: Loopback flag, Bit 2: ForceHscx30
+  0x0016 <byte> DSP info
+  0x0017-0x0019 Serial number
+  0x001a <byte> Card type
+  0x0020 <string> OAD 0
+  0x0040 <string> OSA 0
+  0x0060 <string> SPID 0 (if not T.1)
+  0x0060 <struct> if T.1: Robbed Bit Configuration
+  0x0060          length (8)
+  0x0061          RBS Answer Delay
+  0x0062          RBS Config Bit 3, 4:
+                             0  0 -> Wink Start
+                             1  0 -> Loop Start
+                             0  1 -> Ground Start
+                             1  1 -> reserved
+                             Bit 5, 6:
+                             0  0 -> Pulse Dial -> Rotary
+                             1  0 -> DTMF
+                             0  1 -> MF
+                             1  1 -> reserved
+  0x0063          RBS RX Digit Timeout
+  0x0064          RBS Bearer Capability
+  0x0065-0x0069   RBS Debug Mask
+  0x0080 <string> OAD 1
+  0x00a0 <string> OSA 1
+  0x00c0 <string> SPID 1
+  0x00e0 <w-element list> Additional configuration
+*/
+#define PCINIT_END_OF_LIST                0x00
+#define PCINIT_MODEM_GUARD_TONE           0x01
+#define PCINIT_MODEM_MIN_SPEED            0x02
+#define PCINIT_MODEM_MAX_SPEED            0x03
+#define PCINIT_MODEM_PROTOCOL_OPTIONS     0x04
+#define PCINIT_FAX_OPTIONS                0x05
+#define PCINIT_FAX_MAX_SPEED              0x06
+#define PCINIT_MODEM_OPTIONS              0x07
+#define PCINIT_MODEM_NEGOTIATION_MODE     0x08
+#define PCINIT_MODEM_MODULATIONS_MASK     0x09
+#define PCINIT_MODEM_TRANSMIT_LEVEL       0x0a
+#define PCINIT_FAX_DISABLED_RESOLUTIONS   0x0b
+#define PCINIT_FAX_MAX_RECORDING_WIDTH    0x0c
+#define PCINIT_FAX_MAX_RECORDING_LENGTH   0x0d
+#define PCINIT_FAX_MIN_SCANLINE_TIME      0x0e
+#define PCINIT_US_EKTS_CACH_HANDLES       0x0f
+#define PCINIT_US_EKTS_BEGIN_CONF         0x10
+#define PCINIT_US_EKTS_DROP_CONF          0x11
+#define PCINIT_US_EKTS_CALL_TRANSFER      0x12
+#define PCINIT_RINGERTONE_OPTION          0x13
+#define PCINIT_CARD_ADDRESS               0x14
+#define PCINIT_FPGA_FEATURES              0x15
+#define PCINIT_US_EKTS_MWI                0x16
+#define PCINIT_MODEM_SPEAKER_CONTROL      0x17
+#define PCINIT_MODEM_SPEAKER_VOLUME       0x18
+#define PCINIT_MODEM_CARRIER_WAIT_TIME    0x19
+#define PCINIT_MODEM_CARRIER_LOSS_TIME    0x1a
+#define PCINIT_UNCHAN_B_MASK              0x1b
+#define PCINIT_PART68_LIMITER             0x1c
+#define PCINIT_XDI_FEATURES               0x1d
+#define PCINIT_QSIG_DIALECT               0x1e
+#define PCINIT_DISABLE_AUTOSPID_FLAG      0x1f
+#define PCINIT_FORCE_VOICE_MAIL_ALERT     0x20
+#define PCINIT_PIAFS_TURNAROUND_FRAMES    0x21
+#define PCINIT_L2_COUNT                   0x22
+#define PCINIT_QSIG_FEATURES              0x23
+#define PCINIT_NO_SIGNALLING              0x24
+#define PCINIT_CARD_SN                    0x25
+#define PCINIT_CARD_PORT                  0x26
+#define PCINIT_ALERTTO                    0x27
+#define PCINIT_MODEM_EYE_SETUP            0x28
+#define PCINIT_FAX_V34_OPTIONS            0x29
+/*------------------------------------------------------------------*/
+#define PCINIT_MODEM_GUARD_TONE_NONE            0x00
+#define PCINIT_MODEM_GUARD_TONE_550HZ           0x01
+#define PCINIT_MODEM_GUARD_TONE_1800HZ          0x02
+#define PCINIT_MODEM_GUARD_TONE_CHOICES         0x03
+#define PCINIT_MODEMPROT_DISABLE_V42_V42BIS     0x0001
+#define PCINIT_MODEMPROT_DISABLE_MNP_MNP5       0x0002
+#define PCINIT_MODEMPROT_REQUIRE_PROTOCOL       0x0004
+#define PCINIT_MODEMPROT_DISABLE_V42_DETECT     0x0008
+#define PCINIT_MODEMPROT_DISABLE_COMPRESSION    0x0010
+#define PCINIT_MODEMPROT_REQUIRE_PROTOCOL_V34UP 0x0020
+#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_1200    0x0100
+#define PCINIT_MODEMPROT_BUFFER_IN_V42_DETECT   0x0200
+#define PCINIT_MODEMPROT_DISABLE_V42_SREJ       0x0400
+#define PCINIT_MODEMPROT_DISABLE_MNP3           0x0800
+#define PCINIT_MODEMPROT_DISABLE_MNP4           0x1000
+#define PCINIT_MODEMPROT_DISABLE_MNP10          0x2000
+#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_V22BIS  0x4000
+#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_V32BIS  0x8000
+#define PCINIT_MODEMCONFIG_LEASED_LINE_MODE     0x00000001L
+#define PCINIT_MODEMCONFIG_4_WIRE_OPERATION     0x00000002L
+#define PCINIT_MODEMCONFIG_DISABLE_BUSY_DETECT  0x00000004L
+#define PCINIT_MODEMCONFIG_DISABLE_CALLING_TONE 0x00000008L
+#define PCINIT_MODEMCONFIG_DISABLE_ANSWER_TONE  0x00000010L
+#define PCINIT_MODEMCONFIG_ENABLE_DIAL_TONE_DET 0x00000020L
+#define PCINIT_MODEMCONFIG_USE_POTS_INTERFACE   0x00000040L
+#define PCINIT_MODEMCONFIG_FORCE_RAY_TAYLOR_FAX 0x00000080L
+#define PCINIT_MODEMCONFIG_DISABLE_RETRAIN      0x00000100L
+#define PCINIT_MODEMCONFIG_DISABLE_STEPDOWN     0x00000200L
+#define PCINIT_MODEMCONFIG_DISABLE_SPLIT_SPEED  0x00000400L
+#define PCINIT_MODEMCONFIG_DISABLE_TRELLIS      0x00000800L
+#define PCINIT_MODEMCONFIG_ALLOW_RDL_TEST_LOOP  0x00001000L
+#define PCINIT_MODEMCONFIG_DISABLE_STEPUP       0x00002000L
+#define PCINIT_MODEMCONFIG_DISABLE_FLUSH_TIMER  0x00004000L
+#define PCINIT_MODEMCONFIG_REVERSE_DIRECTION    0x00008000L
+#define PCINIT_MODEMCONFIG_DISABLE_TX_REDUCTION 0x00010000L
+#define PCINIT_MODEMCONFIG_DISABLE_PRECODING    0x00020000L
+#define PCINIT_MODEMCONFIG_DISABLE_PREEMPHASIS  0x00040000L
+#define PCINIT_MODEMCONFIG_DISABLE_SHAPING      0x00080000L
+#define PCINIT_MODEMCONFIG_DISABLE_NONLINEAR_EN 0x00100000L
+#define PCINIT_MODEMCONFIG_DISABLE_MANUALREDUCT 0x00200000L
+#define PCINIT_MODEMCONFIG_DISABLE_16_POINT_TRN 0x00400000L
+#define PCINIT_MODEMCONFIG_DISABLE_2400_SYMBOLS 0x01000000L
+#define PCINIT_MODEMCONFIG_DISABLE_2743_SYMBOLS 0x02000000L
+#define PCINIT_MODEMCONFIG_DISABLE_2800_SYMBOLS 0x04000000L
+#define PCINIT_MODEMCONFIG_DISABLE_3000_SYMBOLS 0x08000000L
+#define PCINIT_MODEMCONFIG_DISABLE_3200_SYMBOLS 0x10000000L
+#define PCINIT_MODEMCONFIG_DISABLE_3429_SYMBOLS 0x20000000L
+#define PCINIT_MODEM_NEGOTIATE_HIGHEST          0x00
+#define PCINIT_MODEM_NEGOTIATE_DISABLED         0x01
+#define PCINIT_MODEM_NEGOTIATE_IN_CLASS         0x02
+#define PCINIT_MODEM_NEGOTIATE_V100             0x03
+#define PCINIT_MODEM_NEGOTIATE_V8               0x04
+#define PCINIT_MODEM_NEGOTIATE_V8BIS            0x05
+#define PCINIT_MODEM_NEGOTIATE_CHOICES          0x06
+#define PCINIT_MODEMMODULATION_DISABLE_V21      0x00000001L
+#define PCINIT_MODEMMODULATION_DISABLE_V23      0x00000002L
+#define PCINIT_MODEMMODULATION_DISABLE_V22      0x00000004L
+#define PCINIT_MODEMMODULATION_DISABLE_V22BIS   0x00000008L
+#define PCINIT_MODEMMODULATION_DISABLE_V32      0x00000010L
+#define PCINIT_MODEMMODULATION_DISABLE_V32BIS   0x00000020L
+#define PCINIT_MODEMMODULATION_DISABLE_V34      0x00000040L
+#define PCINIT_MODEMMODULATION_DISABLE_V90      0x00000080L
+#define PCINIT_MODEMMODULATION_DISABLE_BELL103  0x00000100L
+#define PCINIT_MODEMMODULATION_DISABLE_BELL212A 0x00000200L
+#define PCINIT_MODEMMODULATION_DISABLE_VFC      0x00000400L
+#define PCINIT_MODEMMODULATION_DISABLE_K56FLEX  0x00000800L
+#define PCINIT_MODEMMODULATION_DISABLE_X2       0x00001000L
+#define PCINIT_MODEMMODULATION_ENABLE_V29FDX    0x00010000L
+#define PCINIT_MODEMMODULATION_ENABLE_V33       0x00020000L
+#define PCINIT_MODEMMODULATION_ENABLE_V90A      0x00040000L
+#define PCINIT_MODEM_TRANSMIT_LEVEL_CHOICES     0x10
+#define PCINIT_MODEM_SPEAKER_OFF                0x00
+#define PCINIT_MODEM_SPEAKER_DURING_TRAIN       0x01
+#define PCINIT_MODEM_SPEAKER_TIL_CONNECT        0x02
+#define PCINIT_MODEM_SPEAKER_ALWAYS_ON          0x03
+#define PCINIT_MODEM_SPEAKER_CHOICES            0x04
+#define PCINIT_MODEM_SPEAKER_VOLUME_MIN         0x00
+#define PCINIT_MODEM_SPEAKER_VOLUME_LOW         0x01
+#define PCINIT_MODEM_SPEAKER_VOLUME_HIGH        0x02
+#define PCINIT_MODEM_SPEAKER_VOLUME_MAX         0x03
+#define PCINIT_MODEM_SPEAKER_VOLUME_CHOICES     0x04
+/*------------------------------------------------------------------*/
+#define PCINIT_FAXCONFIG_DISABLE_FINE           0x0001
+#define PCINIT_FAXCONFIG_DISABLE_ECM            0x0002
+#define PCINIT_FAXCONFIG_ECM_64_BYTES           0x0004
+#define PCINIT_FAXCONFIG_DISABLE_2D_CODING      0x0008
+#define PCINIT_FAXCONFIG_DISABLE_T6_CODING      0x0010
+#define PCINIT_FAXCONFIG_DISABLE_UNCOMPR        0x0020
+#define PCINIT_FAXCONFIG_REFUSE_POLLING         0x0040
+#define PCINIT_FAXCONFIG_HIDE_TOTAL_PAGES       0x0080
+#define PCINIT_FAXCONFIG_HIDE_ALL_HEADLINE      0x0100
+#define PCINIT_FAXCONFIG_HIDE_PAGE_INFO         0x0180
+#define PCINIT_FAXCONFIG_HEADLINE_OPTIONS_MASK  0x0180
+#define PCINIT_FAXCONFIG_DISABLE_FEATURE_FALLBACK 0x0200
+#define PCINIT_FAXCONFIG_V34FAX_CONTROL_RATE_1200 0x0800
+#define PCINIT_FAXCONFIG_DISABLE_V34FAX         0x1000
+#define PCINIT_FAXCONFIG_DISABLE_R8_0770_OR_200 0x01
+#define PCINIT_FAXCONFIG_DISABLE_R8_1540        0x02
+#define PCINIT_FAXCONFIG_DISABLE_R16_1540_OR_400 0x04
+#define PCINIT_FAXCONFIG_DISABLE_R4_0385_OR_100 0x08
+#define PCINIT_FAXCONFIG_DISABLE_300_300        0x10
+#define PCINIT_FAXCONFIG_DISABLE_INCH_BASED     0x40
+#define PCINIT_FAXCONFIG_DISABLE_METRIC_BASED   0x80
+#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_A3       0
+#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_B4       1
+#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_A4       2
+#define PCINIT_FAXCONFIG_REC_WIDTH_COUNT        3
+#define PCINIT_FAXCONFIG_REC_LENGTH_UNLIMITED   0
+#define PCINIT_FAXCONFIG_REC_LENGTH_ISO_B4      1
+#define PCINIT_FAXCONFIG_REC_LENGTH_ISO_A4      2
+#define PCINIT_FAXCONFIG_REC_LENGTH_COUNT       3
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_00_00_00 0
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_05_05_05 1
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_05_05 2
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_10_10 3
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_10_10 4
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_20_20 5
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_20_20 6
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_40_40 7
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_8    8
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_9    9
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_10   10
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_10_05 11
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_10_05 12
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_20_10 13
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_20_10 14
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_40_20 15
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_COUNT    16
+#define PCINIT_FAXCONFIG_DISABLE_TX_REDUCTION   0x00010000L
+#define PCINIT_FAXCONFIG_DISABLE_PRECODING      0x00020000L
+#define PCINIT_FAXCONFIG_DISABLE_PREEMPHASIS    0x00040000L
+#define PCINIT_FAXCONFIG_DISABLE_SHAPING        0x00080000L
+#define PCINIT_FAXCONFIG_DISABLE_NONLINEAR_EN   0x00100000L
+#define PCINIT_FAXCONFIG_DISABLE_MANUALREDUCT   0x00200000L
+#define PCINIT_FAXCONFIG_DISABLE_16_POINT_TRN   0x00400000L
+#define PCINIT_FAXCONFIG_DISABLE_2400_SYMBOLS   0x01000000L
+#define PCINIT_FAXCONFIG_DISABLE_2743_SYMBOLS   0x02000000L
+#define PCINIT_FAXCONFIG_DISABLE_2800_SYMBOLS   0x04000000L
+#define PCINIT_FAXCONFIG_DISABLE_3000_SYMBOLS   0x08000000L
+#define PCINIT_FAXCONFIG_DISABLE_3200_SYMBOLS   0x10000000L
+#define PCINIT_FAXCONFIG_DISABLE_3429_SYMBOLS   0x20000000L
+/*--------------------------------------------------------------------------*/
+#define PCINIT_XDI_CMA_FOR_ALL_NL_PRIMITIVES    0x01
+/*--------------------------------------------------------------------------*/
+#define PCINIT_FPGA_PLX_ACCESS_SUPPORTED        0x01
+/*--------------------------------------------------------------------------*/
+#endif
+/*--------------------------------------------------------------------------*/
diff -Nru a/drivers/isdn/hardware/eicon/pc_maint.h b/drivers/isdn/hardware/eicon/pc_maint.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/pc_maint.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,160 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifdef PLATFORM_GT_32BIT
+/* #define POINTER_32BIT byte * __ptr32 */
+#define POINTER_32BIT dword 
+#else
+#define POINTER_32BIT byte *
+#endif
+#if !defined(MIPS_SCOM)
+#define BUFFER_SZ  48
+#define MAINT_OFFS 0x380
+#else
+#define BUFFER_SZ  128
+#if defined(PRI)
+#define MAINT_OFFS 0xef00
+#else
+#define MAINT_OFFS 0xff00
+#endif
+#endif
+#define MIPS_BUFFER_SZ  128
+#if defined(PRI)
+#define MIPS_MAINT_OFFS 0xef00
+#else
+#define MIPS_MAINT_OFFS 0xff00
+#endif
+#define LOG                     1
+#define MEMR                    2
+#define MEMW                    3
+#define IOR                     4
+#define IOW                     5
+#define B1TEST                  6
+#define B2TEST                  7
+#define BTESTOFF                8
+#define DSIG_STATS              9
+#define B_CH_STATS              10
+#define D_CH_STATS              11
+#define BL1_STATS               12
+#define BL1_STATS_C             13
+#define GET_VERSION             14
+#define OS_STATS                15
+#define XLOG_SET_MASK           16
+#define XLOG_GET_MASK           17
+#define DSP_READ                20
+#define DSP_WRITE               21
+#define OK 0xff
+#define MORE_EVENTS 0xfe
+#define NO_EVENT 1
+struct DSigStruc
+{
+  byte Id;
+  byte u;
+  byte listen;
+  byte active;
+  byte sin[3];
+  byte bc[6];
+  byte llc[6];
+  byte hlc[6];
+  byte oad[20];
+};
+struct BL1Struc {
+  dword cx_b1;
+  dword cx_b2;
+  dword cr_b1;
+  dword cr_b2;
+  dword px_b1;
+  dword px_b2;
+  dword pr_b1;
+  dword pr_b2;
+  word er_b1;
+  word er_b2;
+};
+struct L2Struc {
+  dword XTotal;
+  dword RTotal;
+  word XError;
+  word RError;
+};
+struct OSStruc {
+  dword free_n;
+};
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[BUFFER_SZ];
+  word   w[BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[BUFFER_SZ>>2];
+} BUFFER;
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[MIPS_BUFFER_SZ];
+  word   w[MIPS_BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[MIPS_BUFFER_SZ>>2];
+} MIPS_BUFFER;
+#if !defined(MIPS_SCOM)
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  POINTER_32BIT mem;
+  short length;
+  word port;
+  byte fill[6];
+  BUFFER data;
+};
+#else
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  POINTER_32BIT mem;
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  BUFFER data;
+};
+#endif
+struct mi_pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  POINTER_32BIT mem;
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  MIPS_BUFFER data;
+};
diff -Nru a/drivers/isdn/hardware/eicon/pkmaint.h b/drivers/isdn/hardware/eicon/pkmaint.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/pkmaint.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,44 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_XDI_OS_DEPENDENT_PACK_MAIN_ON_BYTE_INC__
+#define __DIVA_XDI_OS_DEPENDENT_PACK_MAIN_ON_BYTE_INC__
+
+
+/*
+	Only one purpose of this compiler dependent file to pack
+	structures, described in pc_maint.h so that no padding
+	will be included.
+
+	With microsoft compile it is done by "pshpack1.h" and
+	after is restored by "poppack.h"
+	*/
+
+
+#include "pc_maint.h"
+
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/platform.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,318 @@
+/* $Id: platform.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $
+ *
+ * platform.h
+ * 
+ *
+ * Copyright 2000-2002  by Armin Schindler (mac@melware.de)
+ * Copyright 2000  Eicon Networks 
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+
+#ifndef	__PLATFORM_H__
+#define	__PLATFORM_H__
+
+#if !defined(DIVA_BUILD)
+#define DIVA_BUILD "local"
+#endif
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "cardtype.h"
+
+#define DIVA_INIT_FUNCTION  __init
+#define DIVA_EXIT_FUNCTION  __exit
+
+#define DIVA_USER_MODE_CARD_CONFIG 1
+#define XDI_USE_XLOG 1
+#define	USE_EXTENDED_DEBUGS 1
+
+#define MAX_ADAPTER     32
+
+#define DIVA_ISTREAM 1
+
+#define MEMORY_SPACE_TYPE  0
+#define PORT_SPACE_TYPE    1
+
+#include "debuglib.h"
+
+#define dtrc(p) DBG_PRV0(p)
+#define dbug(a,p) DBG_PRV1(p)
+
+
+#include <linux/string.h>
+
+#ifndef	byte
+#define	byte   u8
+#endif
+
+#ifndef	word
+#define	word   u16
+#endif
+
+#ifndef	dword
+#define	dword  u32
+#endif
+
+#ifndef	qword
+#define	qword  u64
+#endif
+
+#ifndef	TRUE
+#define	TRUE	1
+#endif
+
+#ifndef	FALSE
+#define	FALSE	0
+#endif
+
+#ifndef	NULL
+#define	NULL	((void *) 0)
+#endif
+
+#ifndef	MIN
+#define MIN(a,b)	((a)>(b) ? (b) : (a))
+#endif
+
+#ifndef	MAX
+#define MAX(a,b)	((a)>(b) ? (a) : (b))
+#endif
+
+#ifndef	far
+#define far
+#endif
+
+#ifndef	_pascal
+#define _pascal
+#endif
+
+#ifndef	_loadds
+#define _loadds
+#endif
+
+#ifndef	_cdecl
+#define _cdecl
+#endif
+
+#if !defined(DIM)
+#define DIM(array)  (sizeof (array)/sizeof ((array)[0]))
+#endif
+
+#define DIVA_INVALID_FILE_HANDLE  ((dword)(-1))
+
+#define DIVAS_CONTAINING_RECORD(address, type, field) \
+        ((type *)((char*)(address) - (char*)(&((type *)0)->field)))
+
+extern int sprintf(char *, const char*, ...);
+
+typedef void* LIST_ENTRY;
+
+typedef char    DEVICE_NAME[64];
+typedef struct _ISDN_ADAPTER   ISDN_ADAPTER;
+typedef struct _ISDN_ADAPTER* PISDN_ADAPTER;
+
+typedef void (* DIVA_DI_PRINTF) (unsigned char *, ...);
+extern DIVA_DI_PRINTF dprintf;
+
+typedef struct e_info_s E_INFO ;
+
+typedef char diva_os_dependent_devica_name_t[64];
+typedef void* PDEVICE_OBJECT;
+
+struct _diva_os_soft_isr;
+struct _diva_os_timer;
+struct _ISDN_ADAPTER;
+
+void diva_log_info(unsigned char *, ...);
+
+/*
+**  XDI DIDD Interface
+*/
+void diva_xdi_didd_register_adapter (int card);
+void diva_xdi_didd_remove_adapter (int card);
+
+/*
+** memory allocation
+*/
+void* diva_os_malloc (unsigned long flags, unsigned long size);
+void  diva_os_free   (unsigned long flags, void* ptr);
+
+/*
+** use skbuffs for message buffer
+*/
+typedef struct sk_buff diva_os_message_buffer_s;
+diva_os_message_buffer_s *diva_os_alloc_message_buffer(unsigned long size, void **data_buf);
+void diva_os_free_message_buffer(diva_os_message_buffer_s *dmb);
+#define DIVA_MESSAGE_BUFFER_LEN(x) x->len
+#define DIVA_MESSAGE_BUFFER_DATA(x) x->data
+
+/*
+** mSeconds waiting
+*/
+void diva_os_sleep(dword mSec);
+void diva_os_wait(dword mSec);
+
+/*
+**  PCI Configuration space access
+*/
+void PCIwrite (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle);
+void PCIread (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle);
+
+/*
+**  I/O Port utilities
+*/
+int diva_os_register_io_port (int register, unsigned long port, unsigned long length, const char* name);
+
+/*
+**  I/O port access abstraction
+*/
+byte inpp (void*);
+word inppw (void*);
+void inppw_buffer (void*, void*, int);
+void outppw (void*, word);
+void outppw_buffer (void* , void*, int);
+void outpp (void*, word);
+
+/*
+**  IRQ 
+*/
+typedef struct _diva_os_adapter_irq_info {
+        byte irq_nr;
+        int  registered;
+        char irq_name[24];
+} diva_os_adapter_irq_info_t;
+int diva_os_register_irq (void* context, byte irq, const char* name);
+void diva_os_remove_irq (void* context, byte irq);
+
+#define diva_os_in_irq() in_irq()
+
+/*
+** module locking
+*/
+#define DIVA_LOCK_MODULE MOD_INC_USE_COUNT
+#define DIVA_UNLOCK_MODULE MOD_DEC_USE_COUNT
+
+/*
+**  Spin Lock framework
+*/
+typedef long diva_os_spin_lock_magic_t;
+typedef spinlock_t diva_os_spin_lock_t;
+static __inline__ int diva_os_initialize_spin_lock (spinlock_t *lock, void * unused) { \
+  spin_lock_init (lock); return(0); }
+static __inline__ void diva_os_enter_spin_lock (diva_os_spin_lock_t* a, \
+                              diva_os_spin_lock_magic_t* old_irql, \
+                              void* dbg) { spin_lock_bh(a); }
+static __inline__ void diva_os_leave_spin_lock (diva_os_spin_lock_t* a, \
+                              diva_os_spin_lock_magic_t* old_irql, \
+                              void* dbg) { spin_unlock_bh(a); }
+
+static __inline__ void diva_os_enter_spin_lock_hard (diva_os_spin_lock_t* a, \
+                                   diva_os_spin_lock_magic_t* old_irql, \
+                                   void* dbg) { \
+  unsigned long flags; \
+  spin_lock_irqsave (a, flags); \
+  *old_irql = (diva_os_spin_lock_magic_t)flags; \
+}
+static __inline__ void diva_os_leave_spin_lock_hard (diva_os_spin_lock_t* a, \
+                                   diva_os_spin_lock_magic_t* old_irql, \
+                                   void* dbg) { \
+  unsigned long flags = (unsigned long)*old_irql; \
+	spin_unlock_irqrestore (a, flags); \
+}
+
+#define diva_os_destroy_spin_lock(a,b) do { } while(0)
+
+/*
+**  Deffered processing framework
+*/
+typedef int (*diva_os_isr_callback_t)(struct _ISDN_ADAPTER*);
+typedef void (*diva_os_soft_isr_callback_t)(struct _diva_os_soft_isr* psoft_isr, void* context);
+
+typedef struct _diva_os_soft_isr {
+  void* object;
+  diva_os_soft_isr_callback_t callback;
+  void* callback_context;
+  char dpc_thread_name[24];
+} diva_os_soft_isr_t;
+
+int diva_os_initialize_soft_isr (diva_os_soft_isr_t* psoft_isr, diva_os_soft_isr_callback_t callback, void*   callback_context);
+int diva_os_schedule_soft_isr (diva_os_soft_isr_t* psoft_isr);
+int diva_os_cancel_soft_isr (diva_os_soft_isr_t* psoft_isr);
+void diva_os_remove_soft_isr (diva_os_soft_isr_t* psoft_isr);
+
+/*
+  Get time service
+  */
+void diva_os_get_time (dword* sec, dword* usec);
+
+/*
+**  atomic operation, fake because we use threads
+*/
+typedef int diva_os_atomic_t;
+static diva_os_atomic_t __inline__
+diva_os_atomic_increment(diva_os_atomic_t* pv)
+{
+  *pv += 1;
+  return (*pv);
+}
+static diva_os_atomic_t __inline__
+diva_os_atomic_decrement(diva_os_atomic_t* pv)
+{
+  *pv -= 1;
+  return (*pv);
+}
+
+/* 
+**  CAPI SECTION
+*/
+#define NO_CORNETN
+#define IMPLEMENT_DTMF 1
+#define IMPLEMENT_LINE_INTERCONNECT2 1
+#define IMPLEMENT_ECHO_CANCELLER 1
+#define IMPLEMENT_RTP 1
+#define IMPLEMENT_T38 1
+#define IMPLEMENT_FAX_SUB_SEP_PWD 1
+#define IMPLEMENT_V18 1
+#define IMPLEMENT_DTMF_TONE 1
+#define IMPLEMENT_PIAFS 1
+#define IMPLEMENT_FAX_PAPER_FORMATS 1
+#define IMPLEMENT_VOWN 1
+#define IMPLEMENT_CAPIDTMF 1
+#define IMPLEMENT_FAX_NONSTANDARD 1
+#define VSWITCH_SUPPORT 1
+
+#define IMPLEMENT_LINE_INTERCONNECT  0
+#define IMPLEMENT_MARKED_OK_AFTER_FC 1
+
+#define DIVA_IDI_RX_DMA 1
+
+#define READ_WORD(addr)   readw(addr)
+#define READ_DWORD(addr)  readl(addr)
+
+#define WRITE_WORD(addr,v)  writew(v,addr)
+#define WRITE_DWORD(addr,v) writel(v,addr)
+
+#ifdef BITS_PER_LONG
+ #if BITS_PER_LONG > 32 
+  #define PLATFORM_GT_32BIT
+  #define ULongToPtr(x) (void *)(unsigned long)(x)
+ #endif
+#endif
+
+#undef ID_MASK
+#undef N_DATA
+#undef ADDR
+
+#endif	/* __PLATFORM_H__ */
diff -Nru a/drivers/isdn/hardware/eicon/pr_pc.h b/drivers/isdn/hardware/eicon/pr_pc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/pr_pc.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,76 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+struct pr_ram {
+  word NextReq;         /* pointer to next Req Buffer               */
+  word NextRc;          /* pointer to next Rc Buffer                */
+  word NextInd;         /* pointer to next Ind Buffer               */
+  byte ReqInput;        /* number of Req Buffers sent               */
+  byte ReqOutput;       /* number of Req Buffers returned           */
+  byte ReqReserved;     /* number of Req Buffers reserved           */
+  byte Int;             /* ISDN-P interrupt                         */
+  byte XLock;           /* Lock field for arbitration               */
+  byte RcOutput;        /* number of Rc buffers received            */
+  byte IndOutput;       /* number of Ind buffers received           */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte Reserved1[2];    /* reserved field, do not use               */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte Reserved2[12];   /* reserved field, do not use               */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-P initialized indication            */
+  byte B[1];            /* buffer space for Req,Ind and Rc          */
+};
+typedef struct {
+  word next;
+  byte Req;
+  byte ReqId;
+  byte ReqCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved[8];
+  PBUFFER XBuffer;
+} REQ;
+typedef struct {
+  word next;
+  byte Rc;
+  byte RcId;
+  byte RcCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved2[8];
+} RC;
+typedef struct {
+  word next;
+  byte Ind;
+  byte IndId;
+  byte IndCh;
+  byte MInd;
+  word MLength;
+  word Reference;
+  byte RNR;
+  byte Reserved;
+  dword Ack;
+  PBUFFER RBuffer;
+} IND;
diff -Nru a/drivers/isdn/hardware/eicon/s_4bri.c b/drivers/isdn/hardware/eicon/s_4bri.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/s_4bri.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,953 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "divasync.h"
+#include "pc_init.h"
+#include "io.h"
+#include "helpers.h"
+#include "dsrv4bri.h"
+#include "dsp_defs.h"
+#include "sdp_hdr.h"
+
+/*****************************************************************************/
+#define	MAX_XLOG_SIZE	(64 * 1024)
+
+/* --------------------------------------------------------------------------
+		Recovery XLOG from QBRI Card
+	 -------------------------------------------------------------------------- */
+static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
+	byte  *base ;
+	word *Xlog ;
+	dword   regs[4], TrapID, offset, size ;
+	Xdesc   xlogDesc ;
+	int factor = (IoAdapter->tasks == 1) ? 1 : 2;
+
+/*
+ *	check for trapped MIPS 46xx CPU, dump exception frame
+ */
+
+	offset = IoAdapter->ControllerNumber * (IoAdapter->MemorySize >> factor) ;
+	base   = IoAdapter->ram - offset - ((IoAdapter->MemorySize >> factor) - MQ_SHARED_RAM_SIZE) ;
+
+	TrapID = READ_DWORD(&base[0x80]) ;
+
+	if ( (TrapID == 0x99999999) || (TrapID == 0x99999901) )
+	{
+		dump_trap_frame (IoAdapter, &base[0x90]) ;
+		IoAdapter->trapped = 1 ;
+	}
+
+	regs[0] = READ_DWORD((&base + offset) + 0x70);
+	regs[1] = READ_DWORD((&base + offset) + 0x74);
+	regs[2] = READ_DWORD((&base + offset) + 0x78);
+	regs[3] = READ_DWORD((&base + offset) + 0x7c);
+	regs[0] &= IoAdapter->MemorySize - 1 ;
+
+	if ( (regs[0] >= offset)
+	  && (regs[0] < offset + (IoAdapter->MemorySize >> factor) - 1) )
+	{
+		if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) )
+			return ;
+
+		size = offset + (IoAdapter->MemorySize >> factor) - regs[0] ;
+		if ( size > MAX_XLOG_SIZE )
+			size = MAX_XLOG_SIZE ;
+		memcpy (Xlog, &base[regs[0]], size) ;
+		xlogDesc.buf = Xlog ;
+		xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
+		xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
+		dump_xlog_buffer (IoAdapter, &xlogDesc) ;
+		diva_os_free (0, Xlog) ;
+		IoAdapter->trapped = 2 ;
+	}
+
+}
+
+/* --------------------------------------------------------------------------
+		Reset QBRI Hardware
+	 -------------------------------------------------------------------------- */
+static void reset_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	word volatile *qBriReset ;
+	dword  volatile *qBriCntrl ;
+
+	qBriReset = (word volatile *)IoAdapter->prom ;
+	qBriCntrl = (dword volatile *)(&IoAdapter->ctlReg[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)]);
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_SOFT_RESET) ;
+	diva_os_wait (1) ;
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_SOFT_RESET) ;
+	diva_os_wait (1);
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_RELOAD_EEPROM) ;
+	diva_os_wait (1) ;
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_RELOAD_EEPROM) ;
+	diva_os_wait (1);
+
+	WRITE_DWORD(qBriCntrl, 0) ;
+
+	DBG_TRC(("resetted board @ reset addr 0x%08lx", qBriReset))
+	DBG_TRC(("resetted board @ cntrl addr 0x%08lx", qBriCntrl))
+
+}
+
+/* --------------------------------------------------------------------------
+		Start Card CPU
+	 -------------------------------------------------------------------------- */
+void start_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	dword volatile *qBriReset ;
+
+	qBriReset = (dword volatile *)(&IoAdapter->ctlReg[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)]);
+	WRITE_DWORD(qBriReset, MQ_RISC_COLD_RESET_MASK) ;
+	diva_os_wait (2) ;
+	WRITE_DWORD(qBriReset, MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK) ;
+	diva_os_wait (10) ;
+
+	DBG_TRC(("started processor @ addr 0x%08lx", qBriReset))
+
+}
+
+/* --------------------------------------------------------------------------
+		Stop Card CPU
+	 -------------------------------------------------------------------------- */
+static void stop_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	dword volatile *qBriReset ;
+	dword volatile *qBriIrq ;
+	dword volatile *qBriIsacDspReset ;
+	int rev2 = DIVA_4BRI_REVISION(IoAdapter);
+	int reset_offset = rev2 ? (MQ2_BREG_RISC)      : (MQ_BREG_RISC);
+	int irq_offset   = rev2 ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST);
+	int hw_offset    = rev2 ? (MQ2_ISAC_DSP_RESET) : (MQ_ISAC_DSP_RESET);
+
+	if ( IoAdapter->ControllerNumber > 0 )
+		return ;
+ qBriReset = (dword volatile *)(&IoAdapter->ctlReg[reset_offset]) ;
+ qBriIrq   = (dword volatile *)(&IoAdapter->ctlReg[irq_offset]) ;
+ qBriIsacDspReset = (dword volatile *)(&IoAdapter->ctlReg[hw_offset]);
+/*
+ *	clear interrupt line (reset Local Interrupt Test Register)
+ */
+	WRITE_DWORD(qBriReset, 0) ;
+ 	WRITE_DWORD(qBriIsacDspReset, 0) ;
+	IoAdapter->reset[PLX9054_INTCSR] = 0x00 ;	/* disable PCI interrupts */
+	WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
+
+	DBG_TRC(("stopped processor @ addr 0x%08lx", qBriReset))
+
+}
+
+/* --------------------------------------------------------------------------
+		FPGA download
+	 -------------------------------------------------------------------------- */
+#define FPGA_NAME_OFFSET         0x10
+
+static byte * qBri_check_FPGAsrc (PISDN_ADAPTER IoAdapter, char *FileName,
+                                  dword *Length, dword *code) {
+	byte *File ;
+	char  *fpgaFile, *fpgaType, *fpgaDate, *fpgaTime ;
+	dword  fpgaFlen,  fpgaTlen,  fpgaDlen, cnt, year, i ;
+
+	if (!(File = (byte *)xdiLoadFile (FileName, Length, 0))) {
+		return (NULL) ;
+	}
+/*
+ *	 scan file until FF and put id string into buffer
+ */
+	for ( i = 0 ; File[i] != 0xff ; )
+	{
+		if ( ++i >= *Length )
+		{
+			DBG_FTL(("FPGA download: start of data header not found"))
+			xdiFreeFile (File) ;
+			return (NULL) ;
+		}
+	}
+	*code = i++ ;
+
+	if ( (File[i] & 0xF0) != 0x20 )
+	{
+		DBG_FTL(("FPGA download: data header corrupted"))
+		xdiFreeFile (File) ;
+		return (NULL) ;
+	}
+	fpgaFlen = (dword)  File[FPGA_NAME_OFFSET - 1] ;
+	if ( fpgaFlen == 0 )
+		fpgaFlen = 12 ;
+	fpgaFile = (char *)&File[FPGA_NAME_OFFSET] ;
+	fpgaTlen = (dword)  fpgaFile[fpgaFlen + 2] ;
+	if ( fpgaTlen == 0 )
+		fpgaTlen = 10 ;
+	fpgaType = (char *)&fpgaFile[fpgaFlen + 3] ;
+	fpgaDlen = (dword)  fpgaType[fpgaTlen + 2] ;
+	if ( fpgaDlen == 0 )
+		fpgaDlen = 11 ;
+	fpgaDate = (char *)&fpgaType[fpgaTlen + 3] ;
+	fpgaTime = (char *)&fpgaDate[fpgaDlen + 3] ;
+	cnt = (dword)(((File[  i  ] & 0x0F) << 20) + (File[i + 1] << 12)
+	             + (File[i + 2]         <<  4) + (File[i + 3] >>  4)) ;
+
+	if ( (dword)(i + (cnt / 8)) > *Length )
+	{
+		DBG_FTL(("FPGA download: '%s' file too small (%ld < %ld)",
+		         FileName, *Length, code + ((cnt + 7) / 8) ))
+		xdiFreeFile (File) ;
+		return (NULL) ;
+	}
+	i = 0 ;
+	do
+	{
+		while ( (fpgaDate[i] != '\0')
+		     && ((fpgaDate[i] < '0') || (fpgaDate[i] > '9')) )
+		{
+			i++;
+		}
+		year = 0 ;
+		while ( (fpgaDate[i] >= '0') && (fpgaDate[i] <= '9') )
+			year = year * 10 + (fpgaDate[i++] - '0') ;
+	} while ( (year < 2000) && (fpgaDate[i] != '\0') );
+
+	switch (IoAdapter->cardType) {
+		case CARDTYPE_DIVASRV_B_2F_PCI:
+			break;
+
+		default:
+	    if ( year >= 2001 ) {
+				IoAdapter->fpga_features |= PCINIT_FPGA_PLX_ACCESS_SUPPORTED ;
+			}
+	}
+
+	DBG_LOG(("FPGA[%s] file %s (%s %s) len %d",
+	         fpgaType, fpgaFile, fpgaDate, fpgaTime, cnt))
+	return (File) ;
+}
+
+/******************************************************************************/
+
+#define FPGA_PROG   0x0001		// PROG enable low
+#define FPGA_BUSY   0x0002		// BUSY high, DONE low
+#define	FPGA_CS     0x000C		// Enable I/O pins
+#define FPGA_CCLK   0x0100
+#define FPGA_DOUT   0x0400
+#define FPGA_DIN    FPGA_DOUT   // bidirectional I/O
+
+int qBri_FPGA_download (PISDN_ADAPTER IoAdapter) {
+	int            bit ;
+	byte           *File ;
+	dword          code, FileLength ;
+	word volatile *addr = (word volatile *)IoAdapter->prom ;
+	word           val, baseval = FPGA_CS | FPGA_PROG ;
+
+
+
+	if (DIVA_4BRI_REVISION(IoAdapter))
+	{
+		char* name;
+
+		switch (IoAdapter->cardType) {
+			case CARDTYPE_DIVASRV_B_2F_PCI:
+				name = "dsbri2f.bit";
+				break;
+
+			case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+			case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+				name = "dsbri2m.bit";
+				break;
+
+			default:
+				name = "ds4bri2.bit";
+		}
+
+		File = qBri_check_FPGAsrc (IoAdapter, name,
+	                           		&FileLength, &code);
+	}
+	else
+	{
+		File = qBri_check_FPGAsrc (IoAdapter, "ds4bri.bit",
+		                           &FileLength, &code) ;
+	}
+	if ( !File )
+		return (0) ;
+/*
+ *	prepare download, pulse PROGRAM pin down.
+ */
+	WRITE_WORD(addr, baseval & ~FPGA_PROG) ; // PROGRAM low pulse
+	WRITE_WORD(addr, baseval) ;              // release
+	diva_os_wait (50) ;  // wait until FPGA finished internal memory clear
+/*
+ *	check done pin, must be low
+ */
+	if ( READ_WORD(addr) & FPGA_BUSY )
+	{
+		DBG_FTL(("FPGA download: acknowledge for FPGA memory clear missing"))
+		xdiFreeFile (File) ;
+		return (0) ;
+	}
+/*
+ *	put data onto the FPGA
+ */
+	while ( code < FileLength )
+	{
+		val = ((word)File[code++]) << 3 ;
+
+		for ( bit = 8 ; bit-- > 0 ; val <<= 1 ) // put byte onto FPGA
+		{
+			baseval &= ~FPGA_DOUT ;             // clr  data bit
+			baseval |= (val & FPGA_DOUT) ;      // copy data bit
+			WRITE_WORD(addr, baseval) ;
+			WRITE_WORD(addr, baseval | FPGA_CCLK) ;     // set CCLK hi
+			WRITE_WORD(addr, baseval | FPGA_CCLK) ;     // set CCLK hi
+			WRITE_WORD(addr, baseval) ;                 // set CCLK lo
+		}
+	}
+	xdiFreeFile (File) ;
+	diva_os_wait (100) ;
+	val = READ_WORD(addr) ;
+
+	if ( !(val & FPGA_BUSY) )
+	{
+		DBG_FTL(("FPGA download: chip remains in busy state (0x%04x)", val))
+		return (0) ;
+	}
+
+	return (1) ;
+}
+
+#if !defined(DIVA_USER_MODE_CARD_CONFIG) /* { */
+/* --------------------------------------------------------------------------
+		Download protocol code to the adapter
+	 -------------------------------------------------------------------------- */
+
+#define	DOWNLOAD_ADDR(IoAdapter) (&IoAdapter->ram[IoAdapter->downloadAddr & (IoAdapter->MemorySize - 1)])
+
+
+static int qBri_protocol_load (PISDN_ADAPTER BaseIoAdapter, PISDN_ADAPTER IoAdapter) {
+	PISDN_ADAPTER HighIoAdapter;
+
+	dword  FileLength ;
+	dword *sharedRam, *File;
+	dword  Addr, ProtOffset, SharedRamOffset, i;
+	dword tasks = BaseIoAdapter->tasks ;
+	int factor = (tasks == 1) ? 1 : 2;
+
+	if (!(File = (dword *)xdiLoadArchive (IoAdapter, &FileLength, 0))) {
+		return (0) ;
+	}
+
+	IoAdapter->features = diva_get_protocol_file_features ((byte*)File,
+	                                       OFFS_PROTOCOL_ID_STRING,
+	                                       IoAdapter->ProtocolIdString,
+	                                       sizeof(IoAdapter->ProtocolIdString)) ;
+	IoAdapter->a.protocol_capabilities = IoAdapter->features ;
+
+	DBG_LOG(("Loading %s", IoAdapter->ProtocolIdString))
+
+	ProtOffset = IoAdapter->ControllerNumber * (IoAdapter->MemorySize >> factor);
+	SharedRamOffset = (IoAdapter->MemorySize >> factor) - MQ_SHARED_RAM_SIZE;
+	Addr = ((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR]))
+	  | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 1])) << 8)
+	  | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 2])) << 16)
+	  | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 3])) << 24) ;
+        if ( Addr != 0 )
+	{
+		IoAdapter->DspCodeBaseAddr = (Addr + 3) & (~3) ;
+		IoAdapter->MaxDspCodeSize = (MQ_UNCACHED_ADDR (ProtOffset + SharedRamOffset) -
+										IoAdapter->DspCodeBaseAddr) & ((IoAdapter->MemorySize >> factor) - 1);
+
+		i = 0 ;
+		while ( BaseIoAdapter->QuadroList->QuadroAdapter[i]->ControllerNumber != tasks - 1 )
+			i++ ;
+		HighIoAdapter = BaseIoAdapter->QuadroList->QuadroAdapter[i] ;
+		Addr = HighIoAdapter->DspCodeBaseAddr ;
+
+		if (tasks == 1) {
+			((byte *) File)[OFFS_DIVA_INIT_TASK_COUNT]   =(byte)1;
+			((byte *) File)[OFFS_DIVA_INIT_TASK_COUNT+1] = (byte)BaseIoAdapter->cardType;
+		}
+
+		((byte *) File)[OFFS_DSP_CODE_BASE_ADDR] = (byte) Addr ;
+		((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 1] = (byte)(Addr >> 8) ;
+		((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 2] = (byte)(Addr >> 16) ;
+		((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 3] = (byte)(Addr >> 24) ;
+		IoAdapter->InitialDspInfo = 0x80 ;
+	}
+	else
+	{
+		if ( IoAdapter->features & PROTCAP_VOIP )
+		{
+			IoAdapter->DspCodeBaseAddr = MQ_CACHED_ADDR (ProtOffset + SharedRamOffset - MQ_VOIP_MAX_DSP_CODE_SIZE) ;
+
+			IoAdapter->MaxDspCodeSize = MQ_VOIP_MAX_DSP_CODE_SIZE ;
+
+		}
+		else if ( IoAdapter->features & PROTCAP_V90D )
+		{
+			IoAdapter->DspCodeBaseAddr = MQ_CACHED_ADDR (ProtOffset + SharedRamOffset - MQ_V90D_MAX_DSP_CODE_SIZE) ;
+
+			IoAdapter->MaxDspCodeSize = (IoAdapter->ControllerNumber == tasks - 1) ? MQ_V90D_MAX_DSP_CODE_SIZE : 0 ;
+
+		}
+		else
+		{
+			IoAdapter->DspCodeBaseAddr = MQ_CACHED_ADDR (ProtOffset + SharedRamOffset - MQ_ORG_MAX_DSP_CODE_SIZE) ;
+
+			IoAdapter->MaxDspCodeSize = (IoAdapter->ControllerNumber == tasks - 1) ? MQ_ORG_MAX_DSP_CODE_SIZE : 0 ;
+
+		}
+		IoAdapter->InitialDspInfo = (MQ_CACHED_ADDR (ProtOffset + SharedRamOffset -
+															MQ_ORG_MAX_DSP_CODE_SIZE) - IoAdapter->DspCodeBaseAddr) >> 14 ;
+
+	}
+	DBG_LOG(("%d: DSP code base 0x%08lx, max size 0x%08lx (%08lx,%02x)",
+	         IoAdapter->ControllerNumber,
+	         IoAdapter->DspCodeBaseAddr, IoAdapter->MaxDspCodeSize,
+	         Addr, IoAdapter->InitialDspInfo))
+
+	if (FileLength > ((IoAdapter->DspCodeBaseAddr - MQ_CACHED_ADDR (ProtOffset)) & (IoAdapter->MemorySize - 1)) )
+	{
+		xdiFreeFile (File) ;
+		DBG_FTL(("Protocol code '%s' too long (%ld)",
+		         &IoAdapter->Protocol[0], FileLength))
+		return (0) ;
+	}
+	IoAdapter->downloadAddr = 0 ;
+	sharedRam = (dword *)DOWNLOAD_ADDR(IoAdapter) ;
+	memcpy (sharedRam, File, FileLength) ;
+
+	DBG_TRC(("Download addr 0x%08x len %ld - virtual 0x%08x",
+	         IoAdapter->downloadAddr, FileLength, sharedRam))
+
+	if ( memcmp (sharedRam, File, FileLength) )
+	{
+		DBG_FTL(("%s: Memory test failed!", IoAdapter->Properties.Name))
+
+		DBG_FTL(("File=0x%x, sharedRam=0x%x", File, sharedRam))
+		DBG_BLK(( (char *)File, 256))
+		DBG_BLK(( (char *)sharedRam, 256))
+
+		xdiFreeFile (File) ;
+		return (0) ;
+	}
+	xdiFreeFile (File) ;
+
+	return (1) ;
+}
+
+/* --------------------------------------------------------------------------
+		DSP Code download
+	 -------------------------------------------------------------------------- */
+static long qBri_download_buffer (OsFileHandle *fp, long length, void **addr) {
+	PISDN_ADAPTER BaseIoAdapter = (PISDN_ADAPTER)fp->sysLoadDesc ;
+	PISDN_ADAPTER IoAdapter;
+	word        i ;
+	dword       *sharedRam ;
+
+	i = 0 ;
+
+	do
+	{
+		IoAdapter = BaseIoAdapter->QuadroList->QuadroAdapter[i++] ;
+	} while ( (i < BaseIoAdapter->tasks)
+	       && (((dword) length) > IoAdapter->DspCodeBaseAddr +
+	                IoAdapter->MaxDspCodeSize - IoAdapter->downloadAddr) );
+
+	*addr = (void *)IoAdapter->downloadAddr ;
+	if ( ((dword) length) > IoAdapter->DspCodeBaseAddr +
+	                        IoAdapter->MaxDspCodeSize - IoAdapter->downloadAddr )
+	{
+		DBG_FTL(("%s: out of card memory during DSP download (0x%X)",
+		         IoAdapter->Properties.Name,
+		         IoAdapter->downloadAddr + length))
+		return (-1) ;
+	}
+	sharedRam = (dword*)(&BaseIoAdapter->ram[IoAdapter->downloadAddr &
+	                                         (IoAdapter->MemorySize - 1)]) ;
+
+
+	if ( fp->sysFileRead (fp, sharedRam, length) != length )
+		return (-1) ;
+
+	IoAdapter->downloadAddr += length ;
+	IoAdapter->downloadAddr  = (IoAdapter->downloadAddr + 3) & (~3) ;
+
+	return (0) ;
+}
+
+/******************************************************************************/
+
+static dword qBri_telindus_load (PISDN_ADAPTER BaseIoAdapter) {
+	PISDN_ADAPTER        IoAdapter = 0;
+	PISDN_ADAPTER        HighIoAdapter = NULL ;
+	char                *error ;
+	OsFileHandle        *fp ;
+	t_dsp_portable_desc  download_table[DSP_MAX_DOWNLOAD_COUNT] ;
+	word                 download_count, i ;
+	dword               *sharedRam ;
+	dword                FileLength ;
+
+	if ( !(fp = OsOpenFile (DSP_TELINDUS_FILE)) ) {
+		DBG_FTL(("qBri_telindus_load: %s not found!", DSP_TELINDUS_FILE))
+		return (0) ;
+	}
+
+
+	for ( i = 0 ; i < BaseIoAdapter->tasks ; ++i )
+	{
+		IoAdapter = BaseIoAdapter->QuadroList->QuadroAdapter[i] ;
+		IoAdapter->downloadAddr = IoAdapter->DspCodeBaseAddr ;
+		if ( IoAdapter->ControllerNumber == BaseIoAdapter->tasks - 1 )
+		{
+			HighIoAdapter = IoAdapter ;
+			HighIoAdapter->downloadAddr = (HighIoAdapter->downloadAddr
+			           + sizeof(dword) + sizeof(download_table) + 3) & (~3) ;
+		}
+	}
+
+
+	FileLength      = fp->sysFileSize ;
+	fp->sysLoadDesc = (void *)BaseIoAdapter ;
+	fp->sysCardLoad = qBri_download_buffer ;
+
+	download_count = DSP_MAX_DOWNLOAD_COUNT ;
+	memset (&download_table[0], '\0', sizeof(download_table)) ;
+/*
+ *	set start address for download
+ */
+	error = dsp_read_file (fp, (word)(IoAdapter->cardType),
+	                       &download_count, NULL, &download_table[0]) ;
+	if ( error )
+	{
+		DBG_FTL(("download file error: %s", error))
+		OsCloseFile (fp) ;
+		return (0) ;
+	}
+	OsCloseFile (fp) ;
+
+
+	/*
+	 *	store # of download files extracted from the archive and download table
+	 */
+		HighIoAdapter->downloadAddr = HighIoAdapter->DspCodeBaseAddr ;
+		sharedRam = (dword *)(&BaseIoAdapter->ram[HighIoAdapter->downloadAddr &
+		                                          (IoAdapter->MemorySize - 1)]) ;
+		WRITE_DWORD(&(sharedRam[0]), (dword)download_count);
+		memcpy (&sharedRam[1], &download_table[0], sizeof(download_table)) ;
+
+
+	/* memory check */
+	if ( memcmp (&sharedRam[1], &download_table, download_count) ) {
+		DBG_FTL(("%s: Dsp Memory test failed!", IoAdapter->Properties.Name))
+	}
+
+	return (FileLength) ;
+}
+
+/*
+	Load SDP tasks to the card
+	Return start address of image on succesful load
+	Return zero in case of problem
+
+	INPUT:
+		task			->	name of the image containing this task
+		link_addr	->	pointer to start of previous task
+	*/
+static byte* qBri_sdp_load (PISDN_ADAPTER BaseIoAdapter,
+													char* task,
+													byte*	link_addr) {
+	OsFileHandle *fp;
+	dword FileLength;
+	byte tmp[sizeof(dword)];
+	dword gp_addr;
+	dword entry_addr;
+	dword start_addr = 0;
+	dword phys_start_addr;
+	dword end_addr;
+	byte* sharedRam = 0;
+
+  if (task) {
+		if (!(fp = OsOpenFile (task))) {
+			DBG_ERR(("Can't open [%s] image", task))
+			return (0);
+		}
+		if ((FileLength = fp->sysFileSize) < DIVA_MIPS_TASK_IMAGE_ID_STRING_OFFS) {
+			OsCloseFile (fp) ;
+			DBG_ERR(("Image [%s] too short", task))
+			return (0);
+		}
+
+		fp->sysFileSeek (fp, DIVA_MIPS_TASK_IMAGE_GP_OFFS, OS_SEEK_SET);
+		if (fp->sysFileRead (fp, tmp, sizeof(dword)) != sizeof(dword)) {
+			OsCloseFile (fp) ;
+			DBG_ERR(("Can't read image [%s]", task))
+			return (0);
+		}
+		gp_addr = ((dword)tmp[0])					|
+							(((dword)tmp[1]) << 8)	|
+							(((dword)tmp[2]) << 16) |
+							(((dword)tmp[3]) << 24);
+		DBG_TRC(("Image [%s] GP = %08lx", task, gp_addr))
+
+		fp->sysFileSeek (fp, DIVA_MIPS_TASK_IMAGE_ENTRY_OFFS, OS_SEEK_SET);
+		if (fp->sysFileRead (fp, tmp, sizeof(dword)) != sizeof(dword)) {
+			OsCloseFile (fp) ;
+			DBG_ERR(("Can't read image [%s]", task))
+			return (0);
+		}
+		entry_addr = ((dword)tmp[0])					|
+									(((dword)tmp[1]) << 8)	|
+									(((dword)tmp[2]) << 16) |
+									(((dword)tmp[3]) << 24);
+		DBG_TRC(("Image [%s] entry = %08lx", task, entry_addr))
+
+		fp->sysFileSeek (fp, DIVA_MIPS_TASK_IMAGE_LOAD_ADDR_OFFS, OS_SEEK_SET);
+		if (fp->sysFileRead (fp, tmp, sizeof(dword)) != sizeof(dword)) {
+			OsCloseFile (fp) ;
+			DBG_ERR(("Can't read image [%s]", task))
+			return (0);
+		}
+		start_addr = ((dword)tmp[0])					|
+									(((dword)tmp[1]) << 8)	|
+									(((dword)tmp[2]) << 16) |
+									(((dword)tmp[3]) << 24);
+		DBG_TRC(("Image [%s] start = %08lx", task, start_addr))
+
+		fp->sysFileSeek (fp, DIVA_MIPS_TASK_IMAGE_END_ADDR_OFFS, OS_SEEK_SET);
+		if (fp->sysFileRead (fp, tmp, sizeof(dword)) != sizeof(dword)) {
+			OsCloseFile (fp) ;
+			DBG_ERR(("Can't read image [%s]", task))
+			return (0);
+		}
+		end_addr = ((dword)tmp[0])					|
+								(((dword)tmp[1]) << 8)	|
+								(((dword)tmp[2]) << 16) |
+								(((dword)tmp[3]) << 24);
+		DBG_TRC(("Image [%s] end = %08lx", task, end_addr))
+
+		phys_start_addr = start_addr & 0x1fffffff;
+
+		if ((phys_start_addr + FileLength) >= BaseIoAdapter->MemorySize) {
+			OsCloseFile (fp) ;
+			DBG_ERR(("Image [%s] too long", task))
+			return (0);
+		}
+
+		fp->sysFileSeek (fp, 0, OS_SEEK_SET);
+		sharedRam = &BaseIoAdapter->ram[phys_start_addr];
+		if ((dword)fp->sysFileRead (fp, sharedRam, FileLength) != FileLength) {
+			OsCloseFile (fp) ;
+			DBG_ERR(("Can't read image [%s]", task))
+			return (0);
+		}
+
+		OsCloseFile (fp) ;
+  }
+
+	if (!link_addr) {
+		link_addr = &BaseIoAdapter->ram[OFFS_DSP_CODE_BASE_ADDR];
+	}
+
+	DBG_TRC(("Write task [%s] link %08lx at %08lx",
+						task ? task : "none",
+						start_addr,
+						link_addr - (byte*)&BaseIoAdapter->ram[0]))
+
+	link_addr[0] = (byte)(start_addr         & 0xff);
+	link_addr[1] = (byte)((start_addr >>  8) & 0xff);
+	link_addr[2] = (byte)((start_addr >> 16) & 0xff);
+	link_addr[3] = (byte)((start_addr >> 24) & 0xff);
+
+	return (task ? &sharedRam[DIVA_MIPS_TASK_IMAGE_LINK_OFFS] : 0);
+}
+
+/* --------------------------------------------------------------------------
+		Load Card
+	 -------------------------------------------------------------------------- */
+static int load_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	dword         i, offset, controller ;
+	word         *signature ;
+	int           factor = (IoAdapter->tasks == 1) ? 1 : 2;
+
+	PISDN_ADAPTER Slave ;
+
+
+	if (
+
+		!IoAdapter->QuadroList
+
+	  || ( (IoAdapter->cardType != CARDTYPE_DIVASRV_Q_8M_PCI)
+	    && (IoAdapter->cardType != CARDTYPE_DIVASRV_VOICE_Q_8M_PCI)
+	    && (IoAdapter->cardType != CARDTYPE_DIVASRV_Q_8M_V2_PCI)
+     && (IoAdapter->cardType != CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI)
+     && (IoAdapter->cardType != CARDTYPE_DIVASRV_B_2M_V2_PCI)
+     && (IoAdapter->cardType != CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI)
+     && (IoAdapter->cardType != CARDTYPE_DIVASRV_B_2F_PCI) ) )
+	{
+		return (0) ;
+	}
+
+/*
+ *	Check for first instance
+ */
+	if ( IoAdapter->ControllerNumber > 0 )
+		return (1) ;
+
+/*
+ *	first initialize the onboard FPGA
+ */
+	if ( !qBri_FPGA_download (IoAdapter) )
+		return (0) ;
+
+
+	for ( i = 0; i < IoAdapter->tasks; i++ )
+	{
+		Slave = IoAdapter->QuadroList->QuadroAdapter[i] ;
+		Slave->fpga_features = IoAdapter->fpga_features ;
+	}
+
+
+/*
+ *	download protocol code for all instances
+ */
+
+	controller = IoAdapter->tasks;
+	do
+	{
+		controller-- ;
+		i = 0 ;
+		while ( IoAdapter->QuadroList->QuadroAdapter[i]->ControllerNumber != controller )
+			i++ ;
+/*
+ *	calculate base address for instance
+ */
+		Slave          = IoAdapter->QuadroList->QuadroAdapter[i] ;
+		offset         = Slave->ControllerNumber * (IoAdapter->MemorySize >> factor) ;
+		Slave->Address = &IoAdapter->Address[offset] ;
+		Slave->ram     = &IoAdapter->ram[offset] ;
+		Slave->reset   = IoAdapter->reset ;
+		Slave->ctlReg  = IoAdapter->ctlReg ;
+		Slave->prom    = IoAdapter->prom ;
+		Slave->reset   = IoAdapter->reset ;
+
+		if ( !qBri_protocol_load (IoAdapter, Slave) )
+			return (0) ;
+
+	} while (controller != 0) ;
+
+
+/*
+ *	download only one copy of the DSP code
+ */
+ if (IoAdapter->cardType != CARDTYPE_DIVASRV_B_2F_PCI) {
+	if ( !qBri_telindus_load (IoAdapter) )
+		return (0) ;
+ } else {
+   byte* link_addr = 0;
+   link_addr = qBri_sdp_load (IoAdapter, DIVA_BRI2F_SDP_1_NAME, link_addr);
+   link_addr = qBri_sdp_load (IoAdapter, DIVA_BRI2F_SDP_2_NAME, link_addr);
+   if (!link_addr) {
+     qBri_sdp_load (IoAdapter, 0, link_addr);
+   }
+ }
+
+/*
+ *	copy configuration parameters
+ */
+
+	for ( i = 0 ; i < IoAdapter->tasks ; ++i )
+	{
+		Slave = IoAdapter->QuadroList->QuadroAdapter[i] ;
+		Slave->ram += (IoAdapter->MemorySize >> factor) - MQ_SHARED_RAM_SIZE ;
+		DBG_TRC(("Configure instance %d shared memory @ 0x%08lx",
+		         Slave->ControllerNumber, Slave->ram))
+		memset (Slave->ram, '\0', 256) ;
+		diva_configure_protocol (Slave);
+	}
+
+/*
+ *	start adapter
+ */
+	start_qBri_hardware (IoAdapter) ;
+	signature = (word *)(&IoAdapter->ram[0x1E]) ;
+/*
+ *	wait for signature in shared memory (max. 3 seconds)
+ */
+	for ( i = 0 ; i < 300 ; ++i )
+	{
+		diva_os_wait (10) ;
+
+		if ( signature[0] == 0x4447 )
+		{
+			DBG_TRC(("Protocol startup time %d.%02d seconds",
+			         (i / 100), (i % 100) ))
+
+			return (1) ;
+		}
+	}
+	DBG_FTL(("%s: Adapter selftest failed (0x%04X)!",
+	         IoAdapter->Properties.Name, signature[0] >> 16))
+	qBri_cpu_trapped (IoAdapter) ;
+	return (FALSE) ;
+}
+#else /* } { */
+static int load_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	return (0);
+}
+#endif /* } */
+
+/* --------------------------------------------------------------------------
+		Card ISR
+	 -------------------------------------------------------------------------- */
+static int qBri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
+	dword volatile     *qBriIrq ;
+
+	PADAPTER_LIST_ENTRY QuadroList = IoAdapter->QuadroList ;
+
+	word              	i ;
+	int             	serviced = 0 ;
+
+
+	if ( !(IoAdapter->reset[PLX9054_INTCSR] & 0x80) )
+		return (0) ;
+
+/*
+ *	clear interrupt line (reset Local Interrupt Test Register)
+ */
+	qBriIrq = (dword volatile *)(&IoAdapter->ctlReg[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
+	WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
+
+	for ( i = 0 ; i < IoAdapter->tasks; ++i )
+	{
+		IoAdapter = QuadroList->QuadroAdapter[i] ;
+
+		if ( IoAdapter && IoAdapter->Initialized
+		  && IoAdapter->tst_irq (&IoAdapter->a) )
+		{
+			IoAdapter->IrqCount++ ;
+			serviced = 1 ;
+			diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
+		}
+	}
+
+	return (serviced) ;
+}
+
+/* --------------------------------------------------------------------------
+		Does disable the interrupt on the card
+	 -------------------------------------------------------------------------- */
+static void disable_qBri_interrupt (PISDN_ADAPTER IoAdapter) {
+	dword volatile *qBriIrq ;
+
+	if ( IoAdapter->ControllerNumber > 0 )
+		return ;
+	qBriIrq = (dword volatile *)(&IoAdapter->ctlReg[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
+/*
+ *	clear interrupt line (reset Local Interrupt Test Register)
+ */
+	IoAdapter->reset[PLX9054_INTCSR] = 0x00 ;	// disable PCI interrupts
+	WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
+}
+
+/* --------------------------------------------------------------------------
+		Install Adapter Entry Points
+	 -------------------------------------------------------------------------- */
+static void set_common_qBri_functions (PISDN_ADAPTER IoAdapter) {
+	ADAPTER *a;
+
+	a = &IoAdapter->a ;
+
+	a->ram_in           = mem_in ;
+	a->ram_inw          = mem_inw ;
+	a->ram_in_buffer    = mem_in_buffer ;
+	a->ram_look_ahead   = mem_look_ahead ;
+	a->ram_out          = mem_out ;
+	a->ram_outw         = mem_outw ;
+	a->ram_out_buffer   = mem_out_buffer ;
+	a->ram_inc          = mem_inc ;
+
+	IoAdapter->out      = pr_out ;
+	IoAdapter->dpc      = pr_dpc ;
+	IoAdapter->tst_irq  = scom_test_int ;
+	IoAdapter->clr_irq  = scom_clear_int ;
+	IoAdapter->pcm      = (struct pc_maint *)MIPS_MAINT_OFFS ;
+
+	IoAdapter->load     = load_qBri_hardware ;
+
+	IoAdapter->disIrq   = disable_qBri_interrupt ;
+	IoAdapter->rstFnc   = reset_qBri_hardware ;
+	IoAdapter->stop     = stop_qBri_hardware ;
+	IoAdapter->trapFnc  = qBri_cpu_trapped ;
+
+	IoAdapter->diva_isr_handler = qBri_ISR;
+
+	IoAdapter->a.io       = (void*)IoAdapter ;
+}
+
+static void set_qBri_functions (PISDN_ADAPTER IoAdapter) {
+	if (!IoAdapter->tasks) {
+		IoAdapter->tasks = MQ_INSTANCE_COUNT;
+	}
+	IoAdapter->MemorySize = MQ_MEMORY_SIZE ;
+	set_common_qBri_functions (IoAdapter) ;
+	diva_os_set_qBri_functions (IoAdapter) ;
+}
+
+static void set_qBri2_functions (PISDN_ADAPTER IoAdapter) {
+	if (!IoAdapter->tasks) {
+		IoAdapter->tasks = MQ_INSTANCE_COUNT;
+	}
+	IoAdapter->MemorySize = (IoAdapter->tasks == 1) ? BRI2_MEMORY_SIZE : MQ2_MEMORY_SIZE;
+	set_common_qBri_functions (IoAdapter) ;
+	diva_os_set_qBri2_functions (IoAdapter) ;
+}
+
+/******************************************************************************/
+
+void prepare_qBri_functions (PISDN_ADAPTER IoAdapter) {
+
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;
+
+}
+
+void prepare_qBri2_functions (PISDN_ADAPTER IoAdapter) {
+	if (!IoAdapter->tasks) {
+		IoAdapter->tasks = MQ_INSTANCE_COUNT;
+	}
+
+	set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
+	if (IoAdapter->tasks > 1) {
+		set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
+		set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
+		set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;
+	}
+
+}
+
+/* -------------------------------------------------------------------------- */
diff -Nru a/drivers/isdn/hardware/eicon/s_bri.c b/drivers/isdn/hardware/eicon/s_bri.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/s_bri.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,497 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "divasync.h"
+#include "io.h"
+#include "helpers.h"
+#include "dsrv_bri.h"
+#include "dsp_defs.h"
+/*****************************************************************************/
+#define MAX_XLOG_SIZE (64 * 1024)
+/* --------------------------------------------------------------------------
+  Investigate card state, recovery trace buffer
+  -------------------------------------------------------------------------- */
+static void bri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
+ byte  *addrHi, *addrLo, *ioaddr ;
+ word *Xlog ;
+ dword   regs[4], i, size ;
+ Xdesc   xlogDesc ;
+/*
+ * first read pointers and trap frame
+ */
+ if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) )
+  return ;
+ addrHi =   IoAdapter->port
+   + ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH) ;
+ addrLo = IoAdapter->port + ADDR ;
+ ioaddr = IoAdapter->port + DATA ;
+ outpp (addrHi,  0) ;
+ outppw (addrLo, 0) ;
+ for ( i = 0 ; i < 0x100 ; Xlog[i++] = inppw(ioaddr) ) ;
+/*
+ * check for trapped MIPS 3xxx CPU, dump only exception frame
+ */
+ if ( READ_WORD(&Xlog[0x80 / sizeof(Xlog[0])]) == 0x99999999 )
+ {
+  dump_trap_frame (IoAdapter, &((byte *)Xlog)[0x90]) ;
+  IoAdapter->trapped = 1 ;
+ }
+ regs[0] = READ_DWORD(&((byte *)Xlog)[0x70]);
+ regs[1] = READ_DWORD(&((byte *)Xlog)[0x74]);
+ regs[2] = READ_DWORD(&((byte *)Xlog)[0x78]);
+ regs[3] = READ_DWORD(&((byte *)Xlog)[0x7c]);
+ outpp (addrHi, (regs[1] >> 16) & 0x7F) ;
+ outppw (addrLo, regs[1] & 0xFFFF) ;
+ xlogDesc.cnt = inppw(ioaddr) ;
+ outpp (addrHi, (regs[2] >> 16) & 0x7F) ;
+ outppw (addrLo, regs[2] & 0xFFFF) ;
+ xlogDesc.out = inppw(ioaddr) ;
+ xlogDesc.buf = Xlog ;
+ regs[0] &= IoAdapter->MemorySize - 1 ;
+ if ( (regs[0] < IoAdapter->MemorySize - 1) )
+ {
+  size = IoAdapter->MemorySize - regs[0] ;
+  if ( size > MAX_XLOG_SIZE )
+   size = MAX_XLOG_SIZE ;
+  for ( i = 0 ; i < (size / sizeof(*Xlog)) ; regs[0] += 2 )
+  {
+   outpp (addrHi, (regs[0] >> 16) & 0x7F) ;
+   outppw (addrLo, regs[0] & 0xFFFF) ;
+   Xlog[i++] = inppw(ioaddr) ;
+  }
+  dump_xlog_buffer (IoAdapter, &xlogDesc) ;
+  diva_os_free (0, Xlog) ;
+  IoAdapter->trapped = 2 ;
+ }
+ outpp  (addrHi, (byte)((BRI_UNCACHED_ADDR (IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                                            BRI_SHARED_RAM_SIZE)) >> 16)) ;
+ outppw (addrLo, 0x00) ;
+}
+/* ---------------------------------------------------------------------
+   Reset hardware
+  --------------------------------------------------------------------- */
+static void reset_bri_hardware (PISDN_ADAPTER IoAdapter) {
+ outpp (IoAdapter->ctlReg, 0x00) ;
+}
+/* ---------------------------------------------------------------------
+   Halt system
+  --------------------------------------------------------------------- */
+static void stop_bri_hardware (PISDN_ADAPTER IoAdapter) {
+ if (IoAdapter->reset) {
+  outpp (IoAdapter->reset, 0x00) ; /* disable interrupts ! */
+ }
+ outpp (IoAdapter->ctlReg, 0x00) ;    /* clear int, halt cpu */
+}
+#if !defined(DIVA_USER_MODE_CARD_CONFIG) /* { */
+/* ---------------------------------------------------------------------
+  Load protocol on the card
+  --------------------------------------------------------------------- */
+static dword bri_protocol_load (PISDN_ADAPTER IoAdapter) {
+ dword   FileLength ;
+ word    test, *File = NULL ;
+ byte*  addrHi, *addrLo, *ioaddr ;
+ char   *FileName = &IoAdapter->Protocol[0] ;
+ dword   Addr, i ;
+ /* -------------------------------------------------------------------
+   Try to load protocol code. 'File' points to memory location
+   that does contain entire protocol code
+   ------------------------------------------------------------------- */
+ if ( !(File = (word *)xdiLoadArchive (IoAdapter, &FileLength, 0)) )
+  return (0) ;
+ /* -------------------------------------------------------------------
+   Get protocol features and calculate load addresses
+   ------------------------------------------------------------------- */
+ IoAdapter->features = diva_get_protocol_file_features ((byte*)File,
+                     OFFS_PROTOCOL_ID_STRING,
+                     IoAdapter->ProtocolIdString,
+                     sizeof(IoAdapter->ProtocolIdString));
+ IoAdapter->a.protocol_capabilities = IoAdapter->features ;
+ DBG_LOG(("Loading %s", IoAdapter->ProtocolIdString))
+ Addr = ((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR]))
+   | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 1])) << 8)
+   | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 2])) << 16)
+   | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 3])) << 24) ;
+        if ( Addr != 0 )
+ {
+  IoAdapter->DspCodeBaseAddr = (Addr + 3) & (~3) ;
+  IoAdapter->MaxDspCodeSize = (BRI_UNCACHED_ADDR (IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                                                  BRI_SHARED_RAM_SIZE)
+                            - IoAdapter->DspCodeBaseAddr) & (IoAdapter->MemorySize - 1) ;
+  Addr = IoAdapter->DspCodeBaseAddr ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR] = (byte) Addr ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 1] = (byte)(Addr >> 8) ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 2] = (byte)(Addr >> 16) ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 3] = (byte)(Addr >> 24) ;
+  IoAdapter->InitialDspInfo = 0x80 ;
+ }
+ else
+ {
+  if ( IoAdapter->features & PROTCAP_V90D )
+   IoAdapter->MaxDspCodeSize = BRI_V90D_MAX_DSP_CODE_SIZE ;
+  else
+   IoAdapter->MaxDspCodeSize = BRI_ORG_MAX_DSP_CODE_SIZE ;
+  IoAdapter->DspCodeBaseAddr = BRI_CACHED_ADDR (IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                                                BRI_SHARED_RAM_SIZE - IoAdapter->MaxDspCodeSize);
+  IoAdapter->InitialDspInfo = (IoAdapter->MaxDspCodeSize - BRI_ORG_MAX_DSP_CODE_SIZE) >> 14 ;
+ }
+ DBG_LOG(("DSP code base 0x%08lx, max size 0x%08lx (%08lx,%02x)",
+      IoAdapter->DspCodeBaseAddr, IoAdapter->MaxDspCodeSize,
+      Addr, IoAdapter->InitialDspInfo))
+ if ( FileLength > ((IoAdapter->DspCodeBaseAddr -
+                     BRI_CACHED_ADDR (IoAdapter->MemoryBase)) & (IoAdapter->MemorySize - 1)) )
+ {
+  xdiFreeFile (File);
+  DBG_FTL(("Protocol code '%s' too big (%ld)", FileName, FileLength))
+  return (0) ;
+ }
+ addrHi =   IoAdapter->port
+        + ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH) ;
+ addrLo = IoAdapter->port + ADDR ;
+ ioaddr = IoAdapter->port + DATA ;
+/*
+ * set start address for download (use autoincrement mode !)
+ */
+ outpp  (addrHi, 0) ;
+ outppw (addrLo, 0) ;
+ for ( i = 0 ; i < FileLength ; i += 2 )
+ {
+  if ( (i & 0x0000FFFF) == 0 )
+  {
+   outpp (addrHi, (byte)(i >> 16)) ;
+  }
+  outppw (ioaddr, File[i/2]) ;
+ }
+/*
+ * memory test without second load of file
+ */
+ outpp  (addrHi, 0) ;
+ outppw (addrLo, 0) ;
+ for ( i = 0 ; i < FileLength ; i += 2 )
+ {
+  if ( (i & 0x0000FFFF) == 0 )
+  {
+   outpp (addrHi, (byte)(i >> 16)) ;
+  }
+  test = inppw (ioaddr) ;
+  if ( test != File[i/2] )
+  {
+   DBG_FTL(("%s: Memory test failed! (%d - 0x%04X/0x%04X)",
+            IoAdapter->Properties.Name, i, test, File[i/2]))
+   xdiFreeFile (File);
+   return (0) ;
+  }
+ }
+ xdiFreeFile (File);
+ return (FileLength) ;
+}
+/******************************************************************************/
+typedef struct
+{
+ PISDN_ADAPTER IoAdapter ;
+ byte*        AddrLo ;
+ byte*        AddrHi ;
+ word*       Data ;
+ dword         DownloadPos ;
+} bri_download_info ;
+static long bri_download_buffer (OsFileHandle *fp, long length, void **addr) {
+ int        buffer_size = 2048*sizeof(word);
+ word       *buffer = (word*)diva_os_malloc (0, buffer_size);
+ bri_download_info *info ;
+ word       test ;
+ long       i, len, page ;
+ if (!buffer) {
+  DBG_ERR(("A: out of memory, s_bri at %d", __LINE__))
+  return (-1);
+ }
+ info = (bri_download_info *)fp->sysLoadDesc ;
+ *addr = (void *)info->DownloadPos ;
+ if ( ((dword) length) > info->IoAdapter->DspCodeBaseAddr +
+                         info->IoAdapter->MaxDspCodeSize - info->DownloadPos )
+ {
+  DBG_FTL(("%s: out of card memory during DSP download (0x%X)",
+           info->IoAdapter->Properties.Name,
+           info->DownloadPos + length))
+  diva_os_free (0, buffer);
+  return (-1) ;
+ }
+ for ( len = 0 ; length > 0 ; length -= len )
+ {
+  len = (length > buffer_size ? buffer_size : length) ;
+  page = ((long)(info->DownloadPos) + len) & 0xFFFF0000 ;
+  if ( page != (long)(info->DownloadPos & 0xFFFF0000) )
+  {
+   len = 0x00010000 - (((long)info->DownloadPos) & 0x0000FFFF) ;
+  }
+  if ( fp->sysFileRead (fp, &buffer[0], len) != len ) {
+   diva_os_free (0, buffer);
+   return (-1) ;
+  }
+  outpp (info->AddrHi, (byte)(info->DownloadPos >> 16)) ;
+  outppw (info->AddrLo, (word)info->DownloadPos) ;
+  outppw_buffer (info->Data, &buffer[0], (len + 1)) ;
+/*
+ * memory test without second load of file
+ */
+  outpp (info->AddrHi, (byte)(info->DownloadPos >> 16)) ;
+  outppw (info->AddrLo, (word)info->DownloadPos) ;
+  for ( i = 0 ; i < len ; i += 2 )
+  {
+   if ( (test = inppw (info->Data)) != buffer[i/2] )
+   {
+    DBG_FTL(("%s: Memory test failed! (0x%lX - 0x%04X/0x%04X)",
+             info->IoAdapter->Properties.Name,
+             info->DownloadPos + i, test, buffer[i/2]))
+    diva_os_free (0, buffer);
+    return (-2) ;
+   }
+  }
+  info->DownloadPos += len ;
+ }
+ info->DownloadPos = (info->DownloadPos + 3) & (~3) ;
+ diva_os_free (0, buffer);
+ return (0) ;
+}
+/******************************************************************************/
+static dword bri_telindus_load (PISDN_ADAPTER IoAdapter, char *DspTelindusFile) 
+{
+ bri_download_info    *pinfo =\
+             (bri_download_info*)diva_os_malloc(0, sizeof(*pinfo));
+ char                *error ;
+ OsFileHandle        *fp ;
+ t_dsp_portable_desc  download_table[DSP_MAX_DOWNLOAD_COUNT] ;
+ word                 download_count ;
+ dword                FileLength ;
+ if (!pinfo) {
+  DBG_ERR (("A: out of memory s_bri at %d", __LINE__))
+  return (0);
+ }
+ if (!(fp = OsOpenFile (DspTelindusFile))) {
+  diva_os_free (0, pinfo);
+  return (0) ;
+ }
+ FileLength     = fp->sysFileSize ;
+ pinfo->IoAdapter = IoAdapter ;
+ pinfo->AddrLo    = IoAdapter->port + ADDR ;
+ pinfo->AddrHi    = IoAdapter->port +\
+     (IoAdapter->Properties.Bus == BUS_PCI ? M_PCI_ADDRH : ADDRH);
+ pinfo->Data = (word*)(IoAdapter->port + DATA) ;
+ pinfo->DownloadPos = (IoAdapter->DspCodeBaseAddr +\
+           sizeof(dword) + sizeof(download_table) + 3) & (~3) ;
+ fp->sysLoadDesc = (void *)pinfo;
+ fp->sysCardLoad = bri_download_buffer ;
+ download_count = DSP_MAX_DOWNLOAD_COUNT ;
+ memset (&download_table[0], '\0', sizeof(download_table)) ;
+/*
+ * set start address for download (use autoincrement mode !)
+ */
+ error = dsp_read_file (fp, (word)(IoAdapter->cardType),
+                        &download_count, NULL, &download_table[0]) ;
+ if ( error )
+ {
+  DBG_FTL(("download file error: %s", error))
+  OsCloseFile (fp) ;
+  diva_os_free (0, pinfo);
+  return (0) ;
+ }
+ OsCloseFile (fp) ;
+/*
+ * store # of separate download files extracted from archive
+ */
+ pinfo->DownloadPos = IoAdapter->DspCodeBaseAddr ;
+ outpp  (pinfo->AddrHi, (byte)(pinfo->DownloadPos >> 16)) ;
+ outppw (pinfo->AddrLo, (word)pinfo->DownloadPos) ;
+ outppw (pinfo->Data,   (word)download_count) ;
+ outppw (pinfo->Data,   (word)0) ;
+/*
+ * copy download table to board
+ */
+ outppw_buffer (pinfo->Data, &download_table[0], sizeof(download_table)) ;
+ diva_os_free (0, pinfo);
+ return (FileLength) ;
+}
+/******************************************************************************/
+static int load_bri_hardware (PISDN_ADAPTER IoAdapter) {
+ dword   i ;
+ byte*  addrHi, *addrLo, *ioaddr ;
+ dword   test ;
+ if ( IoAdapter->Properties.Card != CARD_MAE )
+ {
+  return (FALSE) ;
+ }
+ addrHi =   IoAdapter->port \
+    + ((IoAdapter->Properties.Bus==BUS_PCI) ? M_PCI_ADDRH : ADDRH);
+ addrLo = IoAdapter->port + ADDR ;
+ ioaddr = IoAdapter->port + DATA ;
+ reset_bri_hardware (IoAdapter) ;
+ diva_os_wait (100);
+/*
+ * recover
+ */
+ outpp  (addrHi, (byte) 0) ;
+ outppw (addrLo, (word) 0) ;
+ outppw (ioaddr, (word) 0) ;
+/*
+ * clear shared memory
+ */
+ outpp  (addrHi, (byte)((BRI_UNCACHED_ADDR (IoAdapter->MemoryBase + \
+          IoAdapter->MemorySize - BRI_SHARED_RAM_SIZE)) >> 16)) ;
+ outppw (addrLo, 0) ;
+ for ( i = 0 ; i < 0x8000 ; outppw (ioaddr, 0), ++i ) ;
+ diva_os_wait (100) ;
+/*
+ * download protocol and dsp files
+ */
+ switch ( IoAdapter->protocol_id ) {
+ default:
+  if ( !xdiSetProtocol (IoAdapter, IoAdapter->ProtocolSuffix) )
+   return (FALSE) ;
+  if ( !bri_protocol_load (IoAdapter) )
+   return (FALSE) ;
+  if ( !bri_telindus_load (IoAdapter, DSP_TELINDUS_FILE) )
+   return (FALSE) ;
+  break ;
+ case PROTTYPE_QSIG:
+ case PROTTYPE_CORNETN:
+  if ( !xdiSetProtocol (IoAdapter, IoAdapter->ProtocolSuffix) )
+   return (FALSE) ;
+  if (IoAdapter->ProtocolSuffix && *IoAdapter->ProtocolSuffix) {
+   sprintf (&IoAdapter->Protocol[0],
+        "TE_QSIG.%s", IoAdapter->ProtocolSuffix) ;
+  }
+  DBG_TRC(("xdiSetProtocol: %s firmware '%s' archive '%s'",
+     IoAdapter->Properties.Name,
+     &IoAdapter->Protocol[0], &IoAdapter->Archive[0]))
+  if ( !bri_protocol_load (IoAdapter) )
+   return (FALSE) ;
+  if ( !bri_telindus_load (IoAdapter, DSP_QSIG_TELINDUS_FILE) )
+   return (FALSE) ;
+  break ;
+ }
+/*
+ * clear signature
+ */
+ outpp  (addrHi, (byte)((BRI_UNCACHED_ADDR (IoAdapter->MemoryBase + \
+     IoAdapter->MemorySize - BRI_SHARED_RAM_SIZE)) >> 16)) ;
+ outppw (addrLo, 0x1e) ;
+ outpp (ioaddr, 0) ;
+ outpp (ioaddr, 0) ;
+/*
+ * copy parameters
+ */
+ diva_configure_protocol (IoAdapter);
+/*
+ * start the protocol code
+ */
+ outpp (IoAdapter->ctlReg, 0x08) ;
+/*
+ * wait for signature (max. 3 seconds)
+ */
+ for ( i = 0 ; i < 300 ; ++i )
+ {
+  diva_os_wait (10) ;
+  outpp (addrHi, (byte)((BRI_UNCACHED_ADDR (IoAdapter->MemoryBase + \
+      IoAdapter->MemorySize - BRI_SHARED_RAM_SIZE)) >> 16)) ;
+  outppw (addrLo, 0x1e) ;
+  test = (dword)inppw (ioaddr) ;
+  if ( test == 0x4447 )
+  {
+   DBG_TRC(("Protocol startup time %d.%02d seconds",
+            (i / 100), (i % 100) ))
+   return (TRUE) ;
+  }
+ }
+ DBG_FTL(("%s: Adapter selftest failed (0x%04X)!",
+          IoAdapter->Properties.Name, test))
+ bri_cpu_trapped (IoAdapter) ;
+ return (FALSE) ;
+}
+#else /* } { */
+static int load_bri_hardware (PISDN_ADAPTER IoAdapter) {
+ return (0);
+}
+#endif /* } */
+/******************************************************************************/
+static int bri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
+ if ( !(inpp (IoAdapter->ctlReg) & 0x01) )
+  return (0) ;
+ /*
+  clear interrupt line
+  */
+ outpp (IoAdapter->ctlReg, 0x08) ;
+ IoAdapter->IrqCount++ ;
+ if ( IoAdapter->Initialized ) {
+  diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
+ }
+ return (1) ;
+}
+/* --------------------------------------------------------------------------
+  Disable IRQ in the card hardware
+  -------------------------------------------------------------------------- */
+static void disable_bri_interrupt (PISDN_ADAPTER IoAdapter) {
+ if ( IoAdapter->reset )
+ {
+  outpp (IoAdapter->reset, 0x00) ; // disable interrupts !
+ }
+ outpp (IoAdapter->ctlReg, 0x00) ;    // clear int, halt cpu
+}
+/* -------------------------------------------------------------------------
+  Fill card entry points
+  ------------------------------------------------------------------------- */
+void prepare_maestra_functions (PISDN_ADAPTER IoAdapter) {
+ ADAPTER *a = &IoAdapter->a ;
+ a->ram_in             = io_in ;
+ a->ram_inw            = io_inw ;
+ a->ram_in_buffer      = io_in_buffer ;
+ a->ram_look_ahead     = io_look_ahead ;
+ a->ram_out            = io_out ;
+ a->ram_outw           = io_outw ;
+ a->ram_out_buffer     = io_out_buffer ;
+ a->ram_inc            = io_inc ;
+ IoAdapter->MemoryBase = BRI_MEMORY_BASE ;
+ IoAdapter->MemorySize = BRI_MEMORY_SIZE ;
+ IoAdapter->out        = pr_out ;
+ IoAdapter->dpc        = pr_dpc ;
+ IoAdapter->tst_irq    = scom_test_int ;
+ IoAdapter->clr_irq    = scom_clear_int ;
+ IoAdapter->pcm        = (struct pc_maint *)MIPS_MAINT_OFFS ;
+ IoAdapter->load       = load_bri_hardware ;
+ IoAdapter->disIrq     = disable_bri_interrupt ;
+ IoAdapter->rstFnc     = reset_bri_hardware ;
+ IoAdapter->stop       = stop_bri_hardware ;
+ IoAdapter->trapFnc    = bri_cpu_trapped ;
+ IoAdapter->diva_isr_handler = bri_ISR;
+ /*
+  Prepare OS dependent functions
+  */
+ diva_os_prepare_maestra_functions (IoAdapter);
+}
+/* -------------------------------------------------------------------------- */
diff -Nru a/drivers/isdn/hardware/eicon/s_pri.c b/drivers/isdn/hardware/eicon/s_pri.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/s_pri.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,520 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "divasync.h"
+#include "io.h"
+#include "helpers.h"
+#include "dsrv_pri.h"
+#include "dsp_defs.h"
+/*****************************************************************************/
+#define MAX_XLOG_SIZE  (64 * 1024)
+/* -------------------------------------------------------------------------
+  Does return offset between ADAPTER->ram and real begin of memory
+  ------------------------------------------------------------------------- */
+static dword pri_ram_offset (ADAPTER* a) {
+ return ((dword)MP_SHARED_RAM_OFFSET);
+}
+/* -------------------------------------------------------------------------
+  Recovery XLOG buffer from the card
+  ------------------------------------------------------------------------- */
+static void pri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
+ byte  *base ;
+ word *Xlog ;
+ dword   regs[4], TrapID, size ;
+ Xdesc   xlogDesc ;
+/*
+ * check for trapped MIPS 46xx CPU, dump exception frame
+ */
+ base   = IoAdapter->ram - MP_SHARED_RAM_OFFSET ;
+ TrapID = READ_DWORD(&base[0x80]) ;
+ if ( (TrapID == 0x99999999) || (TrapID == 0x99999901) )
+ {
+  dump_trap_frame (IoAdapter, &base[0x90]) ;
+  IoAdapter->trapped = 1 ;
+ }
+ regs[0] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x70]);
+ regs[1] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x74]);
+ regs[2] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x78]);
+ regs[3] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x7c]);
+ regs[0] &= IoAdapter->MemorySize - 1 ;
+ if ( (regs[0] < IoAdapter->MemorySize - 1) )
+ {
+  if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) )
+   return ;
+  size = IoAdapter->MemorySize - regs[0] ;
+  if ( size > MAX_XLOG_SIZE )
+   size = MAX_XLOG_SIZE ;
+  memcpy (Xlog, &base[regs[0]], size) ;
+  xlogDesc.buf = Xlog ;
+  xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
+  xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
+  dump_xlog_buffer (IoAdapter, &xlogDesc) ;
+  diva_os_free (0, Xlog) ;
+  IoAdapter->trapped = 2 ;
+ }
+}
+/* -------------------------------------------------------------------------
+  Hardware reset of PRI card
+  ------------------------------------------------------------------------- */
+static void reset_pri_hardware (PISDN_ADAPTER IoAdapter) {
+ *IoAdapter->reset = _MP_RISC_RESET | _MP_LED1 | _MP_LED2 ;
+ diva_os_wait (50) ;
+ *IoAdapter->reset = 0x00 ;
+ diva_os_wait (50) ;
+}
+/* -------------------------------------------------------------------------
+  Stop Card Hardware
+  ------------------------------------------------------------------------- */
+static void stop_pri_hardware (PISDN_ADAPTER IoAdapter) {
+ dword i;
+ dword volatile *cfgReg = (dword volatile *)IoAdapter->cfg ;
+ cfgReg[3] = 0x00000000 ;
+ cfgReg[1] = 0x00000000 ;
+ IoAdapter->a.ram_out (&IoAdapter->a, &RAM->SWReg, SWREG_HALT_CPU) ;
+ i = 0 ;
+ while ( (i < 100) && (IoAdapter->a.ram_in (&IoAdapter->a, &RAM->SWReg) != 0) )
+ {
+  diva_os_wait (1) ;
+  i++ ;
+ }
+ DBG_TRC(("%s: PRI stopped (%d)", IoAdapter->Name, i))
+ WRITE_DWORD(&cfgReg[0],((dword)(~0x03E00000)));
+ diva_os_wait (1) ;
+ *IoAdapter->reset = _MP_RISC_RESET | _MP_LED1 | _MP_LED2 ;
+}
+#if !defined(DIVA_USER_MODE_CARD_CONFIG) /* { */
+/* -------------------------------------------------------------------------
+  Load protocol code to the PRI Card
+  ------------------------------------------------------------------------- */
+#define DOWNLOAD_ADDR(IoAdapter) \
+ (&IoAdapter->ram[IoAdapter->downloadAddr & (IoAdapter->MemorySize - 1)])
+static int pri_protocol_load (PISDN_ADAPTER IoAdapter) {
+ dword  FileLength ;
+ dword *File ;
+ dword *sharedRam ;
+ dword  Addr ;
+ if (!(File = (dword *)xdiLoadArchive (IoAdapter, &FileLength, 0))) {
+  return (0) ;
+ }
+ IoAdapter->features = diva_get_protocol_file_features ((byte*)File,
+                                        OFFS_PROTOCOL_ID_STRING,
+                                        IoAdapter->ProtocolIdString,
+                                        sizeof(IoAdapter->ProtocolIdString)) ;
+ IoAdapter->a.protocol_capabilities = IoAdapter->features ;
+ DBG_LOG(("Loading %s", IoAdapter->ProtocolIdString))
+ Addr = ((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR]))
+   | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 1])) << 8)
+   | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 2])) << 16)
+   | (((dword)(((byte *) File)[OFFS_PROTOCOL_END_ADDR + 3])) << 24) ;
+        if ( Addr != 0 )
+ {
+  IoAdapter->DspCodeBaseAddr = (Addr + 3) & (~3) ;
+  IoAdapter->MaxDspCodeSize = (MP_UNCACHED_ADDR (IoAdapter->MemorySize)
+                            - IoAdapter->DspCodeBaseAddr) & (IoAdapter->MemorySize - 1) ;
+  Addr = IoAdapter->DspCodeBaseAddr ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR] = (byte) Addr ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 1] = (byte)(Addr >> 8) ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 2] = (byte)(Addr >> 16) ;
+  ((byte *) File)[OFFS_DSP_CODE_BASE_ADDR + 3] = (byte)(Addr >> 24) ;
+  IoAdapter->InitialDspInfo = 0x80 ;
+ }
+ else
+ {
+  if ( IoAdapter->features & PROTCAP_VOIP )
+   IoAdapter->MaxDspCodeSize = MP_VOIP_MAX_DSP_CODE_SIZE ;
+  else if ( IoAdapter->features & PROTCAP_V90D )
+   IoAdapter->MaxDspCodeSize = MP_V90D_MAX_DSP_CODE_SIZE ;
+  else
+   IoAdapter->MaxDspCodeSize = MP_ORG_MAX_DSP_CODE_SIZE ;
+  IoAdapter->DspCodeBaseAddr = MP_CACHED_ADDR (IoAdapter->MemorySize -
+                                               IoAdapter->MaxDspCodeSize) ;
+  IoAdapter->InitialDspInfo = (IoAdapter->MaxDspCodeSize
+                            - MP_ORG_MAX_DSP_CODE_SIZE) >> 14 ;
+ }
+ DBG_LOG(("DSP code base 0x%08lx, max size 0x%08lx (%08lx,%02x)",
+          IoAdapter->DspCodeBaseAddr, IoAdapter->MaxDspCodeSize,
+          Addr, IoAdapter->InitialDspInfo))
+ if ( FileLength > ((IoAdapter->DspCodeBaseAddr -
+                     MP_CACHED_ADDR (MP_PROTOCOL_OFFSET)) & (IoAdapter->MemorySize - 1)) )
+ {
+  xdiFreeFile (File);
+  DBG_FTL(("Protocol code '%s' too long (%ld)",
+           &IoAdapter->Protocol[0], FileLength))
+  return (0) ;
+ }
+ IoAdapter->downloadAddr = MP_UNCACHED_ADDR (MP_PROTOCOL_OFFSET) ;
+ sharedRam = (dword *)DOWNLOAD_ADDR(IoAdapter) ;
+ memcpy (sharedRam, File, FileLength) ;
+ if ( memcmp (sharedRam, File, FileLength) )
+ {
+  DBG_FTL(("%s: Memory test failed!", IoAdapter->Properties.Name))
+  xdiFreeFile (File);
+  return (0) ;
+ }
+ xdiFreeFile (File);
+ return (1) ;
+}
+/******************************************************************************/
+/*------------------------------------------------------------------
+  Dsp related definitions
+  ------------------------------------------------------------------ */
+#define DSP_SIGNATURE_PROBE_WORD 0x5a5a
+/*
+**  Checks presence of DSP on board
+*/
+static int
+dsp_check_presence (volatile byte* addr, volatile byte* data, int dsp)
+{
+  word pattern;
+  *(volatile word*)addr = 0x4000;
+  *(volatile word*)data = DSP_SIGNATURE_PROBE_WORD;
+  *(volatile word*)addr = 0x4000;
+  pattern = *(volatile word*)data;
+  if (pattern != DSP_SIGNATURE_PROBE_WORD) {
+    DBG_TRC(("W: DSP[%d] %04x(is) != %04x(should)",
+              dsp, pattern, DSP_SIGNATURE_PROBE_WORD))
+    return (-1);
+  }
+  *(volatile word*)addr = 0x4000;
+  *(volatile word*)data = ~DSP_SIGNATURE_PROBE_WORD;
+  *(volatile word*)addr = 0x4000;
+  pattern = *(volatile word*)data;
+  if (pattern != (word)~DSP_SIGNATURE_PROBE_WORD) {
+    DBG_ERR(("A: DSP[%d] %04x(is) != %04x(should)",
+              dsp, pattern, (word)~DSP_SIGNATURE_PROBE_WORD))
+    return (-2);
+  }
+  DBG_TRC (("DSP[%d] present", dsp))
+  return (0);
+}
+/*
+**  Check if DSP's are present and operating
+**  Information about detected DSP's is returned as bit mask
+**  Bit 0  - DSP1
+**  ...
+**  ...
+**  ...
+**  Bit 29 - DSP30
+*/
+static dword
+diva_pri_detect_dsps (PISDN_ADAPTER IoAdapter)
+{
+//  byte* base = a->resources.pci.addr[2];
+  byte* base = IoAdapter->reset - MP_RESET ;
+  dword ret = 0, DspCount = 0 ;
+  dword row_offset[] = {
+    0x00000000,
+    0x00000800, /* 1 - ROW 1 */
+    0x00000840, /* 2 - ROW 2 */
+    0x00001000, /* 3 - ROW 3 */
+    0x00001040, /* 4 - ROW 4 */
+    0x00000000  /* 5 - ROW 0 */
+  };
+  byte *dsp_addr_port, *dsp_data_port, row_state;
+  int dsp_row = 0, dsp_index, dsp_num;
+ IoAdapter->InitialDspInfo &= 0xffff ;
+//  if (!base || !a->xdi_adapter.reset)
+  if (!base || !IoAdapter->reset)
+  {
+    return (0);
+  }
+//  *(volatile byte*)(a->xdi_adapter.reset) = _MP_RISC_RESET | _MP_DSP_RESET;
+  *(volatile byte*)(IoAdapter->reset) = _MP_RISC_RESET | _MP_DSP_RESET;
+  diva_os_wait (5) ;
+  for (dsp_num = 0; dsp_num < 30; dsp_num++) {
+    dsp_row   = dsp_num / 7 + 1;
+    dsp_index = dsp_num % 7;
+    dsp_data_port = base;
+    dsp_addr_port = base;
+    dsp_data_port += row_offset[dsp_row];
+    dsp_addr_port += row_offset[dsp_row];
+    dsp_data_port += (dsp_index * 8);
+    dsp_addr_port += (dsp_index * 8) + 0x80;
+    if (!dsp_check_presence (dsp_addr_port, dsp_data_port, dsp_num+1)) {
+      ret |= (1 << dsp_num);
+   DspCount++ ;
+    }
+  }
+//  *(volatile byte*)(a->xdi_adapter.reset) = _MP_RISC_RESET | _MP_LED1 | _MP_LED2;
+  *(volatile byte*)(IoAdapter->reset) = _MP_RISC_RESET | _MP_LED1 | _MP_LED2;
+  diva_os_wait (50) ;
+  /*
+    Verify modules
+  */
+  for (dsp_row = 0; dsp_row < 4; dsp_row++) {
+    row_state = (byte)((ret >> (dsp_row*7)) & 0x7F);
+    if (row_state && (row_state != 0x7F)) {
+      for (dsp_index = 0; dsp_index < 7; dsp_index++) {
+        if (!(row_state & (1 << dsp_index))) {
+          DBG_ERR (("A: MODULE[%d]-DSP[%d] failed", dsp_row+1, dsp_index+1))
+        }
+      }
+    }
+  }
+  if (!(ret & 0x10000000)) {
+    DBG_ERR (("A: ON BOARD-DSP[1] failed"))
+  }
+  if (!(ret & 0x20000000)) {
+    DBG_ERR (("A: ON BOARD-DSP[2] failed"))
+  }
+  /*
+    Print module population now
+  */
+  DBG_LOG(("+-----------------------+"))
+  DBG_LOG(("| DSP MODULE POPULATION |"))
+  DBG_LOG(("+-----------------------+"))
+  DBG_LOG(("|  1  |  2  |  3  |  4  |"))
+  DBG_LOG(("+-----------------------+"))
+  DBG_LOG(("|  %s  |  %s  |  %s  |  %s  |",
+    ((ret >> (0*7)) & 0x7F) ? "Y" : "N",
+    ((ret >> (1*7)) & 0x7F) ? "Y" : "N",
+    ((ret >> (2*7)) & 0x7F) ? "Y" : "N",
+    ((ret >> (3*7)) & 0x7F) ? "Y" : "N"))
+  DBG_LOG(("+-----------------------+"))
+  DBG_LOG(("DSP's(present-absent):%08x-%08x", ret, ~ret & 0x3fffffff))
+  *(volatile byte*)(IoAdapter->reset) = 0 ;
+  diva_os_wait (50) ;
+ IoAdapter->InitialDspInfo |= DspCount << 16 ;
+  return (ret);
+}
+/* -------------------------------------------------------------------------
+  helper used to download dsp code toi PRI Card
+  ------------------------------------------------------------------------- */
+static long pri_download_buffer (OsFileHandle *fp, long length, void **addr) {
+ PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)fp->sysLoadDesc ;
+ dword        *sharedRam ;
+ *addr = (void *)IoAdapter->downloadAddr ;
+ if ( ((dword) length) > IoAdapter->DspCodeBaseAddr +
+                         IoAdapter->MaxDspCodeSize - IoAdapter->downloadAddr )
+ {
+  DBG_FTL(("%s: out of card memory during DSP download (0x%X)",
+           IoAdapter->Properties.Name,
+           IoAdapter->downloadAddr + length))
+  return (-1) ;
+ }
+ sharedRam = (dword *)DOWNLOAD_ADDR(IoAdapter) ;
+ if ( fp->sysFileRead (fp, sharedRam, length) != length )
+  return (-1) ;
+ IoAdapter->downloadAddr += length ;
+ IoAdapter->downloadAddr  = (IoAdapter->downloadAddr + 3) & (~3) ;
+ return (0) ;
+}
+/* -------------------------------------------------------------------------
+  Download DSP code to PRI Card
+  ------------------------------------------------------------------------- */
+static dword pri_telindus_load (PISDN_ADAPTER IoAdapter) {
+ char                *error ;
+ OsFileHandle        *fp ;
+ t_dsp_portable_desc  download_table[DSP_MAX_DOWNLOAD_COUNT] ;
+ word                 download_count ;
+ dword               *sharedRam ;
+ dword                FileLength ;
+ if ( !(fp = OsOpenFile (DSP_TELINDUS_FILE)) )
+  return (0) ;
+ IoAdapter->downloadAddr = (IoAdapter->DspCodeBaseAddr
+                         + sizeof(dword) + sizeof(download_table) + 3) & (~3) ;
+ FileLength      = fp->sysFileSize ;
+ fp->sysLoadDesc = (void *)IoAdapter ;
+ fp->sysCardLoad = pri_download_buffer ;
+ download_count = DSP_MAX_DOWNLOAD_COUNT ;
+ memset (&download_table[0], '\0', sizeof(download_table)) ;
+/*
+ * set start address for download (use autoincrement mode !)
+ */
+ error = dsp_read_file (fp, (word)(IoAdapter->cardType),
+                        &download_count, NULL, &download_table[0]) ;
+ if ( error )
+ {
+  DBG_FTL(("download file error: %s", error))
+  OsCloseFile (fp) ;
+  return (0) ;
+ }
+ OsCloseFile (fp) ;
+/*
+ * store # of separate download files extracted from archive
+ */
+ IoAdapter->downloadAddr = IoAdapter->DspCodeBaseAddr ;
+ sharedRam    = (dword *)DOWNLOAD_ADDR(IoAdapter) ;
+ WRITE_DWORD(&(sharedRam[0]), (dword)download_count);
+ memcpy (&sharedRam[1], &download_table[0], sizeof(download_table)) ;
+ return (FileLength) ;
+}
+/* -------------------------------------------------------------------------
+  Download PRI Card
+  ------------------------------------------------------------------------- */
+#define MIN_DSPS 0x30000000
+static int load_pri_hardware (PISDN_ADAPTER IoAdapter) {
+ dword           i ;
+ struct mp_load *boot = (struct mp_load *)IoAdapter->ram ;
+ if ( IoAdapter->Properties.Card != CARD_MAEP )
+  return (0) ;
+ boot->err = 0 ;
+#if 0
+ IoAdapter->rstFnc (IoAdapter) ;
+#else
+ if ( MIN_DSPS != (MIN_DSPS & diva_pri_detect_dsps(IoAdapter)) ) { /* makes reset */
+  DBG_FTL(("%s: DSP error!", IoAdapter->Properties.Name))
+  return (0) ;
+ }
+#endif
+/*
+ * check if CPU is alive
+ */
+ diva_os_wait (10) ;
+ i = boot->live ;
+ diva_os_wait (10) ;
+ if ( i == boot->live )
+ {
+  DBG_FTL(("%s: CPU is not alive!", IoAdapter->Properties.Name))
+  return (0) ;
+ }
+ if ( boot->err )
+ {
+  DBG_FTL(("%s: Board Selftest failed!", IoAdapter->Properties.Name))
+  return (0) ;
+ }
+/*
+ * download protocol and dsp files
+ */
+ if ( !xdiSetProtocol (IoAdapter, IoAdapter->ProtocolSuffix) )
+  return (0) ;
+ if ( !pri_protocol_load (IoAdapter) )
+  return (0) ;
+ if ( !pri_telindus_load (IoAdapter) )
+  return (0) ;
+/*
+ * copy configuration parameters
+ */
+ IoAdapter->ram += MP_SHARED_RAM_OFFSET ;
+ memset (IoAdapter->ram, '\0', 256) ;
+ diva_configure_protocol (IoAdapter);
+/*
+ * start adapter
+ */
+ boot->addr = MP_UNCACHED_ADDR (MP_PROTOCOL_OFFSET) ;
+ boot->cmd  = 3 ;
+/*
+ * wait for signature in shared memory (max. 3 seconds)
+ */
+ for ( i = 0 ; i < 300 ; ++i )
+ {
+  diva_os_wait (10) ;
+  if ( (boot->signature >> 16) == 0x4447 )
+  {
+   DBG_TRC(("Protocol startup time %d.%02d seconds",
+            (i / 100), (i % 100) ))
+   return (1) ;
+  }
+ }
+ DBG_FTL(("%s: Adapter selftest failed (0x%04X)!",
+          IoAdapter->Properties.Name, boot->signature >> 16))
+ pri_cpu_trapped (IoAdapter) ;
+ return (0) ;
+}
+#else /* } { */
+static int load_pri_hardware (PISDN_ADAPTER IoAdapter) {
+ return (0);
+}
+#endif /* } */
+/* --------------------------------------------------------------------------
+  PRI Adapter interrupt Service Routine
+   -------------------------------------------------------------------------- */
+static int pri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
+ if ( !((READ_DWORD((dword *)IoAdapter->cfg)) & 0x80000000) )
+  return (0) ;
+ /*
+  clear interrupt line
+  */
+ WRITE_DWORD(((dword *)IoAdapter->cfg), (dword)~0x03E00000) ;
+ IoAdapter->IrqCount++ ;
+ if ( IoAdapter->Initialized )
+ {
+  diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
+ }
+ return (1) ;
+}
+/* -------------------------------------------------------------------------
+  Disable interrupt in the card hardware
+  ------------------------------------------------------------------------- */
+static void disable_pri_interrupt (PISDN_ADAPTER IoAdapter) {
+ dword volatile *cfgReg = (dword volatile *)IoAdapter->cfg ;
+ cfgReg[3] = 0x00000000 ;
+ cfgReg[1] = 0x00000000 ;
+ WRITE_DWORD(&cfgReg[0], (dword)(~0x03E00000)) ;
+}
+/* -------------------------------------------------------------------------
+  Install entry points for PRI Adapter
+  ------------------------------------------------------------------------- */
+static void prepare_common_pri_functions (PISDN_ADAPTER IoAdapter) {
+ ADAPTER *a = &IoAdapter->a ;
+ a->ram_in           = mem_in ;
+ a->ram_inw          = mem_inw ;
+ a->ram_in_buffer    = mem_in_buffer ;
+ a->ram_look_ahead   = mem_look_ahead ;
+ a->ram_out          = mem_out ;
+ a->ram_outw         = mem_outw ;
+ a->ram_out_buffer   = mem_out_buffer ;
+ a->ram_inc          = mem_inc ;
+ a->ram_offset       = pri_ram_offset ;
+ a->ram_out_dw    = mem_out_dw;
+ a->ram_in_dw    = mem_in_dw;
+  a->istream_wakeup   = pr_stream;
+ IoAdapter->out      = pr_out ;
+ IoAdapter->dpc      = pr_dpc ;
+ IoAdapter->tst_irq  = scom_test_int ;
+ IoAdapter->clr_irq  = scom_clear_int ;
+ IoAdapter->pcm      = (struct pc_maint *)(MIPS_MAINT_OFFS
+                                        - MP_SHARED_RAM_OFFSET) ;
+ IoAdapter->load     = load_pri_hardware ;
+ IoAdapter->disIrq   = disable_pri_interrupt ;
+ IoAdapter->rstFnc   = reset_pri_hardware ;
+ IoAdapter->stop     = stop_pri_hardware ;
+ IoAdapter->trapFnc  = pri_cpu_trapped ;
+ IoAdapter->diva_isr_handler = pri_ISR;
+}
+/* -------------------------------------------------------------------------
+  Install entry points for PRI Adapter
+  ------------------------------------------------------------------------- */
+void prepare_pri_functions (PISDN_ADAPTER IoAdapter) {
+ IoAdapter->MemorySize = MP_MEMORY_SIZE ;
+ prepare_common_pri_functions (IoAdapter) ;
+ diva_os_prepare_pri_functions (IoAdapter);
+}
+/* -------------------------------------------------------------------------
+  Install entry points for PRI Rev.2 Adapter
+  ------------------------------------------------------------------------- */
+void prepare_pri2_functions (PISDN_ADAPTER IoAdapter) {
+ IoAdapter->MemorySize = MP2_MEMORY_SIZE ;
+ prepare_common_pri_functions (IoAdapter) ;
+ diva_os_prepare_pri2_functions (IoAdapter);
+}
+/* ------------------------------------------------------------------------- */
diff -Nru a/drivers/isdn/hardware/eicon/sdp_hdr.h b/drivers/isdn/hardware/eicon/sdp_hdr.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/sdp_hdr.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,117 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+#ifndef __DIVA_SOFT_DSP_TASK_ENTRY_H__
+#define __DIVA_SOFT_DSP_TASK_ENTRY_H__
+/*
+ The soft DSP image is described by binary header contained on begin of this
+ image:
+OFFSET FROM IMAGE START |  VARIABLE
+------------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_LINK_OFFS   |  link to the next image
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_GP_OFFS    |  image gp register value, void*
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_ENTRY_OFFS   |  diva_mips_sdp_task_entry_t*
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_LOAD_ADDR_OFFS |  image image start address (void*)
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_END_ADDR_OFFS |  image image end address   (void*)
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_ID_STRING_OFFS |  image id string char[...];
+  ----------------------------------------------------------------------
+ */
+#define DIVA_MIPS_TASK_IMAGE_LINK_OFFS   0x6C
+#define DIVA_MIPS_TASK_IMAGE_GP_OFFS    0x70
+#define DIVA_MIPS_TASK_IMAGE_ENTRY_OFFS   0x74
+#define DIVA_MIPS_TASK_IMAGE_LOAD_ADDR_OFFS 0x78
+#define DIVA_MIPS_TASK_IMAGE_END_ADDR_OFFS 0x7c
+#define DIVA_MIPS_TASK_IMAGE_ID_STRING_OFFS 0x80
+/*
+ This function is called in order to set GP register of this task
+ This function should be always called before any function of the
+ task is called
+ */
+typedef void (*diva_task_set_prog_gp_proc_t)(void* new_gp);
+/*
+ This function is called to clear .bss at task initialization step
+ */
+typedef void  (*diva_task_sys_reset_proc_t)(void);
+/*
+ This function is called in order to provide GP of master call to
+ task, that will be used by calls from the task to the master
+ */
+typedef void (*diva_task_set_main_gp_proc_t)(void* main_gp);
+/*
+ This function is called to provide address of 'dprintf' function
+ to the task
+ */
+typedef word (*diva_prt_proc_t)(char *, ...);
+typedef void (*diva_task_set_prt_proc_t)(diva_prt_proc_t fn);
+/*
+ This function is called to set task PID
+ */
+typedef void (*diva_task_set_pid_proc_t)(dword id);
+/*
+ This function is called for run-time task init
+ */
+typedef int (*diva_task_run_time_init_proc_t)(void*, dword);
+/*
+ This function is called from system scheduler or from timer
+ */
+typedef void (*diva_task_callback_proc_t)(void);
+/*
+ This callback is used by task to get current time im mS
+  */
+typedef dword (*diva_task_get_tick_count_proc_t)(void);
+typedef void (*diva_task_set_get_time_proc_t)(\
+                diva_task_get_tick_count_proc_t fn);
+typedef struct _diva_mips_sdp_task_entry {
+ diva_task_set_prog_gp_proc_t  set_gp_proc;
+ diva_task_sys_reset_proc_t   sys_reset_proc;
+ diva_task_set_main_gp_proc_t  set_main_gp_proc;
+ diva_task_set_prt_proc_t    set_dprintf_proc;
+ diva_task_set_pid_proc_t    set_pid_proc;
+ diva_task_run_time_init_proc_t run_time_init_proc;
+ diva_task_callback_proc_t    task_callback_proc;
+ diva_task_callback_proc_t    timer_callback_proc;
+ diva_task_set_get_time_proc_t  set_get_time_proc;
+ void*              last_entry_proc;
+} diva_mips_sdp_task_entry_t;
+/*
+ 'last_entry_proc' should be set to zero and is used for future extensuios
+ */
+typedef struct _diva_mips_sw_task {
+  diva_mips_sdp_task_entry_t  sdp_entry;
+  void*                       sdp_gp_reg;
+  void*                       own_gp_reg;
+} diva_mips_sw_task_t;
+#if !defined(DIVA_BRI2F_SDP_1_NAME)
+#define DIVA_BRI2F_SDP_1_NAME "sdp0.2q0"
+#endif
+#if !defined(DIVA_BRI2F_SDP_2_NAME)
+#define DIVA_BRI2F_SDP_2_NAME "sdp1.2q0"
+#endif
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/um_idi.c b/drivers/isdn/hardware/eicon/um_idi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/um_idi.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,845 @@
+/* $Id: um_idi.c,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "dlist.h"
+#include "dqueue.h"
+#include "adapter.h"
+#include "entity.h"
+#include "um_xdi.h"
+#include "um_idi.h"
+#include "debuglib.h"
+#include "divasync.h"
+
+#define DIVAS_MAX_XDI_ADAPTERS	64
+
+/* --------------------------------------------------------------------------
+		IMPORTS
+   -------------------------------------------------------------------------- */
+extern void diva_os_wakeup_read (void* os_context);
+extern void diva_os_wakeup_close (void* os_context);
+/* --------------------------------------------------------------------------
+		LOCALS
+   -------------------------------------------------------------------------- */
+static diva_entity_queue_t	adapter_q;
+static diva_os_spin_lock_t adapter_lock;
+
+static diva_um_idi_adapter_t* diva_um_idi_find_adapter (dword nr);
+static void cleanup_adapter (diva_um_idi_adapter_t* a);
+static void cleanup_entity (divas_um_idi_entity_t* e);
+static int diva_user_mode_idi_adapter_features (diva_um_idi_adapter_t* a,
+                                                diva_um_idi_adapter_features_t* features);
+static int process_idi_request (divas_um_idi_entity_t* e,
+                                const diva_um_idi_req_hdr_t* req);
+static int process_idi_rc (divas_um_idi_entity_t* e,	byte rc);
+static int process_idi_ind (divas_um_idi_entity_t* e, byte ind);
+static int write_return_code (divas_um_idi_entity_t* e, byte rc);
+
+/* --------------------------------------------------------------------------
+		MAIN
+   -------------------------------------------------------------------------- */
+int
+diva_user_mode_idi_init (void)
+{
+  diva_q_init(&adapter_q);
+  diva_os_initialize_spin_lock (&adapter_lock, "adapter");
+  return (0);
+}
+
+/* --------------------------------------------------------------------------
+		Copy adapter features to user supplied buffer
+   -------------------------------------------------------------------------- */
+static int
+diva_user_mode_idi_adapter_features (diva_um_idi_adapter_t* a,
+			diva_um_idi_adapter_features_t* features)
+{
+  IDI_SYNC_REQ sync_req;
+
+  if ((a) && (a->d.request)){
+    features->type           = a->d.type;
+    features->features       = a->d.features;
+    features->channels       = a->d.channels;
+    memset(features->name, 0, sizeof(features->name));
+
+    sync_req.GetName.Req = 0;
+    sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
+    (*(a->d.request))((ENTITY *)&sync_req);
+    strncpy(features->name, sync_req.GetName.name, sizeof(features->name)-1);
+
+    sync_req.GetSerial.Req = 0;
+    sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
+    sync_req.GetSerial.serial = 0;
+    (*(a->d.request))((ENTITY *)&sync_req);
+    features->serial_number = sync_req.GetSerial.serial;
+  }
+
+  return ((a) ? 0 : -1);
+}
+
+/* --------------------------------------------------------------------------
+		REMOVE ADAPTER
+   -------------------------------------------------------------------------- */
+void diva_user_mode_idi_remove_adapter(int adapter_nr) {
+	diva_um_idi_adapter_t* a = (diva_um_idi_adapter_t*)diva_q_get_head (&adapter_q);
+
+  while (a) {
+    if(a->adapter_nr == adapter_nr) {
+      diva_q_remove (&adapter_q, &a->link);
+      cleanup_adapter (a);
+      DBG_LOG (("DIDD: del adapter(%d)", a->adapter_nr));
+      diva_os_free (0, a);
+      break;
+    }
+    a = (diva_um_idi_adapter_t*)diva_q_get_next (&a->link);
+  }
+}
+
+/* --------------------------------------------------------------------------
+		CALLED ON DRIVER EXIT (UNLOAD)
+   -------------------------------------------------------------------------- */
+void
+diva_user_mode_idi_finit (void)
+{
+	diva_um_idi_adapter_t* a = (diva_um_idi_adapter_t*)diva_q_get_head (&adapter_q);
+
+	while (a) {
+		diva_q_remove (&adapter_q, &a->link);
+		cleanup_adapter (a);
+		DBG_LOG (("DIDD: del adapter(%d)", a->adapter_nr));
+		diva_os_free (0, a);
+		a = (diva_um_idi_adapter_t*)diva_q_get_head (&adapter_q);
+	}
+        diva_os_destroy_spin_lock (&adapter_lock, "adapter");
+}
+
+/* -------------------------------------------------------------------------
+		CREATE AND INIT IDI ADAPTER
+	 ------------------------------------------------------------------------- */
+int diva_user_mode_idi_create_adapter (const DESCRIPTOR* d, int adapter_nr) {
+        diva_os_spin_lock_magic_t old_irql;
+	diva_um_idi_adapter_t* a =
+		(diva_um_idi_adapter_t*)diva_os_malloc (0, sizeof(diva_um_idi_adapter_t));
+	
+	if (!a) {
+		return (-1);
+	}
+	memset(a, 0x00, sizeof(*a));
+
+	a->d = *d;
+	a->adapter_nr = adapter_nr;
+
+	DBG_LOG (("DIDD_ADD A(%d), type:%02x, features:%04x, channels:%d",
+					 adapter_nr, a->d.type, a->d.features, a->d.channels));
+
+        diva_os_enter_spin_lock (&adapter_lock, &old_irql, "create_adapter");
+	diva_q_add_tail (&adapter_q, &a->link);
+        diva_os_leave_spin_lock (&adapter_lock, &old_irql, "create_adapter");
+	return (0);
+}
+
+static int cmp_adapter_nr (const void* what, const diva_entity_link_t* p) {
+	diva_um_idi_adapter_t* a = (diva_um_idi_adapter_t*)p;
+	dword nr = (dword)(unsigned long)what;
+
+	DBG_TRC (("find_adapter: (%d)-(%d)", nr, a->adapter_nr));
+
+	return (nr != a->adapter_nr);
+}
+
+/* ------------------------------------------------------------------------
+			Find adapter by Adapter number
+   ------------------------------------------------------------------------ */
+static diva_um_idi_adapter_t* diva_um_idi_find_adapter (dword nr) {
+	return (diva_um_idi_adapter_t*)diva_q_find (&adapter_q,
+                                                    (void*)(unsigned long)nr,
+                                                    cmp_adapter_nr);
+}
+
+/* ------------------------------------------------------------------------
+		Return number of adapters in system
+   ------------------------------------------------------------------------ */
+int diva_um_idi_nr_of_adapters (void) {
+	return (diva_q_get_nr_of_entries (&adapter_q));
+}
+
+/* ------------------------------------------------------------------------
+		Cleanup this adapter and cleanup/delete all entities assigned
+		to this adapter
+   ------------------------------------------------------------------------ */
+static void cleanup_adapter (diva_um_idi_adapter_t* a) {
+  divas_um_idi_entity_t* e = (divas_um_idi_entity_t*)diva_q_get_head	(&a->entity_q);
+
+  while (e) {
+    diva_q_remove (&a->entity_q, &e->link);
+    cleanup_entity (e);
+    if (e->os_context) {
+		  diva_os_wakeup_read (e->os_context);
+		  diva_os_wakeup_close (e->os_context);
+    }
+    e = (divas_um_idi_entity_t*)diva_q_get_head	(&a->entity_q);
+  }
+  memset(&a->d, 0x00, sizeof(DESCRIPTOR));
+}
+
+/* ------------------------------------------------------------------------
+		Cleanup, but NOT delete this entity
+   ------------------------------------------------------------------------ */
+static void cleanup_entity (divas_um_idi_entity_t* e) {
+  e->os_ref   = 0;
+  e->status   = 0;
+  e->adapter  = 0;
+  e->e.Id     = 0;
+  e->rc_count = 0;
+
+  e->status |= DIVA_UM_IDI_REMOVED;
+	e->status |= DIVA_UM_IDI_REMOVE_PENDING;
+
+  diva_data_q_finit	(&e->data);
+  diva_data_q_finit	(&e->rc);
+}
+
+
+/* ------------------------------------------------------------------------
+		Create ENTITY, link it to the adapter and remove pointer to entity
+   ------------------------------------------------------------------------ */
+void* divas_um_idi_create_entity (dword adapter_nr, void* file) {
+  divas_um_idi_entity_t* e;
+  diva_um_idi_adapter_t* a;
+  diva_os_spin_lock_magic_t old_irql;
+
+	if ((e = (divas_um_idi_entity_t*)diva_os_malloc (0, sizeof(*e)))) {
+		memset(e, 0x00, sizeof(*e));
+		if (!(e->os_context = diva_os_malloc (0, diva_os_get_context_size ()))) {
+			DBG_LOG (("E(%08x) no memory for os context", e));
+			diva_os_free (0, e);
+			return (0);
+		}
+		memset(e->os_context, 0x00, diva_os_get_context_size ());
+
+		if ((diva_data_q_init (&e->data, 2048+512, 16))) {
+			diva_os_free (0, e->os_context);
+			diva_os_free (0, e);
+			return (0);
+		}
+		if ((diva_data_q_init (&e->rc, 64, 2))) {
+			diva_data_q_finit	(&e->data);
+			diva_os_free (0, e->os_context);
+			diva_os_free (0, e);
+			return (0);
+		}
+
+    diva_os_enter_spin_lock (&adapter_lock, &old_irql, "create_entity");
+		/*
+			Look for Adapter requested
+			*/
+		if (!(a = diva_um_idi_find_adapter (adapter_nr))) {
+			/*
+				No adapter was found, or this adapter was removed
+				*/
+      diva_os_leave_spin_lock (&adapter_lock, &old_irql, "create_entity");
+
+			DBG_LOG (("A: no adapter(%ld)", adapter_nr));
+
+			cleanup_entity (e);
+			diva_os_free (0, e->os_context);
+			diva_os_free (0, e);
+
+			return (0);
+		}
+
+		e->os_ref = file; /* link to os handle */
+		e->adapter = a;   /* link to adapter   */
+
+		diva_q_add_tail (&a->entity_q, &e->link); /* link from adapter */
+
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "create_entity");
+
+		DBG_LOG (("A(%ld), create E(%08x)", adapter_nr, e));
+	}
+
+	return (e);
+}
+
+/* ------------------------------------------------------------------------
+		Unlink entity and free memory 
+   ------------------------------------------------------------------------ */
+int divas_um_idi_delete_entity (int adapter_nr, void* entity) {
+  divas_um_idi_entity_t* e;
+  diva_um_idi_adapter_t* a;
+  diva_os_spin_lock_magic_t old_irql;
+
+  if (!(e = (divas_um_idi_entity_t*)entity))
+    return(-1);
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "delete_entity");
+  if ((a = e->adapter)) {
+    diva_q_remove (&a->entity_q, &e->link);
+  }
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "delete_entity");
+
+  diva_um_idi_stop_wdog (entity);
+  cleanup_entity (e);
+  diva_os_free (0, e->os_context);
+  memset(e, 0x00, sizeof(*e));
+  diva_os_free (0, e);
+
+  DBG_LOG (("A(%d) remove E:%08x", adapter_nr, e));
+
+  return (0);
+}
+
+/* --------------------------------------------------------------------------
+		Called by application to read data from IDI
+	 -------------------------------------------------------------------------- */
+int diva_um_idi_read (void* entity,
+                      void* os_handle,
+                      void* dst,
+                      int max_length,
+                      divas_um_idi_copy_to_user_fn_t cp_fn) {
+	divas_um_idi_entity_t* e;
+	diva_um_idi_adapter_t* a;
+	const void* data;
+	int length, ret = 0;
+	diva_um_idi_data_queue_t* q;
+  diva_os_spin_lock_magic_t old_irql;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "read");
+
+	e = (divas_um_idi_entity_t*)entity;
+  if (!e || (!(a = e->adapter)) ||
+      (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
+      (e->status & DIVA_UM_IDI_REMOVED) ||
+      (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "read");
+	  DBG_ERR(("E(%08x) read failed - adapter removed", e))
+    return (-1);
+  }
+
+	DBG_TRC(("A(%d) E(%08x) read(%d)", a->adapter_nr, e, max_length));
+
+	/*
+		Try to read return code first
+		*/
+	data	= diva_data_q_get_segment4read	(&e->rc);
+	q			=	&e->rc;
+
+	/*
+		No return codes available, read indications now
+		*/
+	if (!data) {
+		if (!(e->status & DIVA_UM_IDI_RC_PENDING)) {
+			DBG_TRC (("A(%d) E(%08x) read data", a->adapter_nr, e));
+			data	= diva_data_q_get_segment4read	(&e->data);
+			q			=	&e->data;
+		}
+	} else {
+		e->status &= ~DIVA_UM_IDI_RC_PENDING;
+		DBG_TRC (("A(%d) E(%08x) read rc", a->adapter_nr, e));
+	}
+		
+	if (data) {
+		if ((length = diva_data_q_get_segment_length (q)) > max_length) {
+			/*
+				Not enough space to read message
+				*/
+			DBG_ERR (("A: A(%d) E(%08x) read small buffer", a->adapter_nr, e, ret));
+      diva_os_leave_spin_lock (&adapter_lock, &old_irql, "read");
+			return (-2);
+		}
+		/*
+			Copy it to user, this function does access ONLY locked an verified
+			memory, also we can access it witch spin lock held
+			*/
+	
+		if ((ret = (*cp_fn) (os_handle, dst, data, length)) >= 0) {
+			/*
+				Acknowledge only if read was successfull
+				*/
+			diva_data_q_ack_segment4read	(q);
+		}
+	}
+
+
+  DBG_TRC (("A(%d) E(%08x) read=%d", a->adapter_nr, e, ret));
+
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "read");
+
+	return (ret);
+}
+
+
+int diva_um_idi_write (void* entity,
+                       void* os_handle,
+                       const void* src,
+                       int length,
+                       divas_um_idi_copy_from_user_fn_t cp_fn) {
+	divas_um_idi_entity_t* e;
+	diva_um_idi_adapter_t* a;
+	diva_um_idi_req_hdr_t* req;
+	void* data;
+	int ret = 0;
+  diva_os_spin_lock_magic_t old_irql;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "write");
+
+  e = (divas_um_idi_entity_t*)entity;
+  if (!e || (!(a = e->adapter)) ||
+      (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
+      (e->status & DIVA_UM_IDI_REMOVED) ||
+      (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+    DBG_ERR(("E(%08x) write failed - adapter removed", e))
+    return (-1);
+  }
+
+  DBG_TRC(("A(%d) E(%08x) write(%d)", a->adapter_nr, e, length));
+
+  if ((length < sizeof (*req)) || (length > sizeof (e->buffer))) {
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+    return (-2);
+  }
+
+  if (e->status & DIVA_UM_IDI_RC_PENDING) {
+    DBG_ERR(("A: A(%d) E(%08x) rc pending", a->adapter_nr, e));
+              diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+    return (-1); /* should wait for RC code first */
+  }
+
+	/*
+			Copy function does access only locked verified memory,
+			also it can be called with spin lock held
+		*/
+	if ((ret = (*cp_fn)(os_handle, e->buffer, src, length)) < 0) {
+		DBG_TRC(("A: A(%d) E(%08x) write error=%d", a->adapter_nr, e, ret));
+                diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+		return (ret);
+	}
+
+	req = (diva_um_idi_req_hdr_t*)&e->buffer[0];
+
+	switch (req->type) {
+		case DIVA_UM_IDI_GET_FEATURES: {
+			DBG_LOG(("A(%d) get_features", a->adapter_nr));
+			if (!(data = diva_data_q_get_segment4write	(&e->data))) {
+				DBG_ERR(("A(%d) get_features, no free buffer", a->adapter_nr));
+                                diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+				return (0);
+			}
+			diva_user_mode_idi_adapter_features (a,
+												&(((diva_um_idi_ind_hdr_t*)data)->hdr.features));
+			((diva_um_idi_ind_hdr_t*)data)->type = DIVA_UM_IDI_IND_FEATURES;
+			((diva_um_idi_ind_hdr_t*)data)->data_length = 0;
+			diva_data_q_ack_segment4write	(&e->data, sizeof(diva_um_idi_ind_hdr_t));
+
+      diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+
+			diva_os_wakeup_read (e->os_context);
+		} break;
+
+		case DIVA_UM_IDI_REQ:
+		case DIVA_UM_IDI_REQ_MAN:
+		case DIVA_UM_IDI_REQ_SIG:
+		case DIVA_UM_IDI_REQ_NET:
+			DBG_TRC(("A(%d) REQ(%02d)-(%02d)-(%08x)", \
+							a->adapter_nr, req->Req, req->ReqCh,
+							req->type & DIVA_UM_IDI_REQ_TYPE_MASK));
+			switch (process_idi_request (e, req)) {
+				case -1:
+          diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+					return (-1);
+				case -2:
+          diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+					diva_os_wakeup_read (e->os_context);
+					break;
+				default:
+          diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+					break;
+			}
+			break;
+
+		default:
+      diva_os_leave_spin_lock (&adapter_lock, &old_irql, "write");
+			return (-1);
+	}
+
+	DBG_TRC(("A(%d) E(%08x) write=%d", a->adapter_nr, e, ret));
+
+	return (ret);
+}
+
+/* --------------------------------------------------------------------------
+			CALLBACK FROM XDI
+	 -------------------------------------------------------------------------- */
+static void diva_um_idi_xdi_callback (ENTITY* entity) {
+	divas_um_idi_entity_t* e = DIVAS_CONTAINING_RECORD(entity,
+                                   divas_um_idi_entity_t, e); 
+  diva_os_spin_lock_magic_t old_irql;
+	int call_wakeup = 0;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "xdi_callback");
+
+	if (e->e.complete == 255) {
+		if (!(e->status & DIVA_UM_IDI_REMOVE_PENDING)) {
+      diva_um_idi_stop_wdog (e);
+    }
+		if ((call_wakeup = process_idi_rc (e, e->e.Rc))) {
+			if (e->rc_count) {
+				e->rc_count--;
+			}
+		}
+		e->e.Rc = 0;
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "xdi_callback");
+
+		if (call_wakeup) {
+			diva_os_wakeup_read (e->os_context);
+			diva_os_wakeup_close (e->os_context);
+		}
+	} else {
+		if (e->status & DIVA_UM_IDI_REMOVE_PENDING) {
+			e->e.RNum = 0;
+			e->e.RNR =  2;
+		} else {
+			call_wakeup = process_idi_ind (e, e->e.Ind);
+		}
+		e->e.Ind = 0;
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "xdi_callback");
+		if (call_wakeup) {
+			diva_os_wakeup_read (e->os_context);
+		}
+	}
+}
+
+static int process_idi_request (divas_um_idi_entity_t* e,
+                                const diva_um_idi_req_hdr_t* req) {
+	int assign = 0;
+	byte Req = (byte)req->Req;
+	dword type = req->type & DIVA_UM_IDI_REQ_TYPE_MASK;
+
+	if (!e->e.Id || !e->e.callback) { /* not assigned */
+		if (Req != ASSIGN) {
+			DBG_ERR(("A: A(%d) E(%08x) not assigned", e->adapter->adapter_nr, e));
+			return (-1); /* NOT ASSIGNED */
+		} else {
+			switch (type) {
+				case DIVA_UM_IDI_REQ_TYPE_MAN:
+					e->e.Id = MAN_ID;
+					DBG_TRC(("A(%d) E(%08x) assign MAN", e->adapter->adapter_nr, e));
+					break;
+
+				case DIVA_UM_IDI_REQ_TYPE_SIG:
+					e->e.Id = DSIG_ID;
+					DBG_TRC(("A(%d) E(%08x) assign SIG", e->adapter->adapter_nr, e));
+					break;
+
+				case DIVA_UM_IDI_REQ_TYPE_NET:
+					e->e.Id = NL_ID;
+					DBG_TRC(("A(%d) E(%08x) assign NET", e->adapter->adapter_nr, e));
+					break;
+
+				default:
+					DBG_ERR (("A: A(%d) E(%08x) unknown type=%08x", \
+										e->adapter->adapter_nr, e, type));
+					return (-1);
+			}
+		}
+		e->e.XNum = 1;
+		e->e.RNum = 1;
+		e->e.callback = diva_um_idi_xdi_callback;
+		e->e.X = &e->XData;
+		e->e.R = &e->RData;
+		assign = 1;
+	}
+	e->status			 |= DIVA_UM_IDI_RC_PENDING;
+	e->e.Req				= Req;
+	e->e.ReqCh			= (byte)req->ReqCh;
+	e->e.X->PLength = (word)req->data_length;
+	e->e.X->P			  = (byte*)&req[1]; /* Our buffer is safe */
+
+	DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))", \
+					e->adapter->adapter_nr, e, \
+					e->e.Id, e->e.Req, e->e.ReqCh, e->e.X->PLength));
+
+	e->rc_count++;
+
+  if (e->adapter && e->adapter->d.request) {
+    diva_um_idi_start_wdog (e);
+    (*(e->adapter->d.request))(&e->e);
+  }
+
+	if (assign) {
+		if (e->e.Rc == OUT_OF_RESOURCES) {
+			/*
+				XDI has no entities more, call was not forwarded to the card,
+				no callback will be scheduled
+				*/
+			DBG_ERR(("A: A(%d) E(%08x) XDI out of entities",
+							e->adapter->adapter_nr, e));
+
+			e->e.Id		 = 0;
+			e->e.ReqCh = 0;
+			e->e.RcCh	 = 0;
+			e->e.Ind	 = 0;
+			e->e.IndCh = 0;
+			e->e.XNum	 = 0;
+			e->e.RNum	 = 0;
+			e->e.callback = 0;
+			e->e.X		 = 0;
+			e->e.R		 = 0;
+			write_return_code (e, ASSIGN_RC | OUT_OF_RESOURCES);
+			return (-2);
+		} else {
+			e->status |= DIVA_UM_IDI_ASSIGN_PENDING;
+		}
+	}
+
+	return (0);
+}
+
+static int process_idi_rc (divas_um_idi_entity_t* e, byte rc) {
+	DBG_TRC(("A(%d) E(%08x) rc(%02x-%02x-%02x)", \
+					e->adapter->adapter_nr, e, \
+					e->e.Id, rc, e->e.RcCh));
+
+	if (e->status & DIVA_UM_IDI_ASSIGN_PENDING) {
+		e->status &= ~DIVA_UM_IDI_ASSIGN_PENDING;
+		if (rc != ASSIGN_OK) {
+			DBG_ERR(("A: A(%d) E(%08x) ASSIGN failed", e->adapter->adapter_nr, e));
+			e->e.callback = 0;
+			e->e.Id = 0;
+			e->e.Req = 0;
+			e->e.ReqCh = 0;
+			e->e.Rc = 0;
+			e->e.RcCh = 0;
+			e->e.Ind = 0;
+			e->e.IndCh = 0;
+			e->e.X		 = 0;
+			e->e.R		 = 0;
+			e->e.XNum	 = 0;
+			e->e.RNum	 = 0;
+		}
+	}
+	if ((e->e.Req == REMOVE) && e->e.Id && (rc == 0xff)) {
+		DBG_ERR(("A: A(%d) E(%08x)  discard OK in REMOVE",  \
+						e->adapter->adapter_nr, e));
+		return (0); /* let us do it in the driver */
+	}
+	if ((e->e.Req == REMOVE) && (!e->e.Id)) { /* REMOVE COMPLETE */
+		e->e.callback = 0;
+		e->e.Id = 0;
+		e->e.Req = 0;
+		e->e.ReqCh = 0;
+		e->e.Rc = 0;
+		e->e.RcCh = 0;
+		e->e.Ind = 0;
+		e->e.IndCh = 0;
+		e->e.X		 = 0;
+		e->e.R		 = 0;
+		e->e.XNum	 = 0;
+		e->e.RNum	 = 0;
+		e->rc_count = 0;
+	}
+	if ((e->e.Req == REMOVE) && (rc != 0xff)) { /* REMOVE FAILED */
+		DBG_ERR(("A: A(%d) E(%08x)  REMOVE FAILED",  \
+						e->adapter->adapter_nr, e));
+	}
+	write_return_code (e, rc);
+
+	return (1);
+}
+
+static int process_idi_ind (divas_um_idi_entity_t* e, byte ind) {
+	int do_wakeup = 0;
+
+	if (e->e.complete != 0x02) {
+		diva_um_idi_ind_hdr_t* pind =
+					(diva_um_idi_ind_hdr_t*)diva_data_q_get_segment4write (&e->data);
+		if (pind) {
+			e->e.RNum       = 1;
+			e->e.R->P			  = (byte*)&pind[1];
+			e->e.R->PLength = (word)(diva_data_q_get_max_length	(&e->data) -\
+												sizeof(*pind));
+			DBG_TRC(("A(%d) E(%08x) ind_1(%02x-%02x-%02x)-[%d-%d]", \
+							e->adapter->adapter_nr, e, \
+							e->e.Id, ind, e->e.IndCh, e->e.RLength, e->e.R->PLength));
+
+		} else {
+			DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-RNR", \
+								e->adapter->adapter_nr, e, \
+								e->e.Id, ind, e->e.IndCh));
+			e->e.RNum	= 0;
+			e->e.RNR	= 1;
+			do_wakeup = 1;
+		}
+	} else {
+		diva_um_idi_ind_hdr_t* pind =\
+										(diva_um_idi_ind_hdr_t*)(e->e.R->P);
+
+		DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-[%d]", \
+							e->adapter->adapter_nr, e, \
+							e->e.Id, ind, e->e.IndCh, e->e.R->PLength));
+
+		pind--;
+		pind->type					= DIVA_UM_IDI_IND;
+		pind->hdr.ind.Ind		= ind;
+		pind->hdr.ind.IndCh = e->e.IndCh;
+		pind->data_length   = e->e.R->PLength;
+		diva_data_q_ack_segment4write	(&e->data,
+																	 (int)(sizeof(*pind)+e->e.R->PLength));
+		do_wakeup = 1;
+	}
+
+	if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
+		do_wakeup = 0;
+	}
+
+	return (do_wakeup);
+}
+
+/* --------------------------------------------------------------------------
+		Write return code to the return code queue of entity
+	 -------------------------------------------------------------------------- */
+static int	write_return_code (divas_um_idi_entity_t* e, byte rc) {
+	diva_um_idi_ind_hdr_t* prc;
+
+	if (!(prc = (diva_um_idi_ind_hdr_t*)diva_data_q_get_segment4write	(&e->rc))) {
+		DBG_ERR (("A: A(%d) E(%08x) rc(%02x) lost", e->adapter->adapter_nr, e, rc));
+		e->status &= ~DIVA_UM_IDI_RC_PENDING;
+		return (-1);
+	}
+
+	prc->type				 = DIVA_UM_IDI_IND_RC;
+	prc->hdr.rc.Rc	 = rc;
+	prc->hdr.rc.RcCh = e->e.RcCh;
+	prc->data_length = 0;
+	diva_data_q_ack_segment4write	(&e->rc, sizeof(*prc));
+	
+	return (0);
+}
+
+/* --------------------------------------------------------------------------
+		Return amount of entries that can be bead from this entity or
+		-1 if adapter was removed
+	 -------------------------------------------------------------------------- */
+int diva_user_mode_idi_ind_ready (void* entity, void* os_handle) {
+	divas_um_idi_entity_t* e;
+	diva_um_idi_adapter_t* a;
+        diva_os_spin_lock_magic_t old_irql;
+	int ret;
+
+        if (!entity)
+          return(-1);
+        diva_os_enter_spin_lock (&adapter_lock, &old_irql, "ind_ready");
+	e = (divas_um_idi_entity_t*)entity;
+	a = e->adapter;
+
+	if ((!a) || (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+		/*
+			Adapter was unloaded
+			*/
+                diva_os_leave_spin_lock (&adapter_lock, &old_irql, "ind_ready");
+		return (-1); /* adapter was removed */
+	}
+	if (e->status & DIVA_UM_IDI_REMOVED) {
+		/*
+			entity was removed as result of adapter removal
+			user should assign this entity again
+			*/
+                diva_os_leave_spin_lock (&adapter_lock, &old_irql, "ind_ready");
+		return (-1);
+	}
+
+	ret = e->rc.count + e->data.count;
+
+	if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
+		ret = 0;
+	}
+
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "ind_ready");
+
+	return (ret);
+}
+
+void* diva_um_id_get_os_context (void* entity) {
+	return (((divas_um_idi_entity_t*)entity)->os_context);
+}
+
+int divas_um_idi_entity_assigned (void* entity) {
+	divas_um_idi_entity_t* e;
+	diva_um_idi_adapter_t* a;
+	int ret;
+  diva_os_spin_lock_magic_t old_irql;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "assigned?");
+
+
+	e = (divas_um_idi_entity_t*)entity;
+  if (!e || (!(a = e->adapter)) ||
+      (e->status & DIVA_UM_IDI_REMOVED) ||
+      (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "assigned?");
+    return (0);
+  }
+
+	e->status |= DIVA_UM_IDI_REMOVE_PENDING;
+
+  ret = (e->e.Id || e->rc_count || (e->status & DIVA_UM_IDI_ASSIGN_PENDING));
+
+	DBG_TRC(("Id:%02x, rc_count:%d, status:%08x", e->e.Id, e->rc_count, e->status))
+
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "assigned?");
+
+  return (ret);
+}
+
+int divas_um_idi_entity_start_remove (void* entity) {
+	divas_um_idi_entity_t* e;
+	diva_um_idi_adapter_t* a;
+  diva_os_spin_lock_magic_t old_irql;
+
+  diva_os_enter_spin_lock (&adapter_lock, &old_irql, "start_remove");
+
+  e = (divas_um_idi_entity_t*)entity;
+  if (!e || (!(a = e->adapter)) ||
+      (e->status & DIVA_UM_IDI_REMOVED) ||
+      (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "start_remove");
+    return (0);
+  }
+
+  if (e->rc_count) {
+    /*
+       Entity BUSY
+      */
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "start_remove");
+    return (1);
+  }
+
+  if (!e->e.Id) {
+    /*
+       Remove request was already pending, and arrived now
+       */
+    diva_os_leave_spin_lock (&adapter_lock, &old_irql, "start_remove");
+    return (0); /* REMOVE was pending */
+  }
+
+  /*
+    Now send remove request
+    */
+  e->e.Req	 = REMOVE;
+  e->e.ReqCh = 0;
+
+  e->rc_count++;
+
+  DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))", \
+           e->adapter->adapter_nr, e, \
+           e->e.Id, e->e.Req, e->e.ReqCh, e->e.X->PLength));
+
+  if (a->d.request)
+    (*(a->d.request))(&e->e);
+
+  diva_os_leave_spin_lock (&adapter_lock, &old_irql, "start_remove");
+
+	return (0);
+}
+
diff -Nru a/drivers/isdn/hardware/eicon/um_idi.h b/drivers/isdn/hardware/eicon/um_idi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/um_idi.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,46 @@
+/* $Id: um_idi.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_USER_MODE_IDI_CORE_H__
+#define __DIVA_USER_MODE_IDI_CORE_H__
+
+
+/*
+  interface between UM IDI core and OS dependent part
+  */
+int diva_user_mode_idi_init (void);
+void diva_user_mode_idi_finit (void);
+int diva_um_idi_nr_of_adapters (void);
+void* divas_um_idi_create_entity (dword adapter_nr, void* file);
+int divas_um_idi_delete_entity (int adapter_nr, void* entity);
+
+typedef int (*divas_um_idi_copy_to_user_fn_t)(void* os_handle,
+                                              void* dst,
+                                              const void* src,
+                                              int length);
+typedef int (*divas_um_idi_copy_from_user_fn_t)(void* os_handle,
+                                                void* dst,
+                                                const void* src,
+                                                int length);
+
+int diva_um_idi_read (void* entity,
+                      void* os_handle,
+                      void* dst,
+                      int max_length,
+                      divas_um_idi_copy_to_user_fn_t cp_fn);
+
+int diva_um_idi_write (void* entity,
+                       void* os_handle,
+                       const void* src,
+                       int length,
+                       divas_um_idi_copy_from_user_fn_t cp_fn);
+
+int diva_user_mode_idi_ind_ready (void* entity, void* os_handle);
+void* diva_um_id_get_os_context (void* entity);
+int diva_os_get_context_size (void);
+int divas_um_idi_entity_assigned (void* entity);
+int divas_um_idi_entity_start_remove (void* entity);
+
+void diva_um_idi_start_wdog (void* entity);
+void diva_um_idi_stop_wdog (void* entity);
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/um_xdi.h b/drivers/isdn/hardware/eicon/um_xdi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/um_xdi.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,69 @@
+/* $Id: um_xdi.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_USER_MODE_XDI_H__
+#define __DIVA_USER_MODE_XDI_H__
+
+/*
+  Contains declaratiom of structures shared between application
+  and user mode idi driver
+*/
+
+typedef struct _diva_um_idi_adapter_features {
+  dword type;
+  dword features;
+  dword channels;
+  dword serial_number;
+  char  name [128];
+} diva_um_idi_adapter_features_t;
+
+#define DIVA_UM_IDI_REQ_MASK			0x0000FFFF
+#define DIVA_UM_IDI_REQ_TYPE_MASK		(~(DIVA_UM_IDI_REQ_MASK))
+#define DIVA_UM_IDI_GET_FEATURES		1	/* trigger features indication */
+#define DIVA_UM_IDI_REQ				2
+#define DIVA_UM_IDI_REQ_TYPE_MAN		0x10000000
+#define DIVA_UM_IDI_REQ_TYPE_SIG		0x20000000
+#define DIVA_UM_IDI_REQ_TYPE_NET		0x30000000
+#define DIVA_UM_IDI_REQ_MAN			(DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_MAN)
+#define DIVA_UM_IDI_REQ_SIG			(DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_SIG)
+#define DIVA_UM_IDI_REQ_NET			(DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_NET)
+/*
+  data_length  bytes will follow this structure
+*/
+typedef struct _diva_um_idi_req_hdr {
+  dword type;
+  dword Req;
+  dword ReqCh;
+  dword data_length;
+} diva_um_idi_req_hdr_t;
+
+typedef struct _diva_um_idi_ind_parameters {
+  dword Ind;
+  dword IndCh;
+} diva_um_idi_ind_parameters_t;
+
+typedef struct _diva_um_idi_rc_parameters {
+  dword Rc;
+  dword RcCh;
+} diva_um_idi_rc_parameters_t;
+
+typedef union _diva_um_idi_ind {
+  diva_um_idi_adapter_features_t  features;
+  diva_um_idi_ind_parameters_t    ind;
+  diva_um_idi_rc_parameters_t     rc;
+} diva_um_idi_ind_t;
+
+#define DIVA_UM_IDI_IND_FEATURES  1  /* features indication */
+#define DIVA_UM_IDI_IND           2
+#define DIVA_UM_IDI_IND_RC        3
+/*
+  data_length bytes of data follow
+  this structure
+*/
+typedef struct _diva_um_idi_ind_hdr {
+  dword type;
+  diva_um_idi_ind_t  hdr;
+  dword  data_length;
+} diva_um_idi_ind_hdr_t;
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/xdi_adapter.h b/drivers/isdn/hardware/eicon/xdi_adapter.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/xdi_adapter.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,67 @@
+/* $Id: xdi_adapter.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_OS_XDI_ADAPTER_H__
+#define __DIVA_OS_XDI_ADAPTER_H__
+
+#define DIVAS_XDI_ADAPTER_BUS_PCI  0
+#define DIVAS_XDI_ADAPTER_BUS_ISA  1
+
+typedef struct _divas_pci_card_resources {
+	byte	bus;
+	byte	func;
+	void* hdev;
+
+	dword bar[8]; /* contains context of appropriate BAR Register */
+	void* addr[8]; /* same bar, but mapped into memory */
+	dword length[8]; /* bar length */
+
+	byte   irq;
+} divas_pci_card_resources_t;
+
+typedef union _divas_card_resources {
+	divas_pci_card_resources_t pci;
+} divas_card_resources_t;
+
+struct _diva_os_xdi_adapter;
+typedef int (*diva_init_card_proc_t)(struct _diva_os_xdi_adapter* a);
+typedef int (*diva_cmd_card_proc_t)(struct _diva_os_xdi_adapter* a,
+                                    diva_xdi_um_cfg_cmd_t* data, int length);
+typedef void (*diva_xdi_clear_interrupts_proc_t)(struct _diva_os_xdi_adapter*);
+
+#define DIVA_XDI_MBOX_BUSY			1
+#define DIVA_XDI_MBOX_WAIT_XLOG	2
+
+typedef struct _xdi_mbox_t {
+  dword  status;
+  diva_xdi_um_cfg_cmd_data_t cmd_data;
+  dword  data_length;
+  void  *data;
+} xdi_mbox_t;
+
+typedef struct _diva_os_idi_adapter_interface {
+	diva_init_card_proc_t	cleanup_adapter_proc;
+	diva_cmd_card_proc_t	cmd_proc;
+} diva_os_idi_adapter_interface_t;
+
+typedef struct _diva_os_xdi_adapter {
+  diva_entity_link_t  link;
+  int  CardIndex;
+  int  CardOrdinal;
+  int  controller; /* number of this controller */
+  int  Bus; /* PCI, ISA, ... */
+  divas_card_resources_t  resources;
+  char  port_name[24];
+  ISDN_ADAPTER  xdi_adapter;
+  xdi_mbox_t  xdi_mbox;
+  diva_os_idi_adapter_interface_t  interface;
+  struct _diva_os_xdi_adapter*  slave_adapters[3];
+  void*  slave_list;
+  void*  proc_adapter_dir;  /* adapterX proc entry */
+  void*  proc_info;         /* info proc entry     */
+  void*  proc_grp_opt;      /* group_optimization  */
+  void*  proc_d_l1_down;    /* dynamic_l1_down     */
+  volatile diva_xdi_clear_interrupts_proc_t clear_interrupts_proc;
+  dword dsp_mask;
+} diva_os_xdi_adapter_t;
+
+#endif
diff -Nru a/drivers/isdn/hardware/eicon/xdi_msg.h b/drivers/isdn/hardware/eicon/xdi_msg.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/xdi_msg.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,128 @@
+/* $Id: xdi_msg.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_XDI_UM_CFG_MESSSGE_H__
+#define __DIVA_XDI_UM_CFG_MESSAGE_H__
+
+/*
+  Definition of messages used to communicate between
+  XDI device driver and user mode configuration utility
+*/
+
+/*
+  As acknowledge one DWORD - card ordinal will be read from the card
+*/
+#define DIVA_XDI_UM_CMD_GET_CARD_ORDINAL	0
+
+/*
+  no acknowledge will be generated, memory block will be written in the
+  memory at given offset
+*/
+#define DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK	1
+
+/*
+  no acknowledge will be genatated, FPGA will be programmed
+*/
+#define DIVA_XDI_UM_CMD_WRITE_FPGA				2
+
+/*
+  As acknowledge block of SDRAM will be read in the user buffer
+*/
+#define DIVA_XDI_UM_CMD_READ_SDRAM				3
+
+/*
+  As acknowledge dword with serial number will be read in the user buffer
+*/
+#define DIVA_XDI_UM_CMD_GET_SERIAL_NR			4
+
+/*
+  As acknowledge struct consisting from 9 dwords with PCI info.
+  dword[0...7] = 8 PCI BARS
+  dword[9]		 = IRQ
+*/
+#define DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG	5
+
+/*
+  Reset of the board + activation of primary
+  boot loader
+*/
+#define DIVA_XDI_UM_CMD_RESET_ADAPTER			6
+
+/*
+  Called after code download to start adapter
+  at specified address
+  Start does set new set of features due to fact that we not know
+  if protocol features have changed
+*/
+#define DIVA_XDI_UM_CMD_START_ADAPTER			7
+
+/*
+  Stop adapter, called if user
+  wishes to stop adapter without unload
+  of the driver, to reload adapter with
+  different protocol
+*/
+#define DIVA_XDI_UM_CMD_STOP_ADAPTER			8
+
+/*
+  Get state of current adapter
+  Acknowledge is one dword with following values:
+  0 - adapter ready for download
+  1 - adapter running
+  2 - adapter dead
+  3 - out of service, driver should be restarted or hardware problem
+*/
+#define DIVA_XDI_UM_CMD_GET_CARD_STATE		9
+
+/*
+  Reads XLOG entry from the card
+*/
+#define DIVA_XDI_UM_CMD_READ_XLOG_ENTRY		10
+
+/*
+  Set untranslated protocol code features
+  */
+#define DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES	11
+
+typedef struct _diva_xdi_um_cfg_cmd_data_set_features {
+	dword features;
+} diva_xdi_um_cfg_cmd_data_set_features_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_start {
+	dword offset;
+	dword features;
+} diva_xdi_um_cfg_cmd_data_start_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_write_sdram {
+	dword	ram_number;
+	dword	offset;
+	dword	length;
+} diva_xdi_um_cfg_cmd_data_write_sdram_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_write_fpga {
+	dword	fpga_number;
+	dword	image_length;
+} diva_xdi_um_cfg_cmd_data_write_fpga_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_read_sdram {
+	dword	ram_number;
+	dword	offset;
+	dword	length;
+} diva_xdi_um_cfg_cmd_data_read_sdram_t;
+
+typedef union _diva_xdi_um_cfg_cmd_data {
+	diva_xdi_um_cfg_cmd_data_write_sdram_t	write_sdram;
+	diva_xdi_um_cfg_cmd_data_write_fpga_t	write_fpga;
+	diva_xdi_um_cfg_cmd_data_read_sdram_t	read_sdram;
+	diva_xdi_um_cfg_cmd_data_start_t	start;
+  diva_xdi_um_cfg_cmd_data_set_features_t features;
+} diva_xdi_um_cfg_cmd_data_t;
+
+typedef struct _diva_xdi_um_cfg_cmd {
+  dword  adapter; /* Adapter number 1...N */
+  dword  command;
+  diva_xdi_um_cfg_cmd_data_t  command_data;
+  dword  data_length; /* Plain binary data will follow */
+} diva_xdi_um_cfg_cmd_t;
+
+#endif
+
diff -Nru a/drivers/isdn/hardware/eicon/xdi_vers.h b/drivers/isdn/hardware/eicon/xdi_vers.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hardware/eicon/xdi_vers.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,26 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  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 later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  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.
+ *
+ */
+static char diva_xdi_common_code_build[] = "102-52"; 
diff -Nru a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
--- a/drivers/isdn/hisax/config.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/isdn/hisax/config.c	Fri Oct 11 21:23:03 2002
@@ -1173,7 +1173,6 @@
 	cs->tx_skb = NULL;
 	cs->tx_cnt = 0;
 	cs->event = 0;
-	cs->tqueue.sync = 0;
 	cs->tqueue.data = cs;
 
 	skb_queue_head_init(&cs->rq);
diff -Nru a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
--- a/drivers/isdn/hisax/ipacx.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/isdn/hisax/ipacx.c	Fri Oct 11 21:22:58 2002
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/workqueue.h>
 #include "hisax_if.h"
 #include "hisax.h"
 #include "isdnl1.h"
@@ -509,7 +510,7 @@
 {
 	printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
 
-	INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh);
+	INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs);
 	cs->setstack_d      = dch_setstack;
   
 	cs->dbusytimer.function = (void *) dbusy_timer_handler;
diff -Nru a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
--- a/drivers/isdn/i4l/isdn_common.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/isdn/i4l/isdn_common.c	Fri Oct 11 21:22:55 2002
@@ -503,11 +503,14 @@
 						retval = 2;
 					}
 					break;
-				case 1:
+				case 1: /* incoming call accepted by net interface */
 					list_for_each(l, &isdn_net_devs) {
 						isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
 						if (p->isdn_slot == i) {
 							strcpy(cmd.parm.setup.eazmsn, p->mlp->msn);
+							isdn_slot_set_usage(i, (isdn_slot_usage(i) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
+							strcpy(isdn_slot_num(i), c->parm.setup.phone);
+
 							isdn_slot_command(i, ISDN_CMD_ACCEPTD, &cmd);
 							retval = 1;
 							break;
@@ -1535,26 +1538,20 @@
 		if (USG_NONE(slot[i].usage) &&
 		    (slot[i].di != -1)) {
 			int d = slot[i].di;
-			if ((slot[i].usage & ISDN_USAGE_EXCLUSIVE) &&
-			((pre_dev != d) || (pre_chan != slot[i].ch)))
-				continue;
 			if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
 				continue;
 			if (slot[i].usage & ISDN_USAGE_DISABLED)
 			        continue; /* usage not allowed */
-			if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
-				if (((dev->drv[d]->interface->features & features) == features) ||
-				    (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
-				     (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
-					if ((pre_dev < 0) || (pre_chan < 0)) {
-						isdn_slot_set_usage(i, (isdn_slot_usage(i) & ISDN_USAGE_EXCLUSIVE) | usage);
-						restore_flags(flags);
-						return i;
-					} else if ((pre_dev == d) && (pre_chan == slot[i].ch)) {
-						isdn_slot_set_usage(i, (isdn_slot_usage(i) & ISDN_USAGE_EXCLUSIVE) | usage);
-						restore_flags(flags);
-						return i;
-					}
+			if (!dev->drv[d]->flags & DRV_FLAG_RUNNING)
+				continue;
+			if (((dev->drv[d]->interface->features & features) == features) ||
+			    (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
+			     (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
+				if (pre_dev < 0 || pre_chan < 0 ||
+				    (pre_dev == d && pre_chan == slot[i].ch)) {
+					isdn_slot_set_usage(i, usage);
+					restore_flags(flags);
+					return i;
 				}
 			}
 		}
@@ -1571,50 +1568,27 @@
 	int sl;
 
 	sl = isdn_dc2minor(di, ch);
-	isdn_slot_free(sl, usage);
+	isdn_slot_free(sl);
 }
 
 void
-isdn_slot_free(int sl, int usage)
+isdn_slot_free(int sl)
 {
 	unsigned long flags;
 
 	save_flags(flags);
 	cli();
-	if (!usage || (slot[sl].usage & ISDN_USAGE_MASK) == usage) {
-		strcpy(isdn_slot_num(sl), "???");
-		slot[sl].ibytes = 0;
-		slot[sl].obytes = 0;
+	strcpy(isdn_slot_num(sl), "???");
+	slot[sl].ibytes = 0;
+	slot[sl].obytes = 0;
 // 20.10.99 JIM, try to reinitialize v110 !
-		slot[sl].iv110.v110emu = 0;
-		atomic_set(&slot[sl].iv110.v110use, 0);
-		isdn_v110_close(slot[sl].iv110.v110);
-		slot[sl].iv110.v110 = NULL;
+	slot[sl].iv110.v110emu = 0;
+	atomic_set(&slot[sl].iv110.v110use, 0);
+	isdn_v110_close(slot[sl].iv110.v110);
+	slot[sl].iv110.v110 = NULL;
 // 20.10.99 JIM, try to reinitialize v110 !
-		isdn_slot_set_usage(sl, isdn_slot_usage(sl) & (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE));
-		skb_queue_purge(&dev->drv[isdn_slot_driver(sl)]->rpqueue[isdn_slot_channel(sl)]);
-	}
-	restore_flags(flags);
-}
-
-/*
- * Cancel Exclusive-Flag for ISDN-channel
- */
-void
-isdn_unexclusive_channel(int di, int ch)
-{
-	int i;
-	ulong flags;
-
-	save_flags(flags);
-	cli();
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-		if ((slot[i].di == di) &&
-		    (slot[i].ch == ch)) {
-			isdn_slot_set_usage(i, isdn_slot_usage(i) & ~ISDN_USAGE_EXCLUSIVE);
-			restore_flags(flags);
-			return;
-		}
+	isdn_slot_set_usage(sl, ISDN_USAGE_NONE);
+	skb_queue_purge(&dev->drv[isdn_slot_driver(sl)]->rpqueue[isdn_slot_channel(sl)]);
 	restore_flags(flags);
 }
 
@@ -1959,6 +1933,7 @@
 	case ISDN_CMD_DIAL:
 		if (dev->global_flags & ISDN_GLOBAL_STOPPED)
 			return -EBUSY;
+
 		/* fall through */
 	default:
 		ctrl->arg = isdn_slot_channel(sl);
diff -Nru a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
--- a/drivers/isdn/i4l/isdn_common.h	Fri Oct 11 21:22:53 2002
+++ b/drivers/isdn/i4l/isdn_common.h	Fri Oct 11 21:22:53 2002
@@ -64,7 +64,6 @@
 extern void isdn_info_update(void);
 extern char *isdn_map_eaz2msn(char *msn, int di);
 extern void isdn_timer_ctrl(int tf, int onoff);
-extern void isdn_unexclusive_channel(int di, int ch);
 extern int isdn_getnum(char **);
 extern int isdn_msncmp( const char *,  const char *);
 extern int isdn_add_channels(driver *, int, int, int);
@@ -85,7 +84,7 @@
 };
 
 extern int   isdn_get_free_slot(int, int, int, int, int, char *);
-extern void  isdn_slot_free(int slot, int usage);
+extern void  isdn_slot_free(int slot);
 extern void  isdn_slot_all_eaz(int slot);
 extern int   isdn_slot_command(int slot, int cmd, isdn_ctrl *);
 extern int   isdn_slot_dial(int slot, struct dial_info *dial);
diff -Nru a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
--- a/drivers/isdn/i4l/isdn_concap.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/isdn/i4l/isdn_concap.c	Fri Oct 11 21:22:55 2002
@@ -19,7 +19,7 @@
 #include "isdn_net.h"
 #include <linux/concap.h>
 #include "isdn_concap.h"
-
+#include <linux/if_arp.h>
 
 /* The following set of device service operations are for encapsulation
    protocols that require for reliable datalink semantics. That means:
@@ -253,5 +253,3 @@
 	.open                = isdn_x25_open,
 	.close               = isdn_x25_close,
 };
-
-#endif /* CONFIG_ISDN_X25 */
diff -Nru a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
--- a/drivers/isdn/i4l/isdn_net.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/isdn/i4l/isdn_net.c	Fri Oct 11 21:23:05 2002
@@ -424,163 +424,6 @@
 }
 
 /*
- * An incoming call-request has arrived.
- * Search the interface-chain for an appropriate interface.
- * If found, connect the interface to the ISDN-channel and initiate
- * D- and B-Channel-setup. If secure-flag is set, accept only
- * configured phone-numbers. If callback-flag is set, initiate
- * callback-dialing.
- *
- * Return-Value: 0 = No appropriate interface for this call.
- *               1 = Call accepted
- *               2 = Reject call, wait cbdelay, then call back
- *               3 = Reject call
- *               4 = Wait cbdelay, then call back
- *               5 = No appropriate interface for this call,
- *                   would eventually match if CID was longer.
- */
-int
-isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
-{
-	char *eaz;
-	unsigned char si1, si2;
-	int match_more = 0;
-	int retval;
-	struct list_head *l;
-	struct isdn_net_phone *n;
-	ulong flags;
-	char nr[32];
-	char *my_eaz;
-
-	int slot = isdn_dc2minor(di, ch);
-	/* Search name in netdev-chain */
-	save_flags(flags);
-	cli();
-	if (!setup->phone[0]) {
-		nr[0] = '0';
-		nr[1] = '\0';
-		printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
-	} else {
-		strcpy(nr, setup->phone);
-	}
-	si1 = setup->si1;
-	si2 = setup->si2;
-	if (!setup->eazmsn[0]) {
-		printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
-		eaz = "0";
-	} else {
-		eaz = setup->eazmsn;
-	}
-	if (dev->net_verbose > 1)
-		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
-        /* Accept DATA and VOICE calls at this stage
-        local eaz is checked later for allowed call types */
-        if ((si1 != 7) && (si1 != 1)) {
-                restore_flags(flags);
-                if (dev->net_verbose > 1)
-                        printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
-                return 0;
-        }
-
-	n = NULL;
-	dbg_net_icall("n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
-		      isdn_slot_usage(idx));
-
-	list_for_each(l, &isdn_net_devs) {
-		isdn_net_dev *idev = list_entry(l, isdn_net_dev, global_list);
-		isdn_net_local *mlp = idev->mlp;
-
-                /* check acceptable call types for DOV */
-		dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d\n",
-			      idev->name, mlp->msn, mlp->flags, idev->fi.state);
-
-                my_eaz = isdn_slot_map_eaz2msn(slot, mlp->msn);
-                if (si1 == 1) { /* it's a DOV call, check if we allow it */
-                        if (*my_eaz == 'v' || *my_eaz == 'V' ||
-			    *my_eaz == 'b' || *my_eaz == 'B')
-                                my_eaz++; /* skip to allow a match */
-                        else
-                                continue; /* force non match */
-                } else { /* it's a DATA call, check if we allow it */
-                        if (*my_eaz == 'b' || *my_eaz == 'B')
-                                my_eaz++; /* skip to allow a match */
-                }
-
-		switch (isdn_msncmp(eaz, my_eaz)) {
-		case 1:
-			continue;
-		case 2:
-			match_more = 1;
-			continue;
-		}
-
-		if (isdn_net_bound(idev))
-			continue;
-		
-		if (!USG_NONE(isdn_slot_usage(idx)))
-			continue;
-
-		dbg_net_icall("n_fi: match1, pdev=%d pch=%d\n",
-			      idev->pre_device, idev->pre_channel);
-
-		if (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE &&
-		    (idev->pre_channel != ch || idev->pre_device != di)) {
-			dbg_net_icall("n_fi: excl check failed\n");
-			continue;
-		}
-		dbg_net_icall("n_fi: match2\n");
-		if (mlp->flags & ISDN_NET_SECURE) {
-			list_for_each_entry(n, &mlp->phone[0], list) {
-				if (!isdn_msncmp(nr, n->num)) {
-					goto found;
-				}
-			}
-			continue;
-		}
-	found:
-		dbg_net_icall("n_fi: match3\n");
-		/* matching interface found */
-		
-		/*
-		 * Is the state STOPPED?
-		 * If so, no dialin is allowed,
-		 * so reject actively.
-		 * */
-		if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
-			restore_flags(flags);
-			printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
-			       idev->name);
-			return 3;
-		}
-		/*
-		 * Is the interface up?
-		 * If not, reject the call actively.
-		 */
-		if (!isdn_net_device_started(idev)) {
-			restore_flags(flags);
-			printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
-			       idev->name);
-			return 3;
-		}
-                if (mlp->flags & ISDN_NET_CALLBACK) {
-                        retval = isdn_net_do_callback(idev);
-                        restore_flags(flags);
-                        return retval;
-                }
-		printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
-		       idev->name, nr, eaz);
-
-		isdn_net_accept(idev, idx, nr);
-		restore_flags(flags);
-		return 1;
-	}
-	if (dev->net_verbose)
-		printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, slot, eaz);
-	restore_flags(flags);
-	return (match_more == 2) ? 5:0;
-}
-
-/*
  * This is called from certain upper protocol layers (multilink ppp
  * and x25iface encapsulation module) that want to initiate dialing
  * themselves.
diff -Nru a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
--- a/drivers/isdn/i4l/isdn_net.h	Fri Oct 11 21:23:03 2002
+++ b/drivers/isdn/i4l/isdn_net.h	Fri Oct 11 21:23:03 2002
@@ -43,11 +43,7 @@
 extern int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev);
 extern int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev);
 
-extern int  isdn_net_bind_channel(isdn_net_dev *idev, int slot);
-extern void isdn_net_unbind_channel(isdn_net_dev *idev);
 extern int  isdn_net_dial(isdn_net_dev *idev);
-extern void isdn_net_accept(isdn_net_dev *idev, int slot, char *nr);
-extern int  isdn_net_do_callback(isdn_net_dev *idev);
 
 extern int  isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c);
 
diff -Nru a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c
--- a/drivers/isdn/i4l/isdn_net_lib.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/isdn/i4l/isdn_net_lib.c	Fri Oct 11 21:22:51 2002
@@ -10,6 +10,33 @@
  * of the GNU General Public License, incorporated herein by reference.
  */
 
+/* Locking works as follows: 
+ *
+ * The configuration of isdn_net_devs works via ioctl on
+ * /dev/isdnctrl (for legacy reasons).
+ * All configuration accesses are globally serialized by means of
+ * the global semaphore &sem.
+ * 
+ * All other uses of isdn_net_dev will only happen when the corresponding
+ * struct net_device has been opened. So in the non-config code we can
+ * rely on the config data not changing under us.
+ *
+ * To achieve this, in the "writing" ioctls, that is those which may change
+ * data, additionally grep the rtnl semaphore and check to make sure
+ * that the net_device has not been openend ("netif_running()")
+ *
+ * isdn_net_dev's are added to the global list "isdn_net_devs" in the
+ * configuration ioctls, so accesses to that list are protected by
+ * &sem as well.
+ *
+ * Incoming calls are signalled in IRQ context, so we cannot take &sem
+ * while walking the list of devices. To handle this, we put devices
+ * onto a "running" list, which is protected by a spin lock and can thus
+ * be traversed in IRQ context. If a matching isdn_net_dev is found,
+ * it's ref count shall be incremented, to make sure no racing
+ * net_device::close() can take it away under us. 
+ */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -28,6 +55,31 @@
 static DECLARE_MUTEX(sem);
 LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */ // FIXME static
 
+/* Reference counting for net devices (they work on isdn_net_local *,
+ * but count references to the related isdn_net_dev's as well.
+ * Basic rule: When state of isdn_net_dev changes from ST_NULL -> sth,
+ * get a reference, when it changes back to ST_NULL, put it
+ */ 
+
+static inline void
+lp_get(isdn_net_local *lp)
+{
+	if (atomic_read(&lp->refcnt) < 1)
+		isdn_BUG();
+
+	atomic_inc(&lp->refcnt);
+}
+
+static inline void
+lp_put(isdn_net_local *lp)
+{
+	atomic_dec(&lp->refcnt);
+
+	/* the last reference, the list should always remain */
+	if (atomic_read(&lp->refcnt) < 1)
+		isdn_BUG();
+}
+
 int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg); /* FIXME */
 
 static void isdn_net_tasklet(unsigned long data);
@@ -39,6 +91,7 @@
 
 enum {
 	ST_NULL,
+	ST_OUT_BOUND,
 	ST_OUT_WAIT_DCONN,
 	ST_OUT_WAIT_BCONN,
 	ST_IN_WAIT_DCONN,
@@ -51,6 +104,7 @@
 
 static char *isdn_net_st_str[] = {
 	"ST_NULL",
+	"ST_OUT_BOUND",
 	"ST_OUT_WAIT_DCONN",
 	"ST_OUT_WAIT_BCONN",
 	"ST_IN_WAIT_DCONN",
@@ -74,7 +128,9 @@
 	EV_STAT_BHUP,
 	EV_STAT_CINF,
 	EV_STAT_BSENT,
-	EV_CMD_DIAL,
+	EV_DO_DIAL,
+	EV_DO_CALLBACK,
+	EV_DO_ACCEPT,
 };
 
 static char *isdn_net_ev_str[] = {
@@ -90,7 +146,9 @@
 	"EV_STAT_BHUP",
 	"EV_STAT_CINF",
 	"EV_STAT_BSENT",
-	"EV_CMD_DIAL",
+	"EV_DO_DIAL",
+	"EV_DO_CALLBACK",
+	"EV_DO_ACCEPT",
 };
 
 /* ====================================================================== */
@@ -225,21 +283,18 @@
 		goto out;
 	}
 	if (idev->exclusive >= 0) {
-		isdn_unexclusive_channel(idev->pre_device, idev->pre_channel);
-		isdn_free_channel(idev->pre_device, idev->pre_channel, ISDN_USAGE_NET);
+		isdn_slot_free(idev->exclusive);
 		idev->exclusive = -1;
 	}
 	if (cfg->exclusive) {
 		/* If binding is exclusive, try to grab the channel */
-		idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto, 
-						     mlp->l3_proto, drvidx, chidx, cfg->eaz);
+		idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET | ISDN_USAGE_EXCLUSIVE, 
+						     mlp->l2_proto, mlp->l3_proto, drvidx, chidx, cfg->eaz);
 		if (idev->exclusive < 0) {
 			/* Grab failed, because desired channel is in use */
 			retval = -EBUSY;
 			goto out;
 		}
-		/* All went ok, so update isdninfo */
-		isdn_slot_set_usage(idev->exclusive, ISDN_USAGE_EXCLUSIVE);
 	}
 	idev->pre_device = drvidx;
 	idev->pre_channel = chidx;
@@ -360,6 +415,7 @@
 		}
 	}
 	list_add(&idev->global_list, &isdn_net_devs);
+
 	return 0;
 }
 
@@ -417,7 +473,7 @@
 	isdn_net_rmallphone(idev);
 
 	if (idev->exclusive >= 0)
-		isdn_unexclusive_channel(idev->pre_device, idev->pre_channel);
+		isdn_slot_free(idev->exclusive);
 
 	list_del(&idev->slaves);
 	
@@ -978,6 +1034,9 @@
 /* interface to network layer                                             */
 /* ====================================================================== */
 
+static spinlock_t running_devs_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(running_devs);
+
 /* 
  * Open/initialize the board.
  */
@@ -985,6 +1044,7 @@
 isdn_net_open(struct net_device *dev)
 {
 	isdn_net_local *lp = dev->priv;
+	unsigned long flags;
 	int retval = 0;
 
 	if (!lp->ops)
@@ -997,6 +1057,12 @@
 		return retval;
 	
 	netif_start_queue(dev);
+
+	atomic_set(&lp->refcnt, 1);
+	spin_lock_irqsave(&running_devs_lock, flags);
+	list_add(&lp->running_devs, &running_devs);
+	spin_unlock_irqrestore(&running_devs_lock, flags);
+
 	return 0;
 }
 
@@ -1008,8 +1074,9 @@
 isdn_net_close(struct net_device *dev)
 {
 	isdn_net_local *lp = dev->priv;
-	struct list_head *l, *n;
 	isdn_net_dev *sdev;
+	struct list_head *l, *n;
+	unsigned long flags;
 
 	if (lp->ops->close)
 		lp->ops->close(lp);
@@ -1020,6 +1087,20 @@
 		sdev = list_entry(l, isdn_net_dev, online);
 		isdn_net_hangup(sdev);
 	}
+	/* The hangup will make the refcnt drop back to
+	 * 1 (referenced by list only) soon. */
+	spin_lock_irqsave(&running_devs_lock, flags);
+	while (atomic_read(&dev->refcnt) != 1) {
+		spin_unlock_irqrestore(&running_devs_lock, flags);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/10);
+		spin_lock_irqsave(&running_devs_lock, flags);
+	}
+	/* We have the only reference and list lock, so
+	 * nobody can get another reference. */
+	list_del(&lp->running_devs);
+	spin_unlock_irqrestore(&running_devs_lock, flags);
+
 	return 0;
 }
 
@@ -1102,42 +1183,12 @@
 }
 
 /*
- * Assign an ISDN-channel to a net-interface
- */
-int
-isdn_net_bind_channel(isdn_net_dev *idev, int slot)
-{
-	isdn_net_local *mlp = idev->mlp;
-	int retval = 0;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	idev->isdn_slot = slot;
-	isdn_slot_set_idev(idev->isdn_slot, idev);
-
-	if (mlp->ops->bind)
-		retval = mlp->ops->bind(idev);
-
-	if (retval < 0)
-		isdn_net_unbind_channel(idev);
-
-	restore_flags(flags);
-	return retval;
-}
-
-/*
  * Unbind a net-interface
  */
-void
+static void
 isdn_net_unbind_channel(isdn_net_dev *idev)
 {
 	isdn_net_local *mlp = idev->mlp;
-	ulong flags;
-
-	save_flags(flags);
-	cli();
 
 	if (idev->isdn_slot < 0) {
 		isdn_BUG();
@@ -1147,58 +1198,66 @@
 	if (mlp->ops->unbind)
 		mlp->ops->unbind(idev);
 
+	isdn_slot_set_idev(idev->isdn_slot, NULL);
+
 	skb_queue_purge(&idev->super_tx_queue);
 
-	fsm_change_state(&idev->fi, ST_NULL);
-
-	isdn_slot_set_idev(idev->isdn_slot, NULL);
-	isdn_slot_free(idev->isdn_slot, ISDN_USAGE_NET);
+	if (idev->isdn_slot != idev->exclusive)
+		isdn_slot_free(idev->isdn_slot);
 
 	idev->isdn_slot = -1;
 
-	restore_flags(flags);
+	if (idev->fi.state != ST_NULL) {
+		lp_put(mlp);
+		fsm_change_state(&idev->fi, ST_NULL);
+	}
 }
 
-int
-isdn_net_dial(isdn_net_dev *idev)
+/*
+ * Assign an ISDN-channel to a net-interface
+ */
+static int
+isdn_net_bind_channel(isdn_net_dev *idev, int slot)
 {
-	int slot;
 	isdn_net_local *mlp = idev->mlp;
+	int retval = 0;
 
-	if (isdn_net_bound(idev))
-		return -EBUSY;
+	idev->isdn_slot = slot;
+	isdn_slot_set_idev(idev->isdn_slot, idev);
 
-	if (idev->exclusive >= 0)
-		slot = idev->exclusive;
-	else
-		slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
-					  mlp->l3_proto, idev->pre_device, 
-					  idev->pre_channel, mlp->msn);
-	if (slot < 0)
-		goto err;
+	if (mlp->ops->bind)
+		retval = mlp->ops->bind(idev);
+
+	if (retval < 0)
+		isdn_net_unbind_channel(idev);
+
+	return retval;
+}
 
-	isdn_slot_set_usage(slot, isdn_slot_usage(slot) | ISDN_USAGE_OUTGOING);
+int
+isdn_net_dial(isdn_net_dev *idev)
+{
+	int retval;
 
-	if (isdn_net_bind_channel(idev, slot) < 0)
-		goto err;
+	lp_get(idev->mlp);
+	retval = fsm_event(&idev->fi, EV_DO_DIAL, NULL);
+	if (retval == -ESRCH) /* event not handled in this state */
+		retval = -EBUSY;
 
-	/* Initiate dialing */
-	fsm_event(&idev->fi, EV_CMD_DIAL, NULL);
-	return 0;
+	if (retval)
+		lp_put(idev->mlp);
 
- err:
-	return -EAGAIN;
+	return retval;
 }
 
-void
-isdn_net_accept(isdn_net_dev *idev, int slot, char *nr)
+static int
+accept_icall(struct fsm_inst *fi, int pr, void *arg)
 {
+	isdn_net_dev *idev = fi->userdata;
 	isdn_net_local *mlp = idev->mlp;
 	isdn_ctrl cmd;
+	int slot = (int) arg;
 
-	strcpy(isdn_slot_num(slot), nr);
-	isdn_slot_set_usage(slot, (isdn_slot_usage(slot) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
-	
 	isdn_net_bind_channel(idev, slot);
 	
 	idev->outgoing = 0;
@@ -1215,47 +1274,191 @@
 	idev->dial_event = EV_TIMER_INCOMING;
 	add_timer(&idev->dial_timer);
 	fsm_change_state(&idev->fi, ST_IN_WAIT_DCONN);
+	return 0;
 }
 
-int
-isdn_net_do_callback(isdn_net_dev *idev)
+static int
+do_callback(struct fsm_inst *fi, int pr, void *arg)
 {
+	isdn_net_dev *idev = fi->userdata;
 	isdn_net_local *mlp = idev->mlp;
-	int slot;
-	/*
-	 * Is the state MANUAL?
-	 * If so, no callback can be made,
-	 * so reject actively.
-	 */
+
+	printk(KERN_DEBUG "%s: start callback\n", idev->name);
+
+	idev->dial_timer.expires = jiffies + mlp->cbdelay;
+	idev->dial_event = EV_TIMER_CB_IN;
+	add_timer(&idev->dial_timer);
+	fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB);
+
+	return 0;
+}
+
+static int
+isdn_net_dev_icall(isdn_net_dev *idev, int di, int ch, int si1,
+		   char *eaz, char *nr)
+{
+	isdn_net_local *mlp = idev->mlp;
+	struct isdn_net_phone *ph;
+	int slot = isdn_dc2minor(di, ch);
+	char *my_eaz;
+	
+	/* check acceptable call types for DOV */
+	dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d\n",
+		      idev->name, mlp->msn, mlp->flags, idev->fi.state);
+	
+	my_eaz = isdn_slot_map_eaz2msn(slot, mlp->msn);
+	if (si1 == 1) { /* it's a DOV call, check if we allow it */
+		if (*my_eaz == 'v' || *my_eaz == 'V' ||
+		    *my_eaz == 'b' || *my_eaz == 'B')
+			my_eaz++; /* skip to allow a match */
+		else
+			return 0; /* no match */
+	} else { /* it's a DATA call, check if we allow it */
+		if (*my_eaz == 'b' || *my_eaz == 'B')
+			my_eaz++; /* skip to allow a match */
+	}
+	if (!USG_NONE(isdn_slot_usage(slot)))  // FIXME?
+		return 0;
+
+	/* check called number */
+	switch (isdn_msncmp(eaz, my_eaz)) {
+	case 1: /* no match */
+		return 0;
+	case 2: /* matches so far */
+		return 5;
+	}
+
+	dbg_net_icall("%s: pdev=%d di=%d pch=%d ch = %d\n", idev->name,
+		      idev->pre_device, di, idev->pre_channel, ch);
+	
+	/* check if exclusive */
+	if ((isdn_slot_usage(slot) & ISDN_USAGE_EXCLUSIVE) &&
+	    (idev->pre_channel != ch || idev->pre_device != di)) {
+		dbg_net_icall("%s: excl check failed\n", idev->name);
+		return 0;
+	}
+	
+	/* check calling number */
+	dbg_net_icall("%s: secure\n", idev->name);
+	if (mlp->flags & ISDN_NET_SECURE) {
+		list_for_each_entry(ph, &mlp->phone[0], list) {
+			if (isdn_msncmp(nr, ph->num) == 0)
+					goto found;
+		}
+		return 0;
+	}
+ found:
+	/* check dial mode */
 	if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
-		printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
+		printk(KERN_INFO "%s: incoming call, stopped -> rejected\n",
 		       idev->name);
 		return 3;
 	}
-	printk(KERN_DEBUG "%s: start callback\n", idev->name);
-	
-	/* Grab a free ISDN-Channel */
-	slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto, mlp->l3_proto,
-				  idev->pre_device, idev->pre_channel, mlp->msn);
-	if (slot < 0)
-		goto err;
+	lp_get(mlp);
+	/* check callback */
+	if (mlp->flags & ISDN_NET_CALLBACK) {
+		if (fsm_event(&idev->fi, EV_DO_CALLBACK, NULL)) {
+			lp_put(mlp);
+			return 0;
+		}
+		/* Initiate dialing by returning 2 or 4 */
+		return (mlp->flags & ISDN_NET_CBHUP) ? 2 : 4;
+	}
+	printk(KERN_INFO "%s: call from %s -> %s accepted\n",
+	       idev->name, nr, eaz);
 
-	isdn_slot_set_usage(slot, isdn_slot_usage(slot) | ISDN_USAGE_OUTGOING);
+	if (fsm_event(&idev->fi, EV_DO_ACCEPT, (void *) slot)) {
+		lp_put(mlp);
+		return 0;
+	}
+	return 1; // accepted
+}
 
-	if (isdn_net_bind_channel(idev, slot) < 0)
-		goto err;
+/*
+ * An incoming call-request has arrived.
+ * Search the interface-chain for an appropriate interface.
+ * If found, connect the interface to the ISDN-channel and initiate
+ * D- and B-Channel-setup. If secure-flag is set, accept only
+ * configured phone-numbers. If callback-flag is set, initiate
+ * callback-dialing.
+ *
+ * Return-Value: 0 = No appropriate interface for this call.
+ *               1 = Call accepted
+ *               2 = Reject call, wait cbdelay, then call back
+ *               3 = Reject call
+ *               4 = Wait cbdelay, then call back
+ *               5 = No appropriate interface for this call,
+ *                   would eventually match if CID was longer.
+ */
+int
+isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
+{
+	isdn_net_local *lp;
+	isdn_net_dev *idev;
+	char *nr, *eaz;
+	unsigned char si1, si2;
+	int retval;
+	unsigned long flags;
 
-	/* Setup dialstate. */
-	idev->dial_timer.expires = jiffies + mlp->cbdelay;
-	idev->dial_event = EV_TIMER_CB_IN;
-	add_timer(&idev->dial_timer);
-	fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB);
+	/* fix up calling number */
+	if (!setup->phone[0]) {
+		printk(KERN_INFO
+		       "isdn_net: Incoming call without OAD, assuming '0'\n");
+		nr = "0";
+	} else {
+		nr = setup->phone;
+	}
+	/* fix up called number */
+	if (!setup->eazmsn[0]) {
+		printk(KERN_INFO
+		       "isdn_net: Incoming call without CPN, assuming '0'\n");
+		eaz = "0";
+	} else {
+		eaz = setup->eazmsn;
+	}
+	si1 = setup->si1;
+	si2 = setup->si2;
+	if (dev->net_verbose > 1)
+		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", 
+		       nr, si1, si2, eaz);
+	/* check service indicator */
+        /* Accept DATA and VOICE calls at this stage
+	   local eaz is checked later for allowed call types */
+        if ((si1 != 7) && (si1 != 1)) {
+                if (dev->net_verbose > 1)
+                        printk(KERN_INFO "isdn_net: "
+			       "Service-Indicator not 1 or 7, ignored\n");
+                return 0;
+        }
 
-	/* Initiate dialing by returning 2 or 4 */
-	return (mlp->flags & ISDN_NET_CBHUP) ? 2 : 4;
+	dbg_net_icall("n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
+		      isdn_slot_usage(idx));
 
- err:
-	return 0;
+	retval = 0;
+	spin_lock_irqsave(&running_devs_lock, flags);
+	list_for_each_entry(lp, &running_devs, running_devs) {
+		lp_get(lp);
+		spin_unlock_irqrestore(&running_devs_lock, flags);
+
+		list_for_each_entry(idev, &lp->slaves, slaves) {
+			retval = isdn_net_dev_icall(idev, di, ch, si1, eaz, nr);
+			if (retval > 0)
+				break;
+		}
+
+		spin_lock_irqsave(&running_devs_lock, flags);
+		lp_put(lp);
+		if (retval > 0)
+			break;
+		
+	}
+	spin_unlock_irqrestore(&running_devs_lock, flags);
+	if (!retval) {
+		if (dev->net_verbose)
+			printk(KERN_INFO "isdn_net: call "
+			       "from %s -> %s ignored\n", nr, eaz);
+	}
+	return retval;
 }
 
 /* ---------------------------------------------------------------------- */
@@ -1283,23 +1486,39 @@
 /* Initiate dialout. */
 
 static int
-dialout_first(struct fsm_inst *fi, int pr, void *arg)
+do_dial(struct fsm_inst *fi, int pr, void *arg)
 {
 	isdn_net_dev *idev = fi->userdata;
 	isdn_net_local *mlp = idev->mlp;
+	int slot;
 
-	if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
-		isdn_net_unbind_channel(idev);
+	if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF)
 		return -EPERM;
-	}
-	if (list_empty(&mlp->phone[1])) {
-		isdn_net_unbind_channel(idev);
+
+	if (list_empty(&mlp->phone[1])) /* no number to dial ? */
 		return -EINVAL;
+
+	if (idev->exclusive >= 0)
+		slot = idev->exclusive;
+	else
+		slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
+					  mlp->l3_proto, idev->pre_device, 
+					  idev->pre_channel, mlp->msn);
+	if (slot < 0)
+		return -EAGAIN;
+
+	if (isdn_net_bind_channel(idev, slot) < 0) {
+		/* has freed the slot as well */
+		return -EAGAIN;
 	}
 
+	fsm_change_state(fi, ST_OUT_BOUND);
+
 	idev->dial = 0;
 	idev->dialretry = 0;
-	return dialout_next(fi, pr, arg);
+
+	dialout_next(fi, pr, arg);
+	return 0;
 }
 
 /* Try dialing the next number. */
@@ -1598,7 +1817,9 @@
 }
 
 static struct fsm_node isdn_net_fn_tbl[] = {
-	{ ST_NULL,           EV_CMD_DIAL,        dialout_first },
+	{ ST_NULL,           EV_DO_DIAL,         do_dial       },
+	{ ST_NULL,           EV_DO_ACCEPT,       accept_icall  },
+	{ ST_NULL,           EV_DO_CALLBACK,     do_callback   },
 
 	{ ST_OUT_WAIT_DCONN, EV_TIMER_DIAL,      dial_timeout  },
 	{ ST_OUT_WAIT_DCONN, EV_STAT_DCONN,      out_dconn     },
@@ -1624,7 +1845,7 @@
 
 	{ ST_WAIT_DHUP,      EV_STAT_DHUP,       dhup          },
 
-	{ ST_WAIT_BEFORE_CB, EV_TIMER_CB_IN,     dialout_first },
+	{ ST_WAIT_BEFORE_CB, EV_TIMER_CB_IN,     do_dial       },
 
 	{ ST_OUT_DIAL_WAIT,  EV_TIMER_DIAL_WAIT, dialout_next  },
 };
diff -Nru a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
--- a/drivers/isdn/i4l/isdn_tty.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/isdn/i4l/isdn_tty.c	Fri Oct 11 21:22:54 2002
@@ -745,7 +745,7 @@
 
 	isdn_slot_all_eaz(slot);
 	info->emu.mdmreg[REG_RINGCNT] = 0;
-	isdn_slot_free(slot, 0);
+	isdn_slot_free(slot);
 	isdn_slot_set_m_idx(slot, -1);
 	info->isdn_slot = -1;
 }
diff -Nru a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
--- a/drivers/isdn/i4l/isdn_ttyfax.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/isdn/i4l/isdn_ttyfax.c	Fri Oct 11 21:22:51 2002
@@ -382,7 +382,7 @@
 		info->isdn_slot = i;
 		isdn_slot_set_m_idx(i, info->line);
 		isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
-		isdn_slot_free(info->isdn_slot, ISDN_USAGE_FAX);
+		isdn_slot_free(info->isdn_slot);
 		isdn_slot_set_m_idx(i, -1);
 		info->isdn_slot = -1;
 		restore_flags(flags);
diff -Nru a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c
--- a/drivers/isdn/pcbit/callbacks.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/isdn/pcbit/callbacks.c	Fri Oct 11 21:23:05 2002
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/tqueue.h>
 #include <linux/skbuff.h>
 
 #include <asm/io.h>
diff -Nru a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
--- a/drivers/isdn/pcbit/capi.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/isdn/pcbit/capi.c	Fri Oct 11 21:23:02 2002
@@ -35,7 +35,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 
-#include <linux/tqueue.h>
 #include <linux/skbuff.h>
 
 #include <asm/io.h>
diff -Nru a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c
--- a/drivers/isdn/pcbit/edss1.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/isdn/pcbit/edss1.c	Fri Oct 11 21:22:53 2002
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/tqueue.h>
 #include <linux/skbuff.h>
 
 #include <linux/timer.h>
diff -Nru a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
--- a/drivers/isdn/pcbit/module.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/isdn/pcbit/module.c	Fri Oct 11 21:23:00 2002
@@ -14,7 +14,6 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
-#include <linux/tqueue.h>
 #include <linux/skbuff.h>
 
 #include <linux/isdnif.h>
diff -Nru a/drivers/isdn/tpam/tpam_commands.c b/drivers/isdn/tpam/tpam_commands.c
--- a/drivers/isdn/tpam/tpam_commands.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/isdn/tpam/tpam_commands.c	Fri Oct 11 21:22:53 2002
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
-#include <linux/tqueue.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 
diff -Nru a/drivers/isdn/tpam/tpam_main.c b/drivers/isdn/tpam/tpam_main.c
--- a/drivers/isdn/tpam/tpam_main.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/isdn/tpam/tpam_main.c	Fri Oct 11 21:22:54 2002
@@ -14,8 +14,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
+
 #include <linux/init.h>
 #include <asm/io.h>
 
diff -Nru a/drivers/isdn/tpam/tpam_nco.c b/drivers/isdn/tpam/tpam_nco.c
--- a/drivers/isdn/tpam/tpam_nco.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/isdn/tpam/tpam_nco.c	Fri Oct 11 21:22:54 2002
@@ -14,7 +14,6 @@
 
 #include <linux/pci.h>
 #include <linux/sched.h>
-#include <linux/tqueue.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 
diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
--- a/drivers/macintosh/adbhid.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/macintosh/adbhid.c	Fri Oct 11 21:23:05 2002
@@ -479,6 +479,8 @@
 	memset(adbhid[id], 0, sizeof(struct adbhid));
 	sprintf(adbhid[id]->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id);
 
+	init_input_dev(&adbhid[id]);
+
 	adbhid[id]->id = default_id;
 	adbhid[id]->original_handler_id = original_handler_id;
 	adbhid[id]->current_handler_id = current_handler_id;
diff -Nru a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
--- a/drivers/macintosh/mac_hid.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/macintosh/mac_hid.c	Fri Oct 11 21:23:03 2002
@@ -91,6 +91,8 @@
 {
 	emumousebtn.name = "Macintosh mouse button emulation";
 
+	init_input_dev(&emumousebtn);
+
 	emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 	emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y);
diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
--- a/drivers/macintosh/macserial.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/macintosh/macserial.c	Fri Oct 11 21:22:56 2002
@@ -755,7 +755,7 @@
 	}
 
 	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
 		if (!info->xmit_buf)
 			return -ENOMEM;
 	}
@@ -2276,7 +2276,7 @@
 	info->tty = tty;
 
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page)
 			return -ENOMEM;
 		if (tmp_buf)
diff -Nru a/drivers/md/Makefile b/drivers/md/Makefile
--- a/drivers/md/Makefile	Fri Oct 11 21:22:50 2002
+++ b/drivers/md/Makefile	Fri Oct 11 21:22:50 2002
@@ -19,3 +19,4 @@
 obj-$(CONFIG_BLK_DEV_LVM)	+= lvm-mod.o
 
 include $(TOPDIR)/Rules.make
+
diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c
--- a/drivers/md/linear.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/md/linear.c	Fri Oct 11 21:22:56 2002
@@ -72,10 +72,12 @@
 		goto out;
 	}
 
-	nb_zone = conf->nr_zones =
-		md_size[mdidx(mddev)] / conf->smallest->size +
-		((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0);
-  
+	{
+		sector_t sz = md_size[mdidx(mddev)];
+		unsigned round = sector_div(sz, conf->smallest->size);
+		nb_zone = conf->nr_zones = sz + (round ? 1 : 0);
+	}
+			
 	conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone,
 					GFP_KERNEL);
 	if (!conf->hash_table)
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/md/md.c	Fri Oct 11 21:22:55 2002
@@ -103,7 +103,7 @@
 static void md_recover_arrays(void);
 static mdk_thread_t *md_recovery_thread;
 
-int md_size[MAX_MD_DEVS];
+sector_t md_size[MAX_MD_DEVS];
 
 static struct block_device_operations md_fops;
 static devfs_handle_t devfs_handle;
@@ -243,35 +243,35 @@
 	return NULL;
 }
 
-static unsigned int calc_dev_sboffset(struct block_device *bdev)
+static sector_t calc_dev_sboffset(struct block_device *bdev)
 {
-	unsigned int size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+	sector_t size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
 	return MD_NEW_SIZE_BLOCKS(size);
 }
 
-static unsigned int calc_dev_size(struct block_device *bdev, mddev_t *mddev)
+static sector_t calc_dev_size(struct block_device *bdev, mddev_t *mddev)
 {
-	unsigned int size;
+	sector_t size;
 
 	if (mddev->persistent)
 		size = calc_dev_sboffset(bdev);
 	else
 		size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
 	if (mddev->chunk_size)
-		size &= ~(mddev->chunk_size/1024 - 1);
+		size &= ~((sector_t)mddev->chunk_size/1024 - 1);
 	return size;
 }
 
-static unsigned int zoned_raid_size(mddev_t *mddev)
+static sector_t zoned_raid_size(mddev_t *mddev)
 {
-	unsigned int mask;
+	sector_t mask;
 	mdk_rdev_t * rdev;
 	struct list_head *tmp;
 
 	/*
 	 * do size and offset calculations.
 	 */
-	mask = ~(mddev->chunk_size/1024 - 1);
+	mask = ~((sector_t)mddev->chunk_size/1024 - 1);
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		rdev->size &= mask;
@@ -362,7 +362,7 @@
 
 static int read_disk_sb(mdk_rdev_t * rdev)
 {
-	unsigned long sb_offset;
+	sector_t sb_offset;
 
 	if (!rdev->sb) {
 		MD_BUG();
@@ -614,9 +614,9 @@
 
 static void print_rdev(mdk_rdev_t *rdev)
 {
-	printk(KERN_INFO "md: rdev %s, SZ:%08ld F:%d S:%d DN:%d ",
+	printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%d ",
 		bdev_partition_name(rdev->bdev),
-		rdev->size, rdev->faulty, rdev->in_sync, rdev->desc_nr);
+		(unsigned long long)rdev->size, rdev->faulty, rdev->in_sync, rdev->desc_nr);
 	if (rdev->sb) {
 		printk(KERN_INFO "md: rdev superblock:\n");
 		print_sb(rdev->sb);
@@ -698,7 +698,8 @@
 
 static int write_disk_sb(mdk_rdev_t * rdev)
 {
-	unsigned long sb_offset, size;
+	sector_t sb_offset;
+	sector_t size;
 
 	if (!rdev->sb) {
 		MD_BUG();
@@ -715,8 +716,10 @@
 
 	sb_offset = calc_dev_sboffset(rdev->bdev);
 	if (rdev->sb_offset != sb_offset) {
-		printk(KERN_INFO "%s's sb offset has changed from %ld to %ld, skipping\n",
-		       bdev_partition_name(rdev->bdev), rdev->sb_offset, sb_offset);
+		printk(KERN_INFO "%s's sb offset has changed from %llu to %llu, skipping\n",
+		       bdev_partition_name(rdev->bdev), 
+		    (unsigned long long)rdev->sb_offset, 
+		    (unsigned long long)sb_offset);
 		goto skip;
 	}
 	/*
@@ -726,12 +729,14 @@
 	 */
 	size = calc_dev_size(rdev->bdev, rdev->mddev);
 	if (size != rdev->size) {
-		printk(KERN_INFO "%s's size has changed from %ld to %ld since import, skipping\n",
-		       bdev_partition_name(rdev->bdev), rdev->size, size);
+		printk(KERN_INFO "%s's size has changed from %llu to %llu since import, skipping\n",
+		       bdev_partition_name(rdev->bdev),
+		       (unsigned long long)rdev->size, 
+		       (unsigned long long)size);
 		goto skip;
 	}
 
-	printk(KERN_INFO "(write) %s's sb offset: %ld\n", bdev_partition_name(rdev->bdev), sb_offset);
+	printk(KERN_INFO "(write) %s's sb offset: %llu\n", bdev_partition_name(rdev->bdev), (unsigned long long)sb_offset);
 
 	if (!sync_page_io(rdev->bdev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE))
 		goto fail;
@@ -929,7 +934,7 @@
 {
 	int err;
 	mdk_rdev_t *rdev;
-	unsigned int size;
+	sector_t size;
 
 	rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL);
 	if (!rdev) {
@@ -1209,9 +1214,9 @@
 		rdev->size = calc_dev_size(rdev->bdev, mddev);
 		if (rdev->size < mddev->chunk_size / 1024) {
 			printk(KERN_WARNING
-				"md: Dev %s smaller than chunk_size: %ldk < %dk\n",
+				"md: Dev %s smaller than chunk_size: %lluk < %dk\n",
 				bdev_partition_name(rdev->bdev),
-				rdev->size, mddev->chunk_size / 1024);
+				(unsigned long long)rdev->size, mddev->chunk_size / 1024);
 			return -EINVAL;
 		}
 	}
@@ -1401,6 +1406,12 @@
 	mddev->pers = pers[pnum];
 
 	blk_queue_make_request(&mddev->queue, mddev->pers->make_request);
+	printk("%s: setting max_sectors to %d, segment boundary to %d\n",
+	       disk->disk_name,
+	       chunk_size >> 9,
+	       (chunk_size>>1)-1);
+	blk_queue_max_sectors(&mddev->queue, chunk_size >> 9);
+	blk_queue_segment_boundary(&mddev->queue, (chunk_size>>1) - 1);
 	mddev->queue.queuedata = mddev;
 
 	err = mddev->pers->run(mddev);
@@ -1872,7 +1883,7 @@
 
 static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
 {
-	int size;
+	sector_t size;
 	mdk_rdev_t *rdev;
 	dev_t dev;
 	dev = MKDEV(info->major,info->minor);
@@ -2025,8 +2036,9 @@
 	size = calc_dev_size(rdev->bdev, mddev);
 
 	if (size < mddev->size) {
-		printk(KERN_WARNING "md%d: disk size %d blocks < array size %ld\n",
-				mdidx(mddev), size, mddev->size);
+		printk(KERN_WARNING "md%d: disk size %llu blocks < array size %llu\n",
+				mdidx(mddev), (unsigned long long)size, 
+				(unsigned long long)mddev->size);
 		err = -ENOSPC;
 		goto abort_export;
 	}
@@ -2628,7 +2640,8 @@
 static int md_status_read_proc(char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
-	int sz = 0, j, size;
+	int sz = 0, j;
+	sector_t size;
 	struct list_head *tmp, *tmp2;
 	mdk_rdev_t *rdev;
 	mddev_t *mddev;
@@ -2662,10 +2675,10 @@
 
 		if (!list_empty(&mddev->disks)) {
 			if (mddev->pers)
-				sz += sprintf(page + sz, "\n      %d blocks",
-						 md_size[mdidx(mddev)]);
+				sz += sprintf(page + sz, "\n      %llu blocks",
+						 (unsigned long long)md_size[mdidx(mddev)]);
 			else
-				sz += sprintf(page + sz, "\n      %d blocks", size);
+				sz += sprintf(page + sz, "\n      %llu blocks", (unsigned long long)size);
 		}
 
 		if (!mddev->pers) {
diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/md/multipath.c	Fri Oct 11 21:22:57 2002
@@ -130,8 +130,8 @@
 		 * oops, IO error:
 		 */
 		md_error (mp_bh->mddev, rdev);
-		printk(KERN_ERR "multipath: %s: rescheduling sector %lu\n", 
-		       bdev_partition_name(rdev->bdev), bio->bi_sector);
+		printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", 
+		       bdev_partition_name(rdev->bdev), (unsigned long long)bio->bi_sector);
 		multipath_reschedule_retry(mp_bh);
 	}
 	atomic_dec(&rdev->nr_pending);
@@ -320,10 +320,10 @@
 }
 
 #define IO_ERROR KERN_ALERT \
-"multipath: %s: unrecoverable IO read error for block %lu\n"
+"multipath: %s: unrecoverable IO read error for block %llu\n"
 
 #define REDIRECT_SECTOR KERN_ERR \
-"multipath: %s: redirecting sector %lu to another IO path\n"
+"multipath: %s: redirecting sector %llu to another IO path\n"
 
 /*
  * This is a kernel thread which:
@@ -356,11 +356,11 @@
 		rdev = NULL;
 		if (multipath_map (mddev, &rdev)<0) {
 			printk(IO_ERROR,
-				bdev_partition_name(bio->bi_bdev), bio->bi_sector);
+				bdev_partition_name(bio->bi_bdev), (unsigned long long)bio->bi_sector);
 			multipath_end_bh_io(mp_bh, 0);
 		} else {
 			printk(REDIRECT_SECTOR,
-				bdev_partition_name(bio->bi_bdev), bio->bi_sector);
+				bdev_partition_name(bio->bi_bdev), (unsigned long long)bio->bi_sector);
 			bio->bi_bdev = rdev->bdev;
 			generic_make_request(bio);
 		}
diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c
--- a/drivers/md/raid0.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/md/raid0.c	Fri Oct 11 21:22:59 2002
@@ -30,7 +30,7 @@
 static int create_strip_zones (mddev_t *mddev)
 {
 	int i, c, j;
-	unsigned long current_offset, curr_zone_offset;
+	sector_t current_offset, curr_zone_offset;
 	raid0_conf_t *conf = mddev_to_conf(mddev);
 	mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev;
 	struct list_head *tmp1, *tmp2;
@@ -46,9 +46,9 @@
 		printk("raid0: looking at %s\n", bdev_partition_name(rdev1->bdev));
 		c = 0;
 		ITERATE_RDEV(mddev,rdev2,tmp2) {
-			printk("raid0:   comparing %s(%ld) with %s(%ld)\n",
-			       bdev_partition_name(rdev1->bdev), rdev1->size,
-			       bdev_partition_name(rdev2->bdev), rdev2->size);
+			printk("raid0:   comparing %s(%llu) with %s(%llu)\n",
+			       bdev_partition_name(rdev1->bdev), (unsigned long long)rdev1->size,
+			       bdev_partition_name(rdev2->bdev), (unsigned long long)rdev2->size);
 			if (rdev2 == rdev1) {
 				printk("raid0:   END\n");
 				break;
@@ -135,7 +135,8 @@
 				c++;
 				if (!smallest || (rdev->size <smallest->size)) {
 					smallest = rdev;
-					printk("  (%ld) is smallest!.\n", rdev->size);
+					printk("  (%llu) is smallest!.\n", 
+					       (unsigned long long)rdev->size);
 				}
 			} else
 				printk(" nope.\n");
@@ -143,7 +144,7 @@
 
 		zone->nb_dev = c;
 		zone->size = (smallest->size - current_offset) * c;
-		printk("raid0: zone->nb_dev: %d, size: %ld\n",zone->nb_dev,zone->size);
+		printk("raid0: zone->nb_dev: %d, size: %llu\n",zone->nb_dev, (unsigned long long)zone->size);
 
 		if (!conf->smallest || (zone->size < conf->smallest->size))
 			conf->smallest = zone;
@@ -152,7 +153,7 @@
 		curr_zone_offset += zone->size;
 
 		current_offset = smallest->size;
-		printk("raid0: current zone offset: %ld\n", current_offset);
+		printk("raid0: current zone offset: %llu\n", (unsigned long long)current_offset);
 	}
 	printk("raid0: done.\n");
 	return 0;
@@ -163,7 +164,9 @@
 
 static int raid0_run (mddev_t *mddev)
 {
-	unsigned long cur=0, i=0, size, zone0_size, nb_zone;
+	unsigned  cur=0, i=0, nb_zone;
+	sector_t zone0_size;
+	s64 size;
 	raid0_conf_t *conf;
 
 	MOD_INC_USE_COUNT;
@@ -176,16 +179,21 @@
 	if (create_strip_zones (mddev)) 
 		goto out_free_conf;
 
-	printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]);
-	printk("raid0 : conf->smallest->size is %ld blocks.\n", conf->smallest->size);
-	nb_zone = md_size[mdidx(mddev)]/conf->smallest->size +
-			(md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0);
-	printk("raid0 : nb_zone is %ld.\n", nb_zone);
+	printk("raid0 : md_size is %llu blocks.\n", (unsigned long long)md_size[mdidx(mddev)]);
+	printk("raid0 : conf->smallest->size is %llu blocks.\n", (unsigned long long)conf->smallest->size);
+	{
+#if __GNUC__ < 3
+		volatile
+#endif
+		sector_t s = md_size[mdidx(mddev)];
+		int round = sector_div(s, (unsigned long)conf->smallest->size) ? 1 : 0;
+		nb_zone = s + round;
+	}
+	printk("raid0 : nb_zone is %d.\n", nb_zone);
 	conf->nr_zones = nb_zone;
 
-	printk("raid0 : Allocating %ld bytes for hash.\n",
+	printk("raid0 : Allocating %d bytes for hash.\n",
 				nb_zone*sizeof(struct raid0_hash));
-
 	conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone);
 	if (!conf->hash_table)
 		goto out_free_zone_conf;
@@ -269,15 +277,22 @@
 	struct raid0_hash *hash;
 	struct strip_zone *zone;
 	mdk_rdev_t *tmp_dev;
-	unsigned long chunk, block, rsect;
+	unsigned long chunk;
+	sector_t block, rsect;
 
 	chunk_size = mddev->chunk_size >> 10;
 	chunksize_bits = ffz(~chunk_size);
 	block = bio->bi_sector >> 1;
-	hash = conf->hash_table + block / conf->smallest->size;
+	
+
+	{
+		sector_t x = block;
+		sector_div(x, (unsigned long)conf->smallest->size);
+		hash = conf->hash_table + x;
+	}
 
 	/* Sanity check */
-	if (chunk_size < (block % chunk_size) + (bio->bi_size >> 10))
+	if (chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10))
 		goto bad_map;
  
 	if (!hash)
@@ -294,8 +309,18 @@
 		zone = hash->zone0;
     
 	sect_in_chunk = bio->bi_sector & ((chunk_size<<1) -1);
-	chunk = (block - zone->zone_offset) / (zone->nb_dev << chunksize_bits);
-	tmp_dev = zone->dev[(block >> chunksize_bits) % zone->nb_dev];
+
+
+	{
+		sector_t x =  block - zone->zone_offset;
+
+		sector_div(x, (zone->nb_dev << chunksize_bits));
+		chunk = x;
+		BUG_ON(x != (sector_t)chunk);
+
+		x = block >> chunksize_bits;
+		tmp_dev = zone->dev[sector_div(x, zone->nb_dev)];
+	}
 	rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1)
 		+ sect_in_chunk;
  
@@ -312,16 +337,16 @@
 	return 1;
 
 bad_map:
-	printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bio->bi_sector, bio->bi_size >> 10);
+	printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %llu %d\n", chunk_size, (unsigned long long)bio->bi_sector, bio->bi_size >> 10);
 	goto outerr;
 bad_hash:
-	printk("raid0_make_request bug: hash==NULL for block %ld\n", block);
+	printk("raid0_make_request bug: hash==NULL for block %llu\n", (unsigned long long)block);
 	goto outerr;
 bad_zone0:
-	printk ("raid0_make_request bug: hash->zone0==NULL for block %ld\n", block);
+	printk ("raid0_make_request bug: hash->zone0==NULL for block %llu\n", (unsigned long long)block);
 	goto outerr;
 bad_zone1:
-	printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block);
+	printk ("raid0_make_request bug: hash->zone1==NULL for block %llu\n", (unsigned long long)block);
  outerr:
 	bio_io_error(bio, bio->bi_size);
 	return 0;
diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c
--- a/drivers/md/raid1.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/md/raid1.c	Fri Oct 11 21:22:59 2002
@@ -298,8 +298,8 @@
 			/*
 			 * oops, read error:
 			 */
-			printk(KERN_ERR "raid1: %s: rescheduling sector %lu\n",
-			       bdev_partition_name(conf->mirrors[mirror].rdev->bdev), r1_bio->sector);
+			printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n",
+			       bdev_partition_name(conf->mirrors[mirror].rdev->bdev), (unsigned long long)r1_bio->sector);
 			reschedule_retry(r1_bio);
 		}
 	} else {
@@ -747,10 +747,10 @@
 }
 
 #define IO_ERROR KERN_ALERT \
-"raid1: %s: unrecoverable I/O read error for block %lu\n"
+"raid1: %s: unrecoverable I/O read error for block %llu\n"
 
 #define REDIRECT_SECTOR KERN_ERR \
-"raid1: %s: redirecting sector %lu to another mirror\n"
+"raid1: %s: redirecting sector %llu to another mirror\n"
 
 static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
 {
@@ -827,7 +827,7 @@
 		 * There is no point trying a read-for-reconstruct as
 		 * reconstruct is about to be aborted
 		 */
-		printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), r1_bio->sector);
+		printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), (unsigned long long)r1_bio->sector);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
 		resume_device(conf);
 		put_buf(r1_bio);
@@ -878,7 +878,8 @@
 		 * Nowhere to write this to... I guess we
 		 * must be done
 		 */
-		printk(KERN_ALERT "raid1: sync aborting as there is nowhere to write sector %lu\n", r1_bio->sector);
+		printk(KERN_ALERT "raid1: sync aborting as there is nowhere to write sector %llu\n", 
+			(unsigned long long)r1_bio->sector);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
 		resume_device(conf);
 		put_buf(r1_bio);
@@ -931,12 +932,12 @@
 		case READ:
 		case READA:
 			if (map(mddev, &rdev) == -1) {
-				printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), r1_bio->sector);
+				printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), (unsigned long long)r1_bio->sector);
 				raid_end_bio_io(r1_bio, 0);
 				break;
 			}
 			printk(REDIRECT_SECTOR,
-				bdev_partition_name(rdev->bdev), r1_bio->sector);
+				bdev_partition_name(rdev->bdev), (unsigned long long)r1_bio->sector);
 			bio->bi_bdev = rdev->bdev;
 			bio->bi_sector = r1_bio->sector;
 			bio->bi_rw = r1_bio->cmd;
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/md/raid5.c	Fri Oct 11 21:22:54 2002
@@ -30,13 +30,15 @@
 
 #define NR_STRIPES		256
 #define STRIPE_SIZE		PAGE_SIZE
+#define STRIPE_SHIFT		(PAGE_SHIFT - 9)
 #define STRIPE_SECTORS		(STRIPE_SIZE>>9)
 #define	IO_THRESHOLD		1
 #define HASH_PAGES		1
 #define HASH_PAGES_ORDER	0
 #define NR_HASH			(HASH_PAGES * PAGE_SIZE / sizeof(struct stripe_head *))
 #define HASH_MASK		(NR_HASH - 1)
-#define stripe_hash(conf, sect)	((conf)->stripe_hashtbl[((sect) / STRIPE_SECTORS) & HASH_MASK])
+
+#define stripe_hash(conf, sect)	((conf)->stripe_hashtbl[((sect) >> STRIPE_SHIFT) & HASH_MASK])
 
 /*
  * The following can be used to debug the driver
@@ -96,7 +98,7 @@
 
 static void remove_hash(struct stripe_head *sh)
 {
-	PRINTK("remove_hash(), stripe %lu\n", sh->sector);
+	PRINTK("remove_hash(), stripe %llu\n", (unsigned long long)sh->sector);
 
 	if (sh->hash_pprev) {
 		if (sh->hash_next)
@@ -110,7 +112,7 @@
 {
 	struct stripe_head **shp = &stripe_hash(conf, sh->sector);
 
-	PRINTK("insert_hash(), stripe %lu\n",sh->sector);
+	PRINTK("insert_hash(), stripe %llu\n", (unsigned long long)sh->sector);
 
 	CHECK_DEVLOCK();
 	if ((sh->hash_next = *shp) != NULL)
@@ -180,7 +182,7 @@
 		BUG();
 	
 	CHECK_DEVLOCK();
-	PRINTK("init_stripe called, stripe %lu\n", sh->sector);
+	PRINTK("init_stripe called, stripe %llu\n", (unsigned long long)sh->sector);
 
 	remove_hash(sh);
 	
@@ -193,8 +195,8 @@
 
 		if (dev->toread || dev->towrite || dev->written ||
 		    test_bit(R5_LOCKED, &dev->flags)) {
-			printk("sector=%lx i=%d %p %p %p %d\n",
-			       sh->sector, i, dev->toread,
+			printk("sector=%llx i=%d %p %p %p %d\n",
+			       (unsigned long long)sh->sector, i, dev->toread,
 			       dev->towrite, dev->written,
 			       test_bit(R5_LOCKED, &dev->flags));
 			BUG();
@@ -336,7 +338,7 @@
 		if (bi == &sh->dev[i].req)
 			break;
 
-	PRINTK("end_read_request %lu/%d, count: %d, uptodate %d.\n", sh->sector, i, atomic_read(&sh->count), uptodate);
+	PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), uptodate);
 	if (i == disks) {
 		BUG();
 		return 0;
@@ -407,7 +409,7 @@
 		if (bi == &sh->dev[i].req)
 			break;
 
-	PRINTK("end_write_request %lu/%d, count %d, uptodate: %d.\n", sh->sector, i, atomic_read(&sh->count), uptodate);
+	PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), uptodate);
 	if (i == disks) {
 		BUG();
 		return 0;
@@ -427,7 +429,7 @@
 }
 
 
-static unsigned long compute_blocknr(struct stripe_head *sh, int i);
+static sector_t compute_blocknr(struct stripe_head *sh, int i);
 	
 static void raid5_build_block (struct stripe_head *sh, int i)
 {
@@ -482,7 +484,7 @@
 			unsigned int data_disks, unsigned int * dd_idx,
 			unsigned int * pd_idx, raid5_conf_t *conf)
 {
-	sector_t stripe;
+	long stripe;
 	unsigned long chunk_number;
 	unsigned int chunk_offset;
 	sector_t new_sector;
@@ -493,8 +495,9 @@
 	/*
 	 * Compute the chunk number and the sector offset inside the chunk
 	 */
-	chunk_number = r_sector / sectors_per_chunk;
-	chunk_offset = r_sector % sectors_per_chunk;
+	chunk_offset = sector_div(r_sector, sectors_per_chunk);
+	chunk_number = r_sector;
+	BUG_ON(r_sector != chunk_number);
 
 	/*
 	 * Compute the stripe number
@@ -548,11 +551,16 @@
 	int raid_disks = conf->raid_disks, data_disks = raid_disks - 1;
 	sector_t new_sector = sh->sector, check;
 	int sectors_per_chunk = conf->chunk_size >> 9;
-	sector_t stripe = new_sector / sectors_per_chunk;
-	int chunk_offset = new_sector % sectors_per_chunk;
+	long stripe;
+	int chunk_offset;
 	int chunk_number, dummy1, dummy2, dd_idx = i;
 	sector_t r_sector;
 
+	chunk_offset = sector_div(new_sector, sectors_per_chunk);
+	stripe = new_sector;
+	BUG_ON(new_sector != stripe);
+
+	
 	switch (conf->algorithm) {
 		case ALGORITHM_LEFT_ASYMMETRIC:
 		case ALGORITHM_RIGHT_ASYMMETRIC:
@@ -570,7 +578,7 @@
 	}
 
 	chunk_number = stripe * data_disks + i;
-	r_sector = chunk_number * sectors_per_chunk + chunk_offset;
+	r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset;
 
 	check = raid5_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf);
 	if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) {
@@ -648,7 +656,7 @@
 	int i, count, disks = conf->raid_disks;
 	void *ptr[MAX_XOR_BLOCKS], *p;
 
-	PRINTK("compute_block, stripe %lu, idx %d\n", sh->sector, dd_idx);
+	PRINTK("compute_block, stripe %llu, idx %d\n", (unsigned long long)sh->sector, dd_idx);
 
 	ptr[0] = page_address(sh->dev[dd_idx].page);
 	memset(ptr[0], 0, STRIPE_SIZE);
@@ -660,7 +668,7 @@
 		if (test_bit(R5_UPTODATE, &sh->dev[i].flags))
 			ptr[count++] = p;
 		else
-			printk("compute_block() %d, stripe %lu, %d not present\n", dd_idx, sh->sector, i);
+			printk("compute_block() %d, stripe %llu, %d not present\n", dd_idx, (unsigned long long)sh->sector, i);
 
 		check_xor();
 	}
@@ -676,7 +684,7 @@
 	void *ptr[MAX_XOR_BLOCKS];
 	struct bio *chosen[MD_SB_DISKS];
 
-	PRINTK("compute_parity, stripe %lu, method %d\n", sh->sector, method);
+	PRINTK("compute_parity, stripe %llu, method %d\n", (unsigned long long)sh->sector, method);
 	memset(chosen, 0, sizeof(chosen));
 
 	count = 1;
@@ -762,7 +770,7 @@
 	struct bio **bip;
 	raid5_conf_t *conf = sh->raid_conf;
 
-	PRINTK("adding bh b#%lu to stripe s#%lu\n", bi->bi_sector, sh->sector);
+	PRINTK("adding bh b#%llu to stripe s#%llu\n", (unsigned long long)bi->bi_sector, (unsigned long long)sh->sector);
 
 
 	spin_lock(&sh->lock);
@@ -783,7 +791,7 @@
 	spin_unlock_irq(&conf->device_lock);
 	spin_unlock(&sh->lock);
 
-	PRINTK("added bi b#%lu to stripe s#%lu, disk %d.\n", bi->bi_sector, sh->sector, dd_idx);
+	PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n", (unsigned long long)bi->bi_sector, (unsigned long long)sh->sector, dd_idx);
 
 	if (forwrite) {
 		/* check if page is coverred */
@@ -831,7 +839,7 @@
 	int failed_num=0;
 	struct r5dev *dev;
 
-	PRINTK("handling stripe %ld, cnt=%d, pd_idx=%d\n", sh->sector, atomic_read(&sh->count), sh->pd_idx);
+	PRINTK("handling stripe %llu, cnt=%d, pd_idx=%d\n", (unsigned long long)sh->sector, atomic_read(&sh->count), sh->pd_idx);
 
 	spin_lock(&sh->lock);
 	clear_bit(STRIPE_HANDLE, &sh->state);
@@ -1035,7 +1043,7 @@
 				else rcw += 2*disks;
 			}
 		}
-		PRINTK("for sector %ld, rmw=%d rcw=%d\n", sh->sector, rmw, rcw);
+		PRINTK("for sector %llu, rmw=%d rcw=%d\n", (unsigned long long)sh->sector, rmw, rcw);
 		set_bit(STRIPE_HANDLE, &sh->state);
 		if (rmw < rcw && rmw > 0)
 			/* prefer read-modify-write, but need to get some data */
@@ -1178,7 +1186,7 @@
 					md_sync_acct(rdev, STRIPE_SECTORS);
 
 				bi->bi_bdev = rdev->bdev;
-				PRINTK("for %ld schedule op %ld on disc %d\n", sh->sector, bi->bi_rw, i);
+				PRINTK("for %llu schedule op %ld on disc %d\n", (unsigned long long)sh->sector, bi->bi_rw, i);
 				atomic_inc(&sh->count);
 				bi->bi_sector = sh->sector;
 				bi->bi_flags = 1 << BIO_UPTODATE;
@@ -1189,7 +1197,7 @@
 				bi->bi_next = NULL;
 				generic_make_request(bi);
 			} else {
-				PRINTK("skip op %ld on disc %d for sector %ld\n", bi->bi_rw, i, sh->sector);
+				PRINTK("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector);
 				clear_bit(R5_LOCKED, &dev->flags);
 				set_bit(STRIPE_HANDLE, &sh->state);
 			}
@@ -1285,8 +1293,9 @@
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	struct stripe_head *sh;
 	int sectors_per_chunk = conf->chunk_size >> 9;
-	unsigned long stripe = sector_nr/sectors_per_chunk;
-	int chunk_offset = sector_nr % sectors_per_chunk;
+	sector_t x;
+	unsigned long stripe;
+	int chunk_offset;
 	int dd_idx, pd_idx;
 	unsigned long first_sector;
 	int raid_disks = conf->raid_disks;
@@ -1296,6 +1305,11 @@
 		/* just being told to finish up .. nothing to do */
 		return 0;
 
+	x = sector_nr;
+	chunk_offset = sector_div(x, sectors_per_chunk);
+	stripe = x;
+	BUG_ON(x != stripe);
+
 	first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk
 		+ chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf);
 	sh = get_active_stripe(conf, sector_nr, pd_idx, 0);
@@ -1510,9 +1524,9 @@
 {
 	int i;
 
-	printk("sh %lu, pd_idx %d, state %ld.\n", sh->sector, sh->pd_idx, sh->state);
-	printk("sh %lu,  count %d.\n", sh->sector, atomic_read(&sh->count));
-	printk("sh %lu, ", sh->sector);
+	printk("sh %llu, pd_idx %d, state %ld.\n", (unsigned long long)sh->sector, sh->pd_idx, sh->state);
+	printk("sh %llu,  count %d.\n", (unsigned long long)sh->sector, atomic_read(&sh->count));
+	printk("sh %llu, ", (unsigned long long)sh->sector);
 	for (i = 0; i < sh->raid_conf->raid_disks; i++) {
 		printk("(cache%d: %p %ld) ", i, sh->dev[i].page, sh->dev[i].flags);
 	}
diff -Nru a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
--- a/drivers/media/radio/radio-cadet.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/media/radio/radio-cadet.c	Fri Oct 11 21:22:57 2002
@@ -57,7 +57,7 @@
  */
 static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
 
-void cadet_wake(unsigned long qnum)
+static void cadet_wake(unsigned long qnum)
 {
         switch(qnum) {
 	case 0:           /* cadet_setfreq */
diff -Nru a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
--- a/drivers/media/radio/radio-zoltrix.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/media/radio/radio-zoltrix.c	Fri Oct 11 21:23:05 2002
@@ -23,6 +23,7 @@
  *		(can detect if station is in stereo)
  *	      - Added unmute function
  *	      - Reworked ioctl functions
+ * 2002-07-15 - Fix Stereo typo
  */
 
 #include <linux/module.h>	/* Modules                        */
@@ -274,7 +275,7 @@
 			struct video_audio *v = arg;
 			memset(&v, 0, sizeof(*v));
 			v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
-			v->mode != zol_is_stereo(zol)
+			v->mode |= zol_is_stereo(zol)
 				? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
 			v->volume = zol->curvol * 4096;
 			v->step = 4096;
diff -Nru a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
--- a/drivers/media/video/cpia.h	Fri Oct 11 21:23:03 2002
+++ b/drivers/media/video/cpia.h	Fri Oct 11 21:23:03 2002
@@ -378,8 +378,8 @@
 /* ErrorCode */
 #define ERROR_FLICKER_BELOW_MIN_EXP     0x01 /*flicker exposure got below minimum exposure */
 
-#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args)
-#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args)
+#define ALOG(fmt,args...) printk(fmt, ##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __FUNCTION__, __LINE__, ##args)
 
 #ifdef _CPIA_DEBUG_
 #define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args)
diff -Nru a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
--- a/drivers/media/video/cpia_usb.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/media/video/cpia_usb.c	Fri Oct 11 21:22:51 2002
@@ -167,7 +167,7 @@
 	/* resubmit */
 	urb->dev = ucpia->dev;
 	if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
-		printk(KERN_ERR __FUNCTION__ ": usb_submit_urb ret %d\n", i);
+		printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __FUNCTION__,  i);
 }
 
 static int cpia_usb_open(void *privdata)
diff -Nru a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
--- a/drivers/media/video/zoran_procfs.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/media/video/zoran_procfs.c	Fri Oct 11 21:23:03 2002
@@ -111,6 +111,9 @@
 
 	zr = (struct zoran *) data;
 
+	if(count > 32768)		/* Stupidity filter */
+		count = 32768;
+
 	string = sp = vmalloc(count + 1);
 	if (!string) {
 		printk(KERN_ERR "%s: write_proc: can not allocate memory\n", zr->name);
diff -Nru a/drivers/media/video/zr36067.c b/drivers/media/video/zr36067.c
--- a/drivers/media/video/zr36067.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/media/video/zr36067.c	Fri Oct 11 21:23:05 2002
@@ -383,7 +383,7 @@
  *
  *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
  *   kmalloc is used to request a physically contiguous area,
- *   else we allocate the memory in framgents with get_free_page.
+ *   else we allocate the memory in framgents with get_zeroed_page.
  *
  *   If a Natoma chipset is present and this is a revision 1 zr36057,
  *   each MJPEG buffer needs to be physically contiguous.
@@ -396,7 +396,7 @@
  *       Therefore there is no need to allocate them with vmalloc in order
  *       to get a contiguous virtual memory space.
  *       I don't understand why many other drivers first allocate them with
- *       vmalloc (which uses internally also get_free_page, but delivers you
+ *       vmalloc (which uses internally also get_zeroed_page, but delivers you
  *       virtual addresses) and then again have to make a lot of efforts
  *       to get the physical address.
  *
@@ -420,10 +420,10 @@
 
 		/* Allocate fragment table for this buffer */
 
-		mem = get_free_page(GFP_KERNEL);
+		mem = get_zeroed_page(GFP_KERNEL);
 		if (mem == 0) {
 			printk(KERN_ERR
-			       "%s: jpg_fbuffer_alloc: get_free_page (frag_tab) failed for buffer %d\n",
+			       "%s: jpg_fbuffer_alloc: get_zeroed_page (frag_tab) failed for buffer %d\n",
 			       zr->name, i);
 			jpg_fbuffer_free(zr);
 			return -ENOBUFS;
@@ -450,10 +450,10 @@
 			/* jpg_bufsize is allreay page aligned */
 			for (j = 0; j < zr->jpg_bufsize / PAGE_SIZE; j++) 
 			{
-				mem = get_free_page(GFP_KERNEL);
+				mem = get_zeroed_page(GFP_KERNEL);
 				if (mem == 0) {
 					printk(KERN_ERR
-					       "%s: jpg_fbuffer_alloc: get_free_page failed for buffer %d\n",
+					       "%s: jpg_fbuffer_alloc: get_zeroed_page failed for buffer %d\n",
 					       zr->name, i);
 					jpg_fbuffer_free(zr);
 					return -ENOBUFS;
@@ -4396,22 +4396,18 @@
 }
 
 static struct video_device zoran_template = {
-	THIS_MODULE,
-	ZORAN_NAME,
-	VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
+	owner:		THIS_MODULE,
+	name:		ZORAN_NAME,
+	type:		VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
 	    VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
-	ZORAN_HARDWARE,
-	zoran_open,
-	zoran_close,
-	zoran_read,
-	zoran_write,
-	NULL,
-	zoran_ioctl,
-	zoran_mmap,
-	zoran_init_done,
-	NULL,
-	0,
-	0
+	hardware:	ZORAN_HARDWARE,
+	open:		zoran_open,
+	close:		zoran_close,
+	read:		zoran_read,
+	write:		zoran_write,
+	ioctl:		zoran_ioctl,
+	mmap:		zoran_mmap,
+	initialize:	zoran_init_done,
 };
 
 /*
diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
--- a/drivers/message/fusion/linux_compat.h	Fri Oct 11 21:22:55 2002
+++ b/drivers/message/fusion/linux_compat.h	Fri Oct 11 21:22:55 2002
@@ -254,8 +254,7 @@
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
 #define mptscsih_save_flags(flags) \
-({	local_save_flags(flags); \
-	local_irq_disable(); \
+({	local_irq_save(flags); \
 })
 #else
 #define mptscsih_save_flags(flags) \
diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
--- a/drivers/message/i2o/i2o_block.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/message/i2o/i2o_block.c	Fri Oct 11 21:23:02 2002
@@ -1,7 +1,7 @@
 /*
  * I2O Random Block Storage Class OSM
  *
- * (C) Copyright 1999 Red Hat Software
+ * (C) Copyright 1999-2002 Red Hat
  *	
  * Written by Alan Cox, Building Number Three Ltd
  *
@@ -10,6 +10,16 @@
  * 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.
+ *
+ * For the purpose of avoiding doubt the preferred form of the work
+ * for making modifications shall be a standards compliant form such
+ * gzipped tar and not one requiring a proprietary or patent encumbered
+ * tool to unpack.
+ *
  * This is a beta test release. Most of the good code was taken
  * from the nbd driver by Pavel Machek, who in turn took some of it
  * from loop.c. Isn't free software great for reusability 8)
@@ -21,6 +31,11 @@
  *	Alan Cox:	
  *		FC920 has an rmw bug. Dont or in the end marker.
  *		Removed queue walk, fixed for 64bitness.
+ *		Rewrote much of the code over time
+ *		Added indirect block lists
+ *		Handle 64K limits on many controllers
+ *		Don't use indirects on the Promise (breaks)
+ *		Heavily chop down the queue depths
  *	Deepak Saxena:
  *		Independent queues per IOP
  *		Support for dynamic device creation/deletion
@@ -45,7 +60,7 @@
 #include <linux/major.h>
 
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
@@ -73,13 +88,12 @@
 #include <linux/wait.h>
 
 #define MAJOR_NR I2O_MAJOR
-#define DEVICE_NR(device) (minor(device)>>4)
 
 #include <linux/blk.h>
 
 #define MAX_I2OB	16
 
-#define MAX_I2OB_DEPTH	128
+#define MAX_I2OB_DEPTH	8
 #define MAX_I2OB_RETRIES 4
 
 //#define DRIVERDEBUG
@@ -125,7 +139,10 @@
  *	Some of these can be made smaller later
  */
 
+static int i2ob_blksizes[MAX_I2OB<<4];
+static int i2ob_sizes[MAX_I2OB<<4];
 static int i2ob_media_change_flag[MAX_I2OB];
+static u32 i2ob_max_sectors[MAX_I2OB<<4];
 
 static int i2ob_context;
 
@@ -143,9 +160,12 @@
 	struct request *head, *tail;
 	request_queue_t *req_queue;
 	int max_segments;
+	int max_direct;		/* Not yet used properly */
 	int done_flag;
-	int constipated;
 	int depth;
+	int rcache;
+	int wcache;
+	int power;
 };
 
 /*
@@ -153,6 +173,7 @@
  *	We should cache align these to avoid ping-ponging lines on SMP
  *	boxes under heavy I/O load...
  */
+
 struct i2ob_request
 {
 	struct i2ob_request *next;
@@ -177,8 +198,6 @@
 	spinlock_t lock;
 };
 static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS];
-static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS];
-static struct i2ob_request *i2ob_backlog_tail[MAX_I2O_CONTROLLERS];
 
 /*
  *	Each I2O disk is one of these.
@@ -186,7 +205,7 @@
 
 static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
 static int i2ob_dev_count = 0;
-static struct gendisk *i2o_disk[MAX_I2OB];
+static struct gendisk *i2ob_disk[MAX_I2OB];
 
 /*
  * Mutex and spin lock for event handling synchronization
@@ -195,10 +214,7 @@
 static DECLARE_MUTEX_LOCKED(i2ob_evt_sem);
 static DECLARE_COMPLETION(i2ob_thread_dead);
 static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED;
-static u32 evt_msg[MSG_FRAME_SIZE>>2];
-
-static struct timer_list i2ob_timer;
-static int i2ob_timer_started = 0;
+static u32 evt_msg[MSG_FRAME_SIZE];
 
 static void i2o_block_reply(struct i2o_handler *, struct i2o_controller *,
 	 struct i2o_message *);
@@ -208,7 +224,6 @@
 static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
 static void i2ob_end_request(struct request *);
 static void i2ob_request(request_queue_t *);
-static int i2ob_backlog_request(struct i2o_controller *, struct i2ob_device *);
 static int i2ob_init_iop(unsigned int);
 static request_queue_t* i2ob_get_queue(kdev_t);
 static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);
@@ -232,8 +247,12 @@
 	I2O_CLASS_RANDOM_BLOCK_STORAGE
 };
 
-/*
- *	Get a message
+/**
+ *	i2ob_get	-	Get an I2O message
+ *	@dev:  I2O block device
+ *
+ *	Get a message from the FIFO used for this block device. The message is returned
+ *	or the I2O 'no message' value of 0xFFFFFFFF if nothing is available.
  */
 
 static u32 i2ob_get(struct i2ob_device *dev)
@@ -242,10 +261,23 @@
    	return I2O_POST_READ32(c);
 }
  
-/*
- *	Turn a Linux block request into an I2O block read/write.
+/**
+ *	i2ob_send		-	Turn a request into a message and send it
+ *	@m: Message offset
+ *	@dev: I2O device
+ *	@ireq: Request structure
+ *	@unit: Device identity
+ *
+ *	Generate an I2O BSAREAD request. This interface function is called for devices that
+ *	appear to explode when they are fed indirect chain pointers (notably right now this
+ *	appears to afflict Promise hardwre, so be careful what you feed the hardware
+ *
+ *	No cleanup is done by this interface. It is done on the interrupt side when the
+ *	reply arrives
+ *
+ *	To Fix: Generate PCI maps of the buffers
  */
-
+ 
 static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, int unit)
 {
 	struct i2o_controller *c = dev->controller;
@@ -256,7 +288,7 @@
 	struct request *req = ireq->req;
 	struct bio *bio = req->bio;
 	int count = req->nr_sectors<<9;
-	unsigned long last = ~0UL;
+	unsigned long last = 0;
 	unsigned short size = 0;
 
 	// printk(KERN_INFO "i2ob_send called\n");
@@ -266,9 +298,9 @@
 	/*
 	 * Build the message based on the request.
 	 */
-	__raw_writel(i2ob_context|(unit<<8), msg+8);
-	__raw_writel(ireq->num, msg+12);
-	__raw_writel(req->nr_sectors << 9, msg+20);
+	i2o_raw_writel(i2ob_context|(unit<<8), msg+8);
+	i2o_raw_writel(ireq->num, msg+12);
+	i2o_raw_writel(req->nr_sectors << 9, msg+20);
 
 	/* 
 	 * Mask out partitions from now on
@@ -278,69 +310,77 @@
 	/* This can be optimised later - just want to be sure its right for
 	   starters */
 	offset = ((u64)req->sector) << 9;
-	__raw_writel( offset & 0xFFFFFFFF, msg+24);
-	__raw_writel(offset>>32, msg+28);
+	i2o_raw_writel( offset & 0xFFFFFFFF, msg+24);
+	i2o_raw_writel(offset>>32, msg+28);
 	mptr=msg+32;
 	
 	if(req->cmd == READ)
 	{
-		__raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4);
-		while(bio)
+		DEBUG("READ\n");
+		i2o_raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4);
+		while(bio!=NULL)
 		{
-			if (bio_to_phys(bio) == last) {
+			if(bio_to_phys(bio) == last) {
 				size += bio->bi_size;
 				last += bio->bi_size;
 				if(bio->bi_next)
-					__raw_writel(0x14000000|(size), mptr-8);
+					i2o_raw_writel(0x10000000|(size), mptr-8);
 				else
-					__raw_writel(0xD4000000|(size), mptr-8);
+					__raw_writel(0xD0000000|(size), mptr-8);
 			}
 			else
 			{
 				if(bio->bi_next)
-					__raw_writel(0x10000000|bio->bi_size, mptr);
+					i2o_raw_writel(0x10000000|bio->bi_size, mptr);
 				else
-					__raw_writel(0xD0000000|bio->bi_size, mptr);
-				__raw_writel(bio_to_phys(bio), mptr+4);
+					i2o_raw_writel(0xD0000000|bio->bi_size, mptr);
+				i2o_raw_writel(bio_to_phys(bio), mptr+4);
 				mptr += 8;	
 				size = bio->bi_size;
-				last = bio_to_phys(bio) + bio->bi_size;
+				last = bio_to_phys(bio) + size;
 			}
 
 			count -= bio->bi_size;
 			bio = bio->bi_next;
 		}
-		/*
-		 *	Heuristic for now since the block layer doesnt give
-		 *	us enough info. If its a big write assume sequential
-		 *	readahead on controller. If its small then don't read
-		 *	ahead but do use the controller cache.
-		 */
-		if(size >= 8192)
-			__raw_writel((8<<24)|(1<<16)|8, msg+16);
-		else
-			__raw_writel((8<<24)|(1<<16)|4, msg+16);
+		switch(dev->rcache)
+		{
+			case CACHE_NULL:
+				i2o_raw_writel(0, msg+16);break;
+			case CACHE_PREFETCH:
+				i2o_raw_writel(0x201F0008, msg+16);break;
+			case CACHE_SMARTFETCH:
+				if(req->nr_sectors > 16)
+					i2o_raw_writel(0x201F0008, msg+16);
+				else
+					i2o_raw_writel(0x001F0000, msg+16);
+				break;
+		}				
+				
+//		printk("Reading %d entries %d bytes.\n",
+//			mptr-msg-8, req->nr_sectors<<9);
 	}
 	else if(req->cmd == WRITE)
 	{
-		__raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4);
-		while(bio)
+		DEBUG("WRITE\n");
+		i2o_raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4);
+		while(bio!=NULL)
 		{
-			if (bio_to_phys(bio) == last) {
+			if(bio_to_phys(bio) == last) {
 				size += bio->bi_size;
 				last += bio->bi_size;
 				if(bio->bi_next)
-					__raw_writel(0x14000000|(size), mptr-8);
+					i2o_raw_writel(0x14000000|(size), mptr-8);
 				else
-					__raw_writel(0xD4000000|(size), mptr-8);
+					i2o_raw_writel(0xD4000000|(size), mptr-8);
 			}
 			else
 			{
 				if(bio->bi_next)
-					__raw_writel(0x14000000|bio->bi_size, mptr);
+					i2o_raw_writel(0x14000000|(bio->bi_size), mptr);
 				else
-					__raw_writel(0xD4000000|bio->bi_size, mptr);
-				__raw_writel(bio_to_phys(bio), mptr+4);
+					i2o_raw_writel(0xD4000000|(bio->bi_size), mptr);
+				i2o_raw_writel(bio_to_phys(bio), mptr+4);
 				mptr += 8;	
 				size = bio->bi_size;
 				last = bio_to_phys(bio) + bio->bi_size;
@@ -350,30 +390,31 @@
 			bio = bio->bi_next;
 		}
 
-		if(c->battery)
-		{
-			
-			if(size>16384)
-				__raw_writel(4, msg+16);
-			else
-				/* 
-				 * Allow replies to come back once data is cached in the controller
-				 * This allows us to handle writes quickly thus giving more of the
-				 * queue to reads.
-				 */
-				__raw_writel(16, msg+16);
-		}
-		else
+		switch(dev->wcache)
 		{
-			/* Large write, don't cache */
-			if(size>8192)
-				__raw_writel(4, msg+16);
-			else
-			/* write through */
-				__raw_writel(8, msg+16);
+			case CACHE_NULL:
+				i2o_raw_writel(0, msg+16);break;
+			case CACHE_WRITETHROUGH:
+				i2o_raw_writel(0x001F0008, msg+16);break;
+			case CACHE_WRITEBACK:
+				i2o_raw_writel(0x001F0010, msg+16);break;
+			case CACHE_SMARTBACK:
+				if(req->nr_sectors > 16)
+					i2o_raw_writel(0x001F0004, msg+16);
+				else
+					i2o_raw_writel(0x001F0010, msg+16);
+				break;
+			case CACHE_SMARTTHROUGH:
+				if(req->nr_sectors > 16)
+					i2o_raw_writel(0x001F0004, msg+16);
+				else
+					i2o_raw_writel(0x001F0010, msg+16);
 		}
+				
+//		printk("Writing %d entries %d bytes.\n",
+//			mptr-msg-8, req->nr_sectors<<9);
 	}
-	__raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
+	i2o_raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
 	
 	if(count != 0)
 	{
@@ -405,47 +446,23 @@
  
 static inline void i2ob_end_request(struct request *req)
 {
+	/* FIXME  - pci unmap the request */
+
 	/*
 	 * Loop until all of the buffers that are linked
 	 * to this request have been marked updated and
 	 * unlocked.
 	 */
 
-	while (end_that_request_first(req, !req->errors, req->hard_cur_sectors))
-		;
+	while (end_that_request_first( req, !req->errors, req->hard_cur_sectors ));
 
 	/*
 	 * It is now ok to complete the request.
 	 */
 	end_that_request_last( req );
+	DEBUG("IO COMPLETED\n");
 }
 
-static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit)
-{
-	unsigned long msg;
-	u32 m = i2ob_get(d);
-	
-	if(m == 0xFFFFFFFF)
-		return -1;
-		
-	msg = c->mem_offset + m;
-
-	/*
-	 *	Ask the controller to write the cache back. This sorts out
-	 *	the supertrak firmware flaw and also does roughly the right
-	 *	thing for other cases too.
-	 */
-	 	
-	__raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
-	__raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4);
-	__raw_writel(i2ob_context|(unit<<8), msg+8);
-	__raw_writel(0, msg+12);
-	__raw_writel(60<<16, msg+16);
-	
-	i2o_post_message(c,m);
-	return 0;
-}
-			
 /*
  *	OSM reply handler. This gets all the message replies
  */
@@ -464,12 +481,13 @@
 	 */
 	if(m[0] & (1<<13))
 	{
+		DEBUG("FAIL");
 		/*
 		 * FAILed message from controller
 		 * We increment the error count and abort it
 		 *
 		 * In theory this will never happen.  The I2O block class
-		 * speficiation states that block devices never return
+		 * specification states that block devices never return
 		 * FAILs but instead use the REQ status field...but
 		 * better be on the safe side since no one really follows
 		 * the spec to the book :)
@@ -499,17 +517,6 @@
 		return;
 	}
 
-	if(msg->function == I2O_CMD_BLOCK_CFLUSH)
-	{
-		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
-		dev->constipated=0;
-		DEBUG(("unconstipated\n"));
-		if(i2ob_backlog_request(c, dev)==0)
-			i2ob_request(dev->req_queue);
-		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
-		return;
-	}
-
 	if(!dev->i2odev)
 	{
 		/*
@@ -567,64 +574,12 @@
 		 *	The second is that you have a SuperTrak 100 and the
 		 *	firmware got constipated. Unlike standard i2o card
 		 *	setups the supertrak returns an error rather than
-		 *	blocking for the timeout in these cases.
+		 *	blocking for the timeout in these cases. 
+		 *
+		 *	Don't stick a supertrak100 into cache aggressive modes
 		 */
 		 
 		
-		spin_lock_irqsave(I2O_LOCK(c->unit), flags);
-		if(err==4)
-		{
-			/*
-			 *	Time to uncork stuff
-			 */
-			
-			if(!dev->constipated)
-			{
-				dev->constipated = 1;
-				DEBUG(("constipated\n"));
-				/* Now pull the chain */
-				if(i2ob_flush(c, dev, unit)<0)
-				{
-					DEBUG(("i2ob: Unable to queue flush. Retrying I/O immediately.\n"));
-					dev->constipated=0;
-				}
-				DEBUG(("flushing\n"));
-			}
-			
-			/*
-			 *	Recycle the request
-			 */
-			 
-//			i2ob_unhook_request(ireq, c->unit);
-			
-			/*
-			 *	Place it on the recycle queue
-			 */
-			 
-			ireq->next = NULL;
-			if(i2ob_backlog_tail[c->unit]!=NULL)
-				i2ob_backlog_tail[c->unit]->next = ireq;
-			else
-				i2ob_backlog[c->unit] = ireq;			
-			i2ob_backlog_tail[c->unit] = ireq;
-			
-			atomic_dec(&i2ob_queues[c->unit]->queue_depth);
-
-			/*
-			 *	If the constipator flush failed we want to
-			 *	poke the queue again. 
-			 */
-			 
-			i2ob_request(dev->req_queue);
-			spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
-			
-			/*
-			 *	and out
-			 */
-			 
-			return;	
-		}
-		spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 		printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, 
 			bsa_errors[m[4]&0XFFFF]);
 		if(m[4]&0x00FF0000)
@@ -639,19 +594,17 @@
 	 *	Dequeue the request. We use irqsave locks as one day we
 	 *	may be running polled controllers from a BH...
 	 */
-
+	
 	spin_lock_irqsave(I2O_LOCK(c->unit), flags);
 	i2ob_unhook_request(ireq, c->unit);
 	i2ob_end_request(ireq->req);
 	atomic_dec(&i2ob_queues[c->unit]->queue_depth);
-
+	
 	/*
 	 *	We may be able to do more I/O
 	 */
-
-	if(i2ob_backlog_request(c, dev)==0)
-		i2ob_request(dev->req_queue);
-
+	 
+	i2ob_request(dev->req_queue);
 	spin_unlock_irqrestore(I2O_LOCK(c->unit), flags);
 }
 
@@ -672,6 +625,7 @@
 		u32 evt_indicator;
 		u8 ASC;
 		u8 ASCQ;
+		u16 pad;
 		u8 data[16];
 		} *evt_local;
 
@@ -702,8 +656,8 @@
 		evt_local = (struct i2o_reply *)evt_msg;
 		spin_unlock_irqrestore(&i2ob_evt_lock, flags);
 
-		unit = evt_local->header[3];
-		evt = evt_local->evt_indicator;
+		unit = le32_to_cpu(evt_local->header[3]);
+		evt = le32_to_cpu(evt_local->evt_indicator);
 
 		switch(evt)
 		{
@@ -715,7 +669,7 @@
 			 */
 			case I2O_EVT_IND_BSA_VOLUME_LOAD:
 			{
-				struct gendisk *p = i2o_disk[unit>>4];
+				struct gendisk *p = i2ob_disk[unit>>4];
 				i2ob_install_device(i2ob_dev[unit].i2odev->controller, 
 					i2ob_dev[unit].i2odev, unit);
 				add_disk(p);
@@ -730,7 +684,7 @@
 			 */
 			case I2O_EVT_IND_BSA_VOLUME_UNLOAD:
 			{
-				struct gendisk *p = i2o_disk[unit>>4];
+				struct gendisk *p = i2ob_disk[unit>>4];
 				del_gendisk(p);
 				for(i = unit; i <= unit+15; i++)
 					blk_queue_max_sectors(i2ob_dev[i].req_queue, 0);
@@ -762,7 +716,8 @@
 					i2ob_query_device(&i2ob_dev[unit], 0x0000, 4, &size, 8);
 
 				spin_lock_irqsave(I2O_LOCK(unit), flags);	
-				set_capacity(i2o_disk[unit>>4], size>>9);
+				i2ob_sizes[unit] = (int)(size>>10);
+				set_capacity(i2ob_disk[unit>>4], size>>9);
 				spin_unlock_irqrestore(I2O_LOCK(unit), flags);	
 				break;
 			}
@@ -795,8 +750,17 @@
 			 * An event we didn't ask for.  Call the card manufacturer
 			 * and tell them to fix their firmware :)
 			 */
+			 
+			case 0x20:
+				/*
+				 * If a promise card reports 0x20 event then the brown stuff
+				 * hit the fan big time. The card seems to recover but loses
+				 * the pending writes. Deeply ungood except for testing fsck
+				 */
+				if(i2ob_dev[unit].i2odev->controller->bus.pci.promise)
+					panic("I2O controller firmware failed. Reboot and force a filesystem check.\n");
 			default:
-				printk(KERN_INFO "%s: Received event %d we didn't register for\n"
+				printk(KERN_INFO "%s: Received event 0x%X we didn't register for\n"
 					KERN_INFO "   Blame the I2O card manufacturer 8)\n", 
 					i2ob_dev[unit].i2odev->dev_name, evt);
 				break;
@@ -808,69 +772,6 @@
 }
 
 /*
- * The timer handler will attempt to restart requests 
- * that are queued to the driver.  This handler
- * currently only gets called if the controller
- * had no more room in its inbound fifo.  
- */
-
-static void i2ob_timer_handler(unsigned long q)
-{
-	request_queue_t *req_queue = (request_queue_t *) q;
-	unsigned long flags;
-
-	/*
-	 * We cannot touch the request queue or the timer
-         * flag without holding the queue_lock
-	 */
-	spin_lock_irqsave(req_queue->queue_lock,flags);
-
-	/* 
-	 * Clear the timer started flag so that 
-	 * the timer can be queued again.
-	 */
-	i2ob_timer_started = 0;
-
-	/* 
-	 * Restart any requests.
-	 */
-	i2ob_request(req_queue);
-
-	/* 
-	 * Free the lock.
-	 */
-	spin_unlock_irqrestore(req_queue->queue_lock,flags);
-}
-
-static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev)
-{
-	u32 m;
-	struct i2ob_request *ireq;
-	
-	while((ireq=i2ob_backlog[c->unit])!=NULL)
-	{
-		int unit;
-
-		if(atomic_read(&i2ob_queues[c->unit]->queue_depth) > dev->depth/4)
-			break;
-
-		m = i2ob_get(dev);
-		if(m == 0xFFFFFFFF)
-			break;
-
-		i2ob_backlog[c->unit] = ireq->next;
-		if(i2ob_backlog[c->unit] == NULL)
-			i2ob_backlog_tail[c->unit] = NULL;
-			
-		unit = minor(ireq->req->rq_dev);
-		i2ob_send(m, dev, ireq, unit);
-	}
-	if(i2ob_backlog[c->unit])
-		return 1;
-	return 0;
-}
-
-/*
  *	The I2O block driver is listed as one of those that pulls the
  *	front entry off the queue before processing it. This is important
  *	to remember here. If we drop the io lock then CURRENT will change
@@ -886,8 +787,7 @@
 	struct i2ob_device *dev;
 	u32 m;
 	
-	
-	while (!blk_queue_empty(q)) {
+	while (blk_queue_empty(q)) {
 		/*
 		 *	On an IRQ completion if there is an inactive
 		 *	request on the queue head it means it isnt yet
@@ -909,49 +809,15 @@
 		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth)
 			break;
 		
-		/*
-		 *	Is the channel constipated ?
-		 */
-
-		if(i2ob_backlog[dev->unit]!=NULL)
-			break;
-			
 		/* Get a message */
 		m = i2ob_get(dev);
 
 		if(m==0xFFFFFFFF)
 		{
-			/* 
-			 * See if the timer has already been queued.
-			 */
-			if (!i2ob_timer_started)
-			{
-				DEBUG((KERN_ERR "i2ob: starting timer\n"));
-
-				/*
-				 * Set the timer_started flag to insure
-				 * that the timer is only queued once.
-				 * Queing it more than once will corrupt
-				 * the timer queue.
-				 */
-				i2ob_timer_started = 1;
-
-				/* 
-				 * Set up the timer to expire in
-				 * 500ms.
-				 */
-				i2ob_timer.expires = jiffies + (HZ >> 1);
-				i2ob_timer.data = (unsigned int)q;
-
-				/*
-				 * Start it.
-				 */
-				 
-				add_timer(&i2ob_timer);
-				return;
-			}
+			if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) == 0)
+				printk(KERN_ERR "i2o_block: message queue and request queue empty!!\n");
+			break;
 		}
-
 		/*
 		 * Everything ok, so pull from kernel queue onto our queue
 		 */
@@ -1017,7 +883,7 @@
 	else
 		heads = 255;
 
-	cylinders = capacity / (heads * sectors);
+	cylinders = (unsigned long)capacity / (heads * sectors);
 
 	*cyls = (unsigned short) cylinders;	/* Stuff return values */ 
 	*secs = (unsigned char) sectors; 
@@ -1031,19 +897,47 @@
 static int i2ob_ioctl(struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	struct hd_geometry g;
-	int u = minor(inode->i_rdev) >> 4;
+	struct i2ob_device *dev;
+	int minor;
+
 	/* Anyone capable of this syscall can do *real bad* things */
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-
-	if (cmd != HDIO_GETGEO)
+	if (!inode)
 		return -EINVAL;
-	i2o_block_biosparam(get_capacity(i2o_disk[u]),
-				&g.cylinders, &g.heads, &g.sectors);
-	g.start = get_start_sect(inode->i_bdev);
-	return copy_to_user((void *)arg, &g, sizeof(g)) ? -EFAULT : 0;
+	minor = minor(inode->i_rdev);
+	if (minor >= (MAX_I2OB<<4))
+		return -ENODEV;
+
+	dev = &i2ob_dev[minor];
+	switch (cmd) {
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g;
+			int u=minor >> 4;
+			i2o_block_biosparam(get_capacity(i2ob_disk[u]), 
+						&g.cylinders, &g.heads, &g.sectors);
+			g.start = get_start_sect(inode->i_bdev);
+			return copy_to_user((void *)arg,&g, sizeof(g))?-EFAULT:0;
+		}
+		
+		case BLKI2OGRSTRAT:
+			return put_user(dev->rcache, (int *)arg);
+		case BLKI2OGWSTRAT:
+			return put_user(dev->wcache, (int *)arg);
+		case BLKI2OSRSTRAT:
+			if(arg<0||arg>CACHE_SMARTFETCH)
+				return -EINVAL;
+			dev->rcache = arg;
+			break;
+		case BLKI2OSWSTRAT:
+			if(arg!=0 && (arg<CACHE_WRITETHROUGH || arg>CACHE_SMARTBACK))
+				return -EINVAL;
+			dev->wcache = arg;
+			break;
+	}
+	return -ENOTTY;
 }
 
 /*
@@ -1081,7 +975,7 @@
 		 */
 		u32 msg[5];
 		int *query_done = &dev->done_flag;
-		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[0] = (FIVE_WORD_MSG_SIZE|SGL_OFFSET_0);
 		msg[1] = I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|dev->tid;
 		msg[2] = i2ob_context|0x40000000;
 		msg[3] = (u32)query_done;
@@ -1100,7 +994,17 @@
 		DEBUG("Unlocking...");
 		i2o_post_wait(dev->controller, msg, 20, 2);
 		DEBUG("Unlocked.\n");
-	
+
+		msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+		msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid;
+		if(dev->flags & (1<<3|1<<4))	/* Removable */
+			msg[4] = 0x21 << 24;
+		else
+			msg[4] = 0x24 << 24;
+
+		if(i2o_post_wait(dev->controller, msg, 20, 60)==0)
+			dev->power = 0x24;
+
 		/*
  		 * Now unclaim the device.
 		 */
@@ -1144,7 +1048,19 @@
 			return -EBUSY;
 		}
 		DEBUG("Claimed ");
-		
+		/*
+	 	 *	Power up if needed
+	 	 */
+
+		if(dev->power > 0x1f)
+		{
+			msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+			msg[1] = I2O_CMD_BLOCK_POWER<<24 | HOST_TID << 12 | dev->tid;
+			msg[4] = 0x02 << 24;
+			if(i2o_post_wait(dev->controller, msg, 20, 60) == 0)
+				dev->power = 0x02;
+		}
+
 		/*
 		 *	Mount the media if needed. Note that we don't use
 		 *	the lock bit. Since we have to issue a lock if it
@@ -1191,8 +1107,8 @@
 {
 	u64 size;
 	u32 blocksize;
-	u32 limit;
 	u8 type;
+	u16 power;
 	u32 flags, status;
 	struct i2ob_device *dev=&i2ob_dev[unit];
 	int i;
@@ -1214,35 +1130,40 @@
 		i2ob_query_device(dev, 0x0000, 4, &size, 8);
 	}
 	
+	if(i2ob_query_device(dev, 0x0000, 2, &power, 2)!=0)
+		power = 0;
 	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
 	i2ob_query_device(dev, 0x0000, 6, &status, 4);
-	set_capacity(i2o_disk[unit>>4], size>>9);
-
-	/* Set limit based on inbound frame size */
-	limit = (d->controller->status_block->inbound_frame_size - 8)/2;
-	limit = limit<<9;
+	i2ob_sizes[unit] = (int)(size>>10);
+	set_capacity(i2ob_disk[unit>>4], size>>9);
 
 	/*
 	 * Max number of Scatter-Gather Elements
 	 */	
+
+	i2ob_dev[unit].power = power;	/* Save power state in device proper */
+	i2ob_dev[unit].flags = flags;
+
 	for(i=unit;i<=unit+15;i++)
 	{
 		request_queue_t *q = i2ob_dev[unit].req_queue;
+		
+		i2ob_dev[i].power = power;	/* Save power state */
+		i2ob_dev[unit].flags = flags;	/* Keep the type info */
+		
+		blk_queue_max_sectors(q, 96);	/* 256 might be nicer but many controllers 
+						   explode on 65536 or higher */
+		blk_queue_max_phys_segments(q, (d->controller->status_block->inbound_frame_size - 7) / 2);
+		blk_queue_max_hw_segments(q, (d->controller->status_block->inbound_frame_size - 7) / 2);
+		
+		i2ob_dev[i].rcache = CACHE_SMARTFETCH;
+		i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
+		
+		if(d->controller->battery == 0)
+			i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
 
-		blk_queue_max_sectors(q, 256);
-		blk_queue_max_phys_segments(q, (d->controller->status_block->inbound_frame_size - 8)/2);
-		blk_queue_max_hw_segments(q, (d->controller->status_block->inbound_frame_size - 8)/2);
-
-		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy == 2)
-			i2ob_dev[i].depth = 32;
-
-		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy == 1)
-		{
-			blk_queue_max_sectors(q, 32);
-			blk_queue_max_phys_segments(q, 8);
-			blk_queue_max_hw_segments(q, 8);
-			i2ob_dev[i].depth = 4;
-		}
+		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.promise)
+			i2ob_dev[i].wcache = CACHE_WRITETHROUGH;
 
 		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.short_req)
 		{
@@ -1252,11 +1173,10 @@
 		}
 	}
 
-
-	strcpy(d->dev_name, i2o_disk[unit>>4]->disk_name);
+	strcpy(d->dev_name, i2ob_disk[unit>>4]->disk_name);
 
 	printk(KERN_INFO "%s: Max segments %d, queue depth %d, byte limit %d.\n",
-		 d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, limit);
+		 d->dev_name, i2ob_dev[unit].max_segments, i2ob_dev[unit].depth, i2ob_max_sectors[unit]<<9);
 
 	i2ob_query_device(dev, 0x0000, 0, &type, 1);
 
@@ -1272,14 +1192,19 @@
 	}
 	if(status&(1<<10))
 		printk("(RAID)");
-	if(((flags & (1<<3)) && !(status & (1<<3))) ||
-	   ((flags & (1<<4)) && !(status & (1<<4))))
+
+	if((flags^status)&(1<<4|1<<3))	/* Missing media or device */
 	{
 		printk(KERN_INFO " Not loaded.\n");
-		return 1;
+		/* Device missing ? */
+		if((flags^status)&(1<<4))
+			return 1;
+	}
+	else
+	{
+		printk(": %dMB, %d byte sectors",
+			(int)(size>>20), blocksize);
 	}
-	printk(": %dMB, %d byte sectors",
-		(int)(size>>20), blocksize);
 	if(status&(1<<0))
 	{
 		u32 cachesize;
@@ -1289,11 +1214,10 @@
 			printk(", %dMb cache", cachesize>>10);
 		else
 			printk(", %dKb cache", cachesize);
-		
 	}
 	printk(".\n");
 	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
-		d->dev_name, i2ob_dev[unit].req_queue->max_sectors);
+		d->dev_name, i2ob_max_sectors[unit]);
 
 	/* 
 	 * If this is the first I2O block device found on this IOP,
@@ -1313,14 +1237,17 @@
 	 */
 	dev->req_queue = &i2ob_queues[c->unit]->req_queue;
 
+	/* Register a size before we register for events - otherwise we
+	   might miss and overwrite an event */
+	set_capacity(i2ob_disk[unit>>4], size>>9);
+
 	/*
 	 * Register for the events we're interested in and that the
 	 * device actually supports.
 	 */
+
 	i2o_event_register(c, d->lct_data.tid, i2ob_context, unit, 
 		(I2OB_EVENT_MASK & d->lct_data.event_capabilities));
-
-	set_capacity(i2o_disk[unit>>4], size>>9);
 	return 0;
 }
 
@@ -1332,22 +1259,18 @@
 {
 	int i;
 
-	i2ob_queues[unit] = (struct i2ob_iop_queue*)
-		kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC);
+	i2ob_queues[unit] = (struct i2ob_iop_queue *) kmalloc(sizeof(struct i2ob_iop_queue), GFP_ATOMIC);
 	if(!i2ob_queues[unit])
 	{
-		printk(KERN_WARNING
-			"Could not allocate request queue for I2O block device!\n");
+		printk(KERN_WARNING "Could not allocate request queue for I2O block device!\n");
 		return -1;
 	}
 
 	for(i = 0; i< MAX_I2OB_DEPTH; i++)
 	{
-		i2ob_queues[unit]->request_queue[i].next = 
-			&i2ob_queues[unit]->request_queue[i+1];
+		i2ob_queues[unit]->request_queue[i].next =  &i2ob_queues[unit]->request_queue[i+1];
 		i2ob_queues[unit]->request_queue[i].num = i;
 	}
-	i2ob_queues[unit]->lock = SPIN_LOCK_UNLOCKED;
 	
 	/* Queue is MAX_I2OB + 1... */
 	i2ob_queues[unit]->request_queue[i].next = NULL;
@@ -1368,8 +1291,6 @@
 	return I2O_UNIT(dev).req_queue;
 }
 
-
-
 /*
  * Probe the I2O subsytem for block class devices
  */
@@ -1389,34 +1310,34 @@
 		if(c==NULL)
 			continue;
 
-	/*
-	 *    The device list connected to the I2O Controller is doubly linked
-	 * Here we traverse the end of the list , and start claiming devices
-	 * from that end. This assures that within an I2O controller atleast
-	 * the newly created volumes get claimed after the older ones, thus
-	 * mapping to same major/minor (and hence device file name) after 
-	 * every reboot.
-	 * The exception being: 
-	 * 1. If there was a TID reuse.
-	 * 2. There was more than one I2O controller. 
-	 */
-
-	if(!bios)
-	{
-		for (d=c->devices;d!=NULL;d=d->next)
-		if(d->next == NULL)
-			b = d;
-	}
-	else
-		b = c->devices;
+		/*
+		 *    The device list connected to the I2O Controller is doubly linked
+		 * Here we traverse the end of the list , and start claiming devices
+		 * from that end. This assures that within an I2O controller atleast
+		 * the newly created volumes get claimed after the older ones, thus
+		 * mapping to same major/minor (and hence device file name) after 
+		 * every reboot.
+		 * The exception being: 
+		 * 1. If there was a TID reuse.
+		 * 2. There was more than one I2O controller. 
+		 */
 
-	while(b != NULL)
-	{
-		d=b;
-		if(bios)
-			b = b->next;
+		if(!bios)
+		{
+			for (d=c->devices;d!=NULL;d=d->next)
+			if(d->next == NULL)
+				b = d;
+		}
 		else
-			b = b->prev;
+			b = c->devices;
+
+		while(b != NULL)
+		{
+			d=b;
+			if(bios)
+				b = b->next;
+			else
+				b = b->prev;
 
 			if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE)
 				continue;
@@ -1534,8 +1455,7 @@
 
 	if(i2o_claim_device(d, &i2o_block_handler))
 	{
-		printk(KERN_INFO 
-			"i2o_block: Unable to claim device. Installation aborted\n");
+		printk(KERN_INFO "i2o_block: Unable to claim device. Installation aborted\n");
 		return;
 	}
 
@@ -1599,7 +1519,7 @@
 	 * This will force errors when i2ob_get_queue() is called
 	 * by the kenrel.
 	 */
-	del_gendisk(i2o_disk[unit>>4]);
+	del_gendisk(i2ob_disk[unit>>4]);
 	i2ob_dev[unit].req_queue = NULL;
 	for(i = unit; i <= unit+15; i++)
 	{
@@ -1709,7 +1629,7 @@
  *  (Just smiley confuses emacs :-)
  */
 
-static int __init i2o_block_init(void)
+static int i2o_block_init(void)
 {
 	int i;
 
@@ -1725,10 +1645,11 @@
 		       MAJOR_NR);
 		return -EIO;
 	}
+
 	for (i = 0; i < MAX_I2OB; i++) {
 		struct gendisk *disk = alloc_disk();
 		if (!disk)
-			goto Enomem;
+			goto oom;
 		i2o_disk[i] = disk;
 	}
 #ifdef MODULE
@@ -1740,7 +1661,7 @@
 	 */
 	 
 	blk_dev[MAJOR_NR].queue = i2ob_get_queue;
-	
+
 	for (i = 0; i < MAX_I2OB << 4; i++) {
 		i2ob_dev[i].refcnt = 0;
 		i2ob_dev[i].flags = 0;
@@ -1750,10 +1671,12 @@
 		i2ob_dev[i].head = NULL;
 		i2ob_dev[i].tail = NULL;
 		i2ob_dev[i].depth = MAX_I2OB_DEPTH;
+		i2ob_blksizes[i] = 1024;
+		i2ob_max_sectors[i] = 2;
 	}
-
+	
 	for (i = 0; i < MAX_I2OB; i++) {
-		struct gendisk *disk = i2o_disk[i];
+		struct gendisk *disk = i2ob_disk + i;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i<<4;
 		disk->minor_shift = 4;
@@ -1770,14 +1693,6 @@
 	}
 
 	/*
-	 *	Timers
-	 */
-	 
-	init_timer(&i2ob_timer);
-	i2ob_timer.function = i2ob_timer_handler;
-	i2ob_timer.data = 0;
-	
-	/*
 	 *	Register the OSM handler as we will need this to probe for
 	 *	drives, geometry and other goodies.
 	 */
@@ -1785,6 +1700,7 @@
 	if(i2o_install_handler(&i2o_block_handler)<0)
 	{
 		unregister_blkdev(MAJOR_NR, "i2o_block");
+		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 		printk(KERN_ERR "i2o_block: unable to register OSM.\n");
 		return -EINVAL;
 	}
@@ -1803,21 +1719,19 @@
 		return 0;
 	}
 
-	/*
-	 *	Finally see what is actually plugged in to our controllers
-	 */
-
 	i2ob_probe();
 
 	return 0;
-Enomem:
+
+oom:
 	while (i--)
 		put_disk(i2o_disk[i]);
 	unregister_blkdev(MAJOR_NR, "i2o_block");
 	return -ENOMEM;
 }
 
-static void __exit i2o_block_exit(void)
+
+static void i2o_block_exit(void)
 {
 	int i;
 	
@@ -1863,10 +1777,10 @@
 	 */
 
 	i2o_remove_handler(&i2o_block_handler);
-
+		 
 	for (i = 0; i < MAX_I2OB; i++)
 		put_disk(i2o_disk[i]);
- 
+
 	/*
 	 *	Return the block device
 	 */
@@ -1874,9 +1788,9 @@
 		printk("i2o_block: cleanup_module failed\n");
 }
 
-MODULE_AUTHOR("Red Hat Software");
+MODULE_AUTHOR("Red Hat");
 MODULE_DESCRIPTION("I2O Block Device OSM");
 MODULE_LICENSE("GPL");
 
-module_init(i2o_block_init)
-module_exit(i2o_block_exit)
+module_init(i2o_block_init);
+module_exit(i2o_block_exit);
diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c
--- a/drivers/message/i2o/i2o_core.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/message/i2o/i2o_core.c	Fri Oct 11 21:23:00 2002
@@ -42,11 +42,11 @@
 #include <linux/wait.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
-#include <linux/tqueue.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <asm/semaphore.h>
 #include <linux/completion.h>
+#include <linux/workqueue.h>
 
 #include <asm/io.h>
 #include <linux/reboot.h>
diff -Nru a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
--- a/drivers/message/i2o/i2o_proc.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/message/i2o/i2o_proc.c	Fri Oct 11 21:23:00 2002
@@ -45,9 +45,9 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/tqueue.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
+#include <linux/workqueue.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
diff -Nru a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
--- a/drivers/message/i2o/i2o_scsi.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/message/i2o/i2o_scsi.c	Fri Oct 11 21:22:54 2002
@@ -1,13 +1,18 @@
 /* 
- *  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
- *  later version.
+ * 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
+ * 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.
+ * 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.
+ *
+ * For the purpose of avoiding doubt the preferred form of the work
+ * for making modifications shall be a standards compliant form such
+ * gzipped tar and not one requiring a proprietary or patent encumbered
+ * tool to unpack.
  *
  *  Complications for I2O scsi
  *
@@ -56,7 +61,7 @@
 #include "../../scsi/sd.h"
 #include "i2o_scsi.h"
 
-#define VERSION_STRING        "Version 0.0.1"
+#define VERSION_STRING        "Version 0.1.0"
 
 #define dprintk(x)
 
@@ -77,6 +82,7 @@
 static u32 *retry[32];
 static struct i2o_controller *retry_ctrl[32];
 static struct timer_list retry_timer;
+static spinlock_t retry_lock;
 static int retry_ct = 0;
 
 static atomic_t queue_depth;
@@ -121,14 +127,11 @@
 	int i;
 	unsigned long flags;
 	
-	save_flags(flags);
-	cli();
-
+	spin_lock_irqsave(&retry_lock, flags);
 	for(i=0;i<retry_ct;i++)
 		i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i]));
 	retry_ct=0;
-	
-	restore_flags(flags);
+	spin_unlock_irqrestore(&retry_lock, flags);
 }
 
 static void flush_pending(void)
@@ -136,9 +139,7 @@
 	int i;
 	unsigned long flags;
 	
-	save_flags(flags);
-	cli();
-
+	spin_lock_irqsave(&retry_lock, flags);
 	for(i=0;i<retry_ct;i++)
 	{
 		retry[i][0]&=~0xFFFFFF;
@@ -146,8 +147,7 @@
 		i2o_post_message(retry_ctrl[i],virt_to_bus(retry[i]));
 	}
 	retry_ct=0;
-	
-	restore_flags(flags);
+	spin_unlock_irqrestore(&retry_lock, flags);
 }
 
 static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
@@ -156,6 +156,7 @@
 	spinlock_t *lock;
 	u32 *m = (u32 *)msg;
 	u8 as,ds,st;
+	unsigned long flags;
 
 	if(m[0] & (1<<13))
 	{
@@ -177,6 +178,9 @@
 		m=(u32 *)bus_to_virt(m[7]);
 		printk("Failing message is %p.\n", m);
 		
+		/* This isnt a fast path .. */
+		spin_lock_irqsave(&retry_lock, flags);
+		
 		if((m[4]&(1<<18)) && retry_ct < 32)
 		{
 			retry_ctrl[retry_ct]=c;
@@ -186,18 +190,20 @@
 				retry_timer.expires=jiffies+1;
 				add_timer(&retry_timer);
 			}
+			spin_unlock_irqrestore(&retry_lock, flags);
 		}
 		else
 		{
+			spin_unlock_irqrestore(&retry_lock, flags);
 			/* Create a scsi error for this */
 			current_command = (Scsi_Cmnd *)m[3];
-			lock = &current_command->host->host_lock;
+			lock = current_command->host->host_lock;
 			printk("Aborted %ld\n", current_command->serial_number);
 
-			spin_lock_irq(lock);
+			spin_lock_irqsave(lock, flags);
 			current_command->result = DID_ERROR << 16;
 			current_command->scsi_done(current_command);
-			spin_unlock_irq(lock);
+			spin_unlock_irqrestore(lock, flags);
 			
 			/* Now flush the message by making it a NOP */
 			m[0]&=0x00FFFFFF;
@@ -214,9 +220,9 @@
 	 *	Low byte is device status, next is adapter status,
 	 *	(then one byte reserved), then request status.
 	 */
-	ds=(u8)m[4]; 
-	as=(u8)(m[4]>>8);
-	st=(u8)(m[4]>>24);
+	ds=(u8)le32_to_cpu(m[4]);
+	as=(u8)le32_to_cpu(m[4]>>8);
+	st=(u8)le32_to_cpu(m[4]>>24);
 	
 	dprintk(("i2o got a scsi reply %08X: ", m[0]));
 	dprintk(("m[2]=%08X: ", m[2]));
@@ -233,7 +239,10 @@
 		printk(KERN_ERR "i2o_scsi: bus reset reply.\n");
 		return;
 	}
-	
+	/*
+ 	 *	FIXME: 64bit breakage
+	 */
+
 	current_command = (Scsi_Cmnd *)m[3];
 	
 	/*
@@ -254,11 +263,11 @@
 	
 	if(st == 0x06)
 	{
-		if(m[5] < current_command->underflow)
+		if(le32_to_cpu(m[5]) < current_command->underflow)
 		{
 			int i;
 			printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n",
-				m[5], current_command->underflow);
+				le32_to_cpu(m[5]), current_command->underflow);
 			printk("Cmd: ");
 			for(i=0;i<15;i++)
 				printk("%02X ", current_command->cmnd[i]);
@@ -286,10 +295,10 @@
 		 *	It worked maybe ?
 		 */		
 		current_command->result = DID_OK << 16 | ds;
-	lock = &current_command->host->host_lock;
-	spin_lock(lock);
+	lock = current_command->host->host_lock;
+	spin_lock_irqsave(lock, flags);
 	current_command->scsi_done(current_command);
-	spin_unlock(lock);
+	spin_unlock_irqrestore(lock, flags);
 	return;
 }
 
@@ -322,7 +331,7 @@
 	return 0;
 }
 
-void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
+static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
 {
 	struct i2o_device *unit;
 	struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
@@ -382,7 +391,7 @@
 	}		
 }
 
-int i2o_scsi_detect(Scsi_Host_Template * tpnt)
+static int i2o_scsi_detect(Scsi_Host_Template * tpnt)
 {
 	unsigned long flags;
 	struct Scsi_Host *shpnt = NULL;
@@ -476,7 +485,7 @@
 	return count;
 }
 
-int i2o_scsi_release(struct Scsi_Host *host)
+static int i2o_scsi_release(struct Scsi_Host *host)
 {
 	if(--i2o_scsi_hosts==0)
 	{
@@ -493,45 +502,14 @@
 }
 
 
-const char *i2o_scsi_info(struct Scsi_Host *SChost)
+static const char *i2o_scsi_info(struct Scsi_Host *SChost)
 {
 	struct i2o_scsi_host *hostdata;
-
 	hostdata = (struct i2o_scsi_host *)SChost->hostdata;
-
 	return(&hostdata->controller->name[0]);
 }
 
-
-/*
- * From the wd93 driver:
- * Returns true if there will be a DATA_OUT phase with this command, 
- * false otherwise.
- * (Thanks to Joerg Dorchain for the research and suggestion.)
- *
- */
-static int is_dir_out(Scsi_Cmnd *cmd)
-{
-	switch (cmd->cmnd[0]) 
-	{
-     		case WRITE_6:           case WRITE_10:          case WRITE_12:
-      		case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
-      		case WRITE_VERIFY:      case WRITE_VERIFY_12:      
-      		case COMPARE:           case COPY:              case COPY_VERIFY:
-      		case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
-      		case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:      
-      		case FORMAT_UNIT:       case REASSIGN_BLOCKS:   case RESERVE:
-      		case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
-      		case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
-      		case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
-      		case 0xea:
-        		return 1;
-		default:
-        		return 0;
-	}
-}
-
-int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	int i;
 	int tid;
@@ -597,9 +575,10 @@
 	do
 	{
 		mb();
-		m = I2O_POST_READ32(c);
+		m = le32_to_cpu(I2O_POST_READ32(c));
 	}
 	while(m==0xFFFFFFFF);
+
 	msg = (u32 *)(c->mem_offset + m);
 	
 	/*
@@ -609,28 +588,29 @@
 	len = SCpnt->request_bufflen;
 	direction = 0x00000000;			// SGL IN  (osm<--iop)
 	
-	/*
-	 *	The scsi layer should be handling this stuff
-	 */
-	
-	scsidir = 0x00000000;			// DATA NO XFER
-	if(len)
+	if(SCpnt->sc_data_direction == SCSI_DATA_NONE)
+		scsidir = 0x00000000;			// DATA NO XFER
+	else if(SCpnt->sc_data_direction == SCSI_DATA_WRITE)
 	{
-		if(is_dir_out(SCpnt))
-		{
-			direction=0x04000000;	// SGL OUT  (osm-->iop)
-			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
-		}
-		else
-		{
-			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
-		}
+		direction=0x04000000;	// SGL OUT  (osm-->iop)
+		scsidir  =0x80000000;	// DATA OUT (iop-->dev)
+	}
+	else if(SCpnt->sc_data_direction == SCSI_DATA_READ)
+	{
+		scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+	}
+	else
+	{
+		/* Unknown - kill the command */
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
 	}
 	
-	__raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
+	i2o_raw_writel(I2O_CMD_SCSI_EXEC<<24|HOST_TID<<12|tid, &msg[1]);
+	i2o_raw_writel(scsi_context, &msg[2]);	/* So the I2O layer passes to us */
 	/* Sorry 64bit folks. FIXME */
-	__raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
+	i2o_raw_writel((u32)SCpnt, &msg[3]);	/* We want the SCSI control block back */
 
 	/* LSI_920_PCI_QUIRK
 	 *
@@ -673,7 +653,7 @@
 	}
 
 	/* Direction, disconnect ok, tag, CDBLen */
-	__raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);
+	i2o_raw_writel(scsidir|0x20000000|SCpnt->cmd_len|tag, &msg[4]);
 
 	mptr=msg+5;
 
@@ -708,8 +688,8 @@
 			/*
 			 *	Need to chain!
 			 */
-			__raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);
-			__raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);
+			i2o_raw_writel(direction|0xB0000000|(SCpnt->use_sg*2*4), mptr++);
+			i2o_raw_writel(virt_to_bus(sg_chain_pool + sg_chain_tag), mptr);
 			mptr = (u32*)(sg_chain_pool + sg_chain_tag);
 			if (SCpnt->use_sg > max_sg_len)
 			{
@@ -723,7 +703,7 @@
 			{
 				*mptr++=direction|0x10000000|sg->length;
 				len+=sg->length;
-				*mptr++=virt_to_bus(sg->address);
+				*mptr++=virt_to_bus(page_address(sg->page)+sg->offset);
 				sg++;
 			}
 			mptr[-2]=direction|0xD0000000|(sg-1)->length;
@@ -732,22 +712,22 @@
 		{		
 			for(i = 0 ; i < SCpnt->use_sg; i++)
 			{
-				__raw_writel(direction|0x10000000|sg->length, mptr++);
+				i2o_raw_writel(direction|0x10000000|sg->length, mptr++);
 				len+=sg->length;
-				__raw_writel(virt_to_bus(sg->address), mptr++);
+				i2o_raw_writel(virt_to_bus(page_address(sg->page) + sg->offset), mptr++);
 				sg++;
 			}
 
 			/* Make this an end of list. Again evade the 920 bug and
 			   unwanted PCI read traffic */
 		
-			__raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);
+			i2o_raw_writel(direction|0xD0000000|(sg-1)->length, &mptr[-2]);
 		}
 		
 		if(!chain)
 			reqlen = mptr - msg;
 		
-		__raw_writel(len, lenptr);
+		i2o_raw_writel(len, lenptr);
 		
 		if(len != SCpnt->underflow)
 			printk("Cmd len %08X Cmd underflow %08X\n",
@@ -757,15 +737,15 @@
 	{
 		dprintk(("non sg for %p, %d\n", SCpnt->request_buffer,
 				SCpnt->request_bufflen));
-		__raw_writel(len = SCpnt->request_bufflen, lenptr);
+		i2o_raw_writel(len = SCpnt->request_bufflen, lenptr);
 		if(len == 0)
 		{
 			reqlen = 9;
 		}
 		else
 		{
-			__raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);
-			__raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++);
+			i2o_raw_writel(0xD0000000|direction|SCpnt->request_bufflen, mptr++);
+			i2o_raw_writel(virt_to_bus(SCpnt->request_buffer), mptr++);
 		}
 	}
 	
@@ -773,7 +753,7 @@
 	 *	Stick the headers on 
 	 */
 
-	__raw_writel(reqlen<<16 | SGL_OFFSET_10, msg);
+	i2o_raw_writel(reqlen<<16 | SGL_OFFSET_10, msg);
 	
 	/* Queue the message */
 	i2o_post_message(c,m);
@@ -797,7 +777,7 @@
 	SCpnt->SCp.Status++;
 }
 
-int i2o_scsi_command(Scsi_Cmnd * SCpnt)
+static int i2o_scsi_command(Scsi_Cmnd * SCpnt)
 {
 	i2o_scsi_queuecommand(SCpnt, internal_done);
 	SCpnt->SCp.Status = 0;
@@ -811,7 +791,7 @@
 	struct i2o_controller *c;
 	struct Scsi_Host *host;
 	struct i2o_scsi_host *hostdata;
-	u32 *msg;
+	unsigned long msg;
 	u32 m;
 	int tid;
 	
@@ -835,30 +815,30 @@
 	do
 	{
 		mb();
-		m = I2O_POST_READ32(c);
+		m = le32_to_cpu(I2O_POST_READ32(c));
 	}
 	while(m==0xFFFFFFFF);
-	msg = (u32 *)(c->mem_offset + m);
+	msg = c->mem_offset + m;
 	
-	__raw_writel(FIVE_WORD_MSG_SIZE, &msg[0]);
-	__raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context, &msg[2]);
-	__raw_writel(0, &msg[3]);	/* Not needed for an abort */
-	__raw_writel((u32)SCpnt, &msg[4]);	
+	i2o_raw_writel(FIVE_WORD_MSG_SIZE, msg);
+	i2o_raw_writel(I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|tid, msg+4);
+	i2o_raw_writel(scsi_context, msg+8);
+	i2o_raw_writel(0, msg+12);	/* Not needed for an abort */
+	i2o_raw_writel((u32)SCpnt, msg+16);	
 	wmb();
 	i2o_post_message(c,m);
 	wmb();
 	return SCSI_ABORT_PENDING;
 }
 
-int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+static int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
 	int tid;
 	struct i2o_controller *c;
 	struct Scsi_Host *host;
 	struct i2o_scsi_host *hostdata;
 	u32 m;
-	u32 *msg;
+	unsigned long msg;
 
 	/*
 	 *	Find the TID for the bus
@@ -877,7 +857,7 @@
 	 *	possibly ?
 	 */
 	 
-	m = I2O_POST_READ32(c);
+	m = le32_to_cpu(I2O_POST_READ32(c));
 	
 	/*
 	 *	No free messages, try again next time - no big deal
@@ -886,13 +866,13 @@
 	if(m == 0xFFFFFFFF)
 		return SCSI_RESET_PUNT;
 	
-	msg = (u32 *)(c->mem_offset + m);
-	__raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
-	__raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, &msg[1]);
-	__raw_writel(scsi_context|0x80000000, &msg[2]);
+	msg = c->mem_offset + m;
+	i2o_raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
+	i2o_raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, msg+4);
+	i2o_raw_writel(scsi_context|0x80000000, msg+8);
 	/* We use the top bit to split controller and unit transactions */
 	/* Now store unit,tid so we can tie the completion back to a specific device */
-	__raw_writel(c->unit << 16 | tid, &msg[3]);
+	__raw_writel(c->unit << 16 | tid, msg+12);
 	wmb();
 	i2o_post_message(c,m);
 	return SCSI_RESET_PENDING;
@@ -902,7 +882,7 @@
  *	This is anyones guess quite frankly.
  */
  
-int i2o_scsi_bios_param(Disk * disk, struct block_device *dev, int *ip)
+static int i2o_scsi_bios_param(Disk * disk, struct block_device *dev, int *ip)
 {
 	int size;
 
diff -Nru a/drivers/message/i2o/i2o_scsi.h b/drivers/message/i2o/i2o_scsi.h
--- a/drivers/message/i2o/i2o_scsi.h	Fri Oct 11 21:22:57 2002
+++ b/drivers/message/i2o/i2o_scsi.h	Fri Oct 11 21:22:57 2002
@@ -14,15 +14,14 @@
 #define I2O_SCSI_CAN_QUEUE 4
 #define I2O_SCSI_CMD_PER_LUN 6
 
-extern int i2o_scsi_detect(Scsi_Host_Template *);
-extern const char *i2o_scsi_info(struct Scsi_Host *);
-extern int i2o_scsi_command(Scsi_Cmnd *);
-extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int i2o_scsi_abort(Scsi_Cmnd *);
-extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
-extern int i2o_scsi_bios_param(Disk *, struct block_device *, int *);
-extern void i2o_scsi_setup(char *str, int *ints);
-extern int i2o_scsi_release(struct Scsi_Host *host);
+static int i2o_scsi_detect(Scsi_Host_Template *);
+static const char *i2o_scsi_info(struct Scsi_Host *);
+static int i2o_scsi_command(Scsi_Cmnd *);
+static int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int i2o_scsi_abort(Scsi_Cmnd *);
+static int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
+static int i2o_scsi_bios_param(Disk *, struct block_device *, int *);
+static int i2o_scsi_release(struct Scsi_Host *host);
 
 #define I2OSCSI {                                          \
 		  next: NULL,				    \
diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
--- a/drivers/mtd/devices/blkmtd.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/mtd/devices/blkmtd.c	Fri Oct 11 21:22:51 2002
@@ -164,7 +164,7 @@
   int err;
   int sectornr, sectors, i;
   struct kiobuf *iobuf;
-  unsigned long *blocks;
+  sector_t *blocks;
 
   if(!rawdevice) {
     printk("blkmtd: readpage: PANIC file->private_data == NULL\n");
@@ -223,7 +223,7 @@
 
   /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
+  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(*blocks));
   if(blocks == NULL) {
     printk("blkmtd: cant allocate iobuf blocks\n");
     free_kiovec(1, &iobuf);
@@ -298,7 +298,7 @@
   int err;
   struct task_struct *tsk = current;
   struct kiobuf *iobuf;
-  unsigned long *blocks;
+  sector_t *blocks;
 
   DECLARE_WAITQUEUE(wait, tsk);
   DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid);
diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
--- a/drivers/mtd/nftlcore.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/mtd/nftlcore.c	Fri Oct 11 21:22:51 2002
@@ -802,9 +802,9 @@
 
 		DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
 		DEBUG(MTD_DEBUG_LEVEL3,
-		      "NFTL %s request, from sector 0x%04lx for %d sectors\n",
+		      "NFTL %s request, from sector 0x%04llx for %d sectors\n",
 		      (req->cmd == READ) ? "Read " : "Write",
-		      req->sector, req->current_nr_sectors);
+		      (unsigned long long)req->sector, req->current_nr_sectors);
 
 		dev = minor(req->rq_dev);
 		block = req->sector;
diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c
--- a/drivers/net/3c501.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/net/3c501.c	Fri Oct 11 21:22:50 2002
@@ -11,12 +11,11 @@
     Do not purchase this card, even as a joke.  It's performance is horrible,
     and it breaks in many ways.
 
-    The author may be reached as becker@scyld.com, or C/O
+    The original author may be reached as becker@scyld.com, or C/O
 	Scyld Computing Corporation
 	410 Severn Ave., Suite 210
 	Annapolis MD 21403
 
-
     Fixed (again!) the missing interrupt locking on TX/RX shifting.
     		Alan Cox <Alan.Cox@linux.org>
 
@@ -34,7 +33,16 @@
     		
     Cleaned up for 2.3.x because we broke SMP now. 
     		20000208 Alan Cox <alan@redhat.com>
+
+    Check up pass for 2.5. Nothing significant changed
+    		20021009 Alan Cox <alan@redhat.com>
     		
+   For the avoidance of doubt the "preferred form" of this code is one which
+   is in an open non patent encumbered format. Where cryptographic key signing
+   forms part of the process of creating an executable the information
+   including keys needed to generate an equivalently functional executable
+   are deemed to be part of the source code.
+
 */
 
 
@@ -88,7 +96,7 @@
  */
 
 #define DRV_NAME	"3c501"
-#define DRV_VERSION	"2001/11/17"
+#define DRV_VERSION	"2002/10/09"
 
 
 static const char version[] =
@@ -122,113 +130,21 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 
+#include "3c501.h"
+
 /* A zero-terminated list of I/O addresses to be probed.
    The 3c501 can be at many locations, but here are the popular ones. */
 static unsigned int netcard_portlist[] __initdata = { 
 	0x280, 0x300, 0
 };
 
-
-/*
- *	Index to functions.
- */
-
-int el1_probe(struct net_device *dev);
-static int  el1_probe1(struct net_device *dev, int ioaddr);
-static int  el_open(struct net_device *dev);
-static void el_timeout(struct net_device *dev);
-static int  el_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void el_receive(struct net_device *dev);
-static void el_reset(struct net_device *dev);
-static int  el1_close(struct net_device *dev);
-static struct net_device_stats *el1_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-
-#define EL1_IO_EXTENT	16
-
-#ifndef EL_DEBUG
-#define EL_DEBUG  0	/* use 0 for production, 1 for devel., >2 for debug */
-#endif			/* Anything above 5 is wordy death! */
-#define debug el_debug
-static int el_debug = EL_DEBUG;
-
-/*
- *	Board-specific info in dev->priv.
- */
-
-struct net_local
-{
-	struct net_device_stats stats;
-	int		tx_pkt_start;	/* The length of the current Tx packet. */
-	int		collisions;	/* Tx collisions this packet */
-	int		loading;	/* Spot buffer load collisions */
-	int		txing;		/* True if card is in TX mode */
-	spinlock_t	lock;		/* Serializing lock */
-};
-
-
-#define RX_STATUS (ioaddr + 0x06)
-#define RX_CMD	  RX_STATUS
-#define TX_STATUS (ioaddr + 0x07)
-#define TX_CMD	  TX_STATUS
-#define GP_LOW 	  (ioaddr + 0x08)
-#define GP_HIGH   (ioaddr + 0x09)
-#define RX_BUF_CLR (ioaddr + 0x0A)
-#define RX_LOW	  (ioaddr + 0x0A)
-#define RX_HIGH   (ioaddr + 0x0B)
-#define SAPROM	  (ioaddr + 0x0C)
-#define AX_STATUS (ioaddr + 0x0E)
-#define AX_CMD	  AX_STATUS
-#define DATAPORT  (ioaddr + 0x0F)
-#define TX_RDY 0x08		/* In TX_STATUS */
-
-#define EL1_DATAPTR	0x08
-#define EL1_RXPTR	0x0A
-#define EL1_SAPROM	0x0C
-#define EL1_DATAPORT 	0x0f
-
-/*
- *	Writes to the ax command register.
- */
-
-#define AX_OFF	0x00			/* Irq off, buffer access on */
-#define AX_SYS  0x40			/* Load the buffer */
-#define AX_XMIT 0x44			/* Transmit a packet */
-#define AX_RX	0x48			/* Receive a packet */
-#define AX_LOOP	0x0C			/* Loopback mode */
-#define AX_RESET 0x80
-
-/*
- *	Normal receive mode written to RX_STATUS.  We must intr on short packets
- *	to avoid bogus rx lockups.
- */
-
-#define RX_NORM 0xA8		/* 0x68 == all addrs, 0xA8 only to me. */
-#define RX_PROM 0x68		/* Senior Prom, uhmm promiscuous mode. */
-#define RX_MULT 0xE8		/* Accept multicast packets. */
-#define TX_NORM 0x0A		/* Interrupt on everything that might hang the chip */
-
-/*
- *	TX_STATUS register.
- */
-
-#define TX_COLLISION 0x02
-#define TX_16COLLISIONS 0x04
-#define TX_READY 0x08
-
-#define RX_RUNT 0x08
-#define RX_MISSED 0x01		/* Missed a packet due to 3c501 braindamage. */
-#define RX_GOOD	0x30		/* Good packet 0x20, or simple overflow 0x10. */
-
 
 /*
  *	The boilerplate probe code.
  */
 
 /**
- * el1_probe:
+ * el1_probe:		-	probe for a 3c501
  * @dev: The device structure passed in to probe. 
  *
  * This can be called from two places. The network layer will probe using
@@ -556,7 +472,6 @@
 	while(1);
 
 }
-
 
 /**
  * el_interrupt:
@@ -1072,12 +987,8 @@
 }
 
 #endif /* MODULE */
+
+MODULE_AUTHOR("Donald Becker, Alan Cox");
+MODULE_DESCRIPTION("Support for the ancient 3Com 3c501 ethernet card");
 MODULE_LICENSE("GPL");
 
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer  -m486 -c -o 3c501.o 3c501.c"
- *  kept-new-versions: 5
- * End:
- */
diff -Nru a/drivers/net/3c501.h b/drivers/net/3c501.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/3c501.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,94 @@
+
+/*
+ *	Index to functions.
+ */
+
+int el1_probe(struct net_device *dev);
+static int  el1_probe1(struct net_device *dev, int ioaddr);
+static int  el_open(struct net_device *dev);
+static void el_timeout(struct net_device *dev);
+static int  el_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void el_receive(struct net_device *dev);
+static void el_reset(struct net_device *dev);
+static int  el1_close(struct net_device *dev);
+static struct net_device_stats *el1_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+
+#define EL1_IO_EXTENT	16
+
+#ifndef EL_DEBUG
+#define EL_DEBUG  0	/* use 0 for production, 1 for devel., >2 for debug */
+#endif			/* Anything above 5 is wordy death! */
+#define debug el_debug
+static int el_debug = EL_DEBUG;
+
+/*
+ *	Board-specific info in dev->priv.
+ */
+
+struct net_local
+{
+	struct net_device_stats stats;
+	int		tx_pkt_start;	/* The length of the current Tx packet. */
+	int		collisions;	/* Tx collisions this packet */
+	int		loading;	/* Spot buffer load collisions */
+	int		txing;		/* True if card is in TX mode */
+	spinlock_t	lock;		/* Serializing lock */
+};
+
+
+#define RX_STATUS (ioaddr + 0x06)
+#define RX_CMD	  RX_STATUS
+#define TX_STATUS (ioaddr + 0x07)
+#define TX_CMD	  TX_STATUS
+#define GP_LOW 	  (ioaddr + 0x08)
+#define GP_HIGH   (ioaddr + 0x09)
+#define RX_BUF_CLR (ioaddr + 0x0A)
+#define RX_LOW	  (ioaddr + 0x0A)
+#define RX_HIGH   (ioaddr + 0x0B)
+#define SAPROM	  (ioaddr + 0x0C)
+#define AX_STATUS (ioaddr + 0x0E)
+#define AX_CMD	  AX_STATUS
+#define DATAPORT  (ioaddr + 0x0F)
+#define TX_RDY 0x08		/* In TX_STATUS */
+
+#define EL1_DATAPTR	0x08
+#define EL1_RXPTR	0x0A
+#define EL1_SAPROM	0x0C
+#define EL1_DATAPORT 	0x0f
+
+/*
+ *	Writes to the ax command register.
+ */
+
+#define AX_OFF	0x00			/* Irq off, buffer access on */
+#define AX_SYS  0x40			/* Load the buffer */
+#define AX_XMIT 0x44			/* Transmit a packet */
+#define AX_RX	0x48			/* Receive a packet */
+#define AX_LOOP	0x0C			/* Loopback mode */
+#define AX_RESET 0x80
+
+/*
+ *	Normal receive mode written to RX_STATUS.  We must intr on short packets
+ *	to avoid bogus rx lockups.
+ */
+
+#define RX_NORM 0xA8		/* 0x68 == all addrs, 0xA8 only to me. */
+#define RX_PROM 0x68		/* Senior Prom, uhmm promiscuous mode. */
+#define RX_MULT 0xE8		/* Accept multicast packets. */
+#define TX_NORM 0x0A		/* Interrupt on everything that might hang the chip */
+
+/*
+ *	TX_STATUS register.
+ */
+
+#define TX_COLLISION 0x02
+#define TX_16COLLISIONS 0x04
+#define TX_READY 0x08
+
+#define RX_RUNT 0x08
+#define RX_MISSED 0x01		/* Missed a packet due to 3c501 braindamage. */
+#define RX_GOOD	0x30		/* Good packet 0x20, or simple overflow 0x10. */
+
diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c
--- a/drivers/net/3c509.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/net/3c509.c	Fri Oct 11 21:22:51 2002
@@ -49,11 +49,13 @@
 			- Power Management support
 		v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
 			- Full duplex support
+		v1.19  16Oct2002 Zwane Mwaikambo <zwane@linuxpower.ca>
+			- Additional ethtool features
 */
 
 #define DRV_NAME	"3c509"
-#define DRV_VERSION	"1.18c"
-#define DRV_RELDATE	"1Mar2002"
+#define DRV_VERSION	"1.19"
+#define DRV_RELDATE	"16Oct2002"
 
 /* A few values that may be tweaked. */
 
@@ -140,9 +142,11 @@
 #define TX_STATUS 	0x0B
 #define TX_FREE		0x0C		/* Remaining free bytes in Tx buffer. */
 
+#define WN0_CONF_CTRL	0x04		/* Window 0: Configuration control register */
+#define WN0_ADDR_CONF	0x06		/* Window 0: Address configuration register */
 #define WN0_IRQ		0x08		/* Window 0: Set IRQ line in bits 12-15. */
 #define WN4_MEDIA	0x0A		/* Window 4: Various transcvr/media bits. */
-#define  MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
+#define	MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
 #define WN4_NETDIAG	0x06		/* Window 4: Net diagnostic */
 #define FD_ENABLE	0x8000		/* Enable full-duplex ("external loopback") */  
 
@@ -981,6 +985,119 @@
 	return 0;
 }
 
+static int 
+el3_link_ok(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+	u16 tmp;
+
+	EL3WINDOW(4);
+	tmp = inw(ioaddr + WN4_MEDIA);
+	EL3WINDOW(1);
+	return tmp & (1<<11);
+}
+
+static int
+el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u16 tmp;
+	int ioaddr = dev->base_addr;
+	
+	EL3WINDOW(0);
+	/* obtain current tranceiver via WN4_MEDIA? */	
+	tmp = inw(ioaddr + WN0_ADDR_CONF);
+	ecmd->transceiver = XCVR_INTERNAL;
+	switch (tmp >> 14) {
+	case 0:
+		ecmd->port = PORT_TP;
+		break;
+	case 1:
+		ecmd->port = PORT_AUI;
+		ecmd->transceiver = XCVR_EXTERNAL;
+		break;
+	case 3:
+		ecmd->port = PORT_BNC;
+	default:
+		break;
+	}
+
+	ecmd->duplex = DUPLEX_HALF;
+	ecmd->supported = 0;
+	tmp = inw(ioaddr + WN0_CONF_CTRL);
+	if (tmp & (1<<13))
+		ecmd->supported |= SUPPORTED_AUI;
+	if (tmp & (1<<12))
+		ecmd->supported |= SUPPORTED_BNC;
+	if (tmp & (1<<9)) {
+		ecmd->supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half |
+				SUPPORTED_10baseT_Full;	/* hmm... */
+		EL3WINDOW(4);
+		tmp = inw(ioaddr + WN4_NETDIAG);
+		if (tmp & FD_ENABLE)
+			ecmd->duplex = DUPLEX_FULL;
+	}
+
+	ecmd->speed = SPEED_10;
+	EL3WINDOW(1);
+	return 0;
+}
+
+static int
+el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u16 tmp;
+	int ioaddr = dev->base_addr;
+
+	if (ecmd->speed != SPEED_10)
+		return -EINVAL;
+	if ((ecmd->duplex != DUPLEX_HALF) && (ecmd->duplex != DUPLEX_FULL))
+		return -EINVAL;
+	if ((ecmd->transceiver != XCVR_INTERNAL) && (ecmd->transceiver != XCVR_EXTERNAL))
+		return -EINVAL;
+
+	/* change XCVR type */
+	EL3WINDOW(0);
+	tmp = inw(ioaddr + WN0_ADDR_CONF);
+	switch (ecmd->port) {
+	case PORT_TP:
+		tmp &= ~(3<<14);
+		dev->if_port = 0;
+		break;
+	case PORT_AUI:
+		tmp |= (1<<14);
+		dev->if_port = 1;
+		break;
+	case PORT_BNC:
+		tmp |= (3<<14);
+		dev->if_port = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	outw(tmp, ioaddr + WN0_ADDR_CONF);
+	if (dev->if_port == 3) {
+		/* fire up the DC-DC convertor if BNC gets enabled */
+		tmp = inw(ioaddr + WN0_ADDR_CONF);
+		if (tmp & (3 << 14)) {
+			outw(StartCoax, ioaddr + EL3_CMD);
+			udelay(800);
+		} else
+			return -EIO;
+	}
+
+	EL3WINDOW(4);
+	tmp = inw(ioaddr + WN4_NETDIAG);
+	if (ecmd->duplex == DUPLEX_FULL)
+		tmp |= FD_ENABLE;
+	else
+		tmp &= ~FD_ENABLE;
+	outw(tmp, ioaddr + WN4_NETDIAG);
+	EL3WINDOW(1);
+
+	return 0;
+}
+
 /**
  * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
  * @dev: network interface on which out-of-band action is to be performed
@@ -989,9 +1106,11 @@
  * Process the various commands of the SIOCETHTOOL interface.
  */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int
+netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
+	struct el3_private *lp = dev->priv;
 
 	/* dev_ioctl() in ../../net/core/dev.c has already checked
 	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
@@ -1010,6 +1129,41 @@
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		int ret;
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&lp->lock);
+		ret = el3_netdev_get_ecmd(dev, &ecmd);
+		spin_unlock_irq(&lp->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return ret;
+	}
+
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int ret;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&lp->lock);
+		ret = el3_netdev_set_ecmd(dev, &ecmd);
+		spin_unlock_irq(&lp->lock);
+		return ret;
+	}
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		spin_lock_irq(&lp->lock);
+		edata.data = el3_link_ok(dev);
+		spin_unlock_irq(&lp->lock);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
 	/* get message-level */
 	case ETHTOOL_GMSGLVL: {
 		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
@@ -1043,7 +1197,8 @@
  * Process the various out-of-band ioctls passed to this driver.
  */
 
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static int
+netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int rc = 0;
 
@@ -1060,7 +1215,8 @@
 	return rc;
 }
 
-static void el3_down(struct net_device *dev)
+static void
+el3_down(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
 
@@ -1077,7 +1233,7 @@
 		/* Turn off thinnet power.  Green! */
 		outw(StopCoax, ioaddr + EL3_CMD);
 	else if (dev->if_port == 0) {
-		/* Disable link beat and jabber, if_port may change ere next open(). */
+		/* Disable link beat and jabber, if_port may change here next open(). */
 		EL3WINDOW(4);
 		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
 	}
@@ -1087,7 +1243,8 @@
 	update_stats(dev);
 }
 
-static void el3_up(struct net_device *dev)
+static void
+el3_up(struct net_device *dev)
 {
 	int i, sw_info, net_diag;
 	int ioaddr = dev->base_addr;
@@ -1176,7 +1333,8 @@
 /* Power Management support functions */
 #ifdef CONFIG_PM
 
-static int el3_suspend(struct pm_dev *pdev)
+static int
+el3_suspend(struct pm_dev *pdev)
 {
 	unsigned long flags;
 	struct net_device *dev;
@@ -1202,7 +1360,8 @@
 	return 0;
 }
 
-static int el3_resume(struct pm_dev *pdev)
+static int
+el3_resume(struct pm_dev *pdev)
 {
 	unsigned long flags;
 	struct net_device *dev;
@@ -1228,7 +1387,8 @@
 	return 0;
 }
 
-static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
+static int
+el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
 {
 	switch (rqst) {
 		case PM_SUSPEND:
diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/net/3c59x.c	Fri Oct 11 21:22:50 2002
@@ -1803,7 +1803,7 @@
 		   dev->name, inb(ioaddr + TxStatus),
 		   inw(ioaddr + EL3_STATUS));
 	EL3WINDOW(4);
-	printk(KERN_ERR "  diagnostics: net %04x media %04x dma %08x fifo %04x\n",
+	printk(KERN_ERR "  diagnostics: net %04x media %04x dma %08lx fifo %04x\n",
 			inw(ioaddr + Wn4_NetDiag),
 			inw(ioaddr + Wn4_Media),
 			inl(ioaddr + PktStatus),
@@ -2643,7 +2643,7 @@
 					vp->full_bus_master_tx,
 					vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE,
 					vp->cur_tx, vp->cur_tx % TX_RING_SIZE);
-			printk(KERN_ERR "  Transmit list %8.8x vs. %p.\n",
+			printk(KERN_ERR "  Transmit list %8.8lx vs. %p.\n",
 				   inl(ioaddr + DownListPtr),
 				   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
 			issue_and_wait(dev, DownStall);
diff -Nru a/drivers/net/aironet4500.h b/drivers/net/aironet4500.h
--- a/drivers/net/aironet4500.h	Fri Oct 11 21:22:50 2002
+++ b/drivers/net/aironet4500.h	Fri Oct 11 21:22:50 2002
@@ -28,6 +28,7 @@
 #include <linux/time.h>
 */
 #include <linux/802_11.h>
+#include <linux/workqueue.h>
 
 //damn idiot PCMCIA stuff
 #ifndef DEV_NAME_LEN
diff -Nru a/drivers/net/aironet4500_card.c b/drivers/net/aironet4500_card.c
--- a/drivers/net/aironet4500_card.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/net/aironet4500_card.c	Fri Oct 11 21:23:00 2002
@@ -22,7 +22,6 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/tqueue.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
diff -Nru a/drivers/net/aironet4500_proc.c b/drivers/net/aironet4500_proc.c
--- a/drivers/net/aironet4500_proc.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/net/aironet4500_proc.c	Fri Oct 11 21:22:53 2002
@@ -17,7 +17,6 @@
 #include <linux/version.h>
 
 #include <linux/sched.h>
-#include <linux/tqueue.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
diff -Nru a/drivers/net/bonding.c b/drivers/net/bonding.c
--- a/drivers/net/bonding.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/net/bonding.c	Fri Oct 11 21:23:04 2002
@@ -186,6 +186,11 @@
  *       also added text to distinguish type of load balancing (rr or xor)
  *     - change arp_ip_target module param from "1-12s" (array of 12 ptrs)
  *       to "s" (a single ptr)
+ *
+ * 2002/09/18 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *     - Fixed up bond_check_dev_link() (and callers): removed some magic
+ *	 numbers, banished local MII_ defines, wrapped ioctl calls to
+ *	 prevent EFAULT errors
  */
 
 #include <linux/config.h>
@@ -228,15 +233,6 @@
 #define BOND_LINK_MON_INTERV	0
 #endif
 
-#undef  MII_LINK_UP
-#define MII_LINK_UP	0x04
-
-#undef  MII_ENDOF_NWAY
-#define MII_ENDOF_NWAY	0x20
-
-#undef  MII_LINK_READY
-#define MII_LINK_READY	(MII_LINK_UP)
-
 #ifndef BOND_LINK_ARP_INTERV
 #define BOND_LINK_ARP_INTERV	0
 #endif
@@ -386,13 +382,25 @@
 	return slave;
 }
 
+/*
+ * Less bad way to call ioctl from within the kernel; this needs to be
+ * done some other way to get the call out of interrupt context.
+ * Needs "ioctl" variable to be supplied by calling context.
+ */
+#define IOCTL(dev, arg, cmd) ({		\
+	int ret;			\
+	mm_segment_t fs = get_fs();	\
+	set_fs(get_ds());		\
+	ret = ioctl(dev, arg, cmd);	\
+	set_fs(fs);			\
+	ret; })
+
 /* 
- * if <dev> supports MII link status reporting, check its link
- * and report it as a bit field in a short int :
- *   - 0x04 means link is up,
- *   - 0x20 means end of autonegociation
- * If the device doesn't support MII, then we only report 0x24,
- * meaning that the link is up and running since we can't check it.
+ * if <dev> supports MII link status reporting, check its link status.
+ *
+ * Return either BMSR_LSTATUS, meaning that the link is up (or we
+ * can't tell and just pretend it is), or 0, meaning that the link is
+ * down.
  */
 static u16 bond_check_dev_link(struct net_device *dev)
 {
@@ -401,7 +409,8 @@
 	struct mii_ioctl_data *mii;
 	struct ethtool_value etool;
 
-	if ((ioctl = dev->do_ioctl) != NULL)  { /* ioctl to access MII */
+	ioctl = dev->do_ioctl;
+	if (ioctl) {
 		/* TODO: set pointer to correct ioctl on a per team member */
 		/*       bases to make this more efficient. that is, once  */
 		/*       we determine the correct ioctl, we will always    */
@@ -415,9 +424,9 @@
 		/* effect...                                               */
 	        etool.cmd = ETHTOOL_GLINK;
 	        ifr.ifr_data = (char*)&etool;
-		if (ioctl(dev, &ifr, SIOCETHTOOL) == 0) {
+		if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) {
 			if (etool.data == 1) {
-				return(MII_LINK_READY);
+				return BMSR_LSTATUS;
 			} 
 			else { 
 				return(0);
@@ -431,21 +440,17 @@
 
 		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
 		mii = (struct mii_ioctl_data *)&ifr.ifr_data;
-		if (ioctl(dev, &ifr, SIOCGMIIPHY) != 0) {
-			return MII_LINK_READY;	 /* can't tell */
+		if (IOCTL(dev, &ifr, SIOCGMIIPHY) != 0) {
+			return BMSR_LSTATUS;	 /* can't tell */
 		}
 
-		mii->reg_num = 1;
-		if (ioctl(dev, &ifr, SIOCGMIIREG) == 0) {
-			/*
-			 * mii->val_out contains MII reg 1, BMSR
-			 * 0x0004 means link established
-			 */
-			return mii->val_out;
+		mii->reg_num = MII_BMSR;
+		if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) {
+			return mii->val_out & BMSR_LSTATUS;
 		}
 
 	}
-	return MII_LINK_READY;  /* spoof link up ( we can't check it) */
+	return BMSR_LSTATUS;  /* spoof link up ( we can't check it) */
 }
 
 static u16 bond_check_mii_link(bonding_t *bond)
@@ -459,7 +464,7 @@
 	read_unlock(&bond->ptrlock);
 	read_unlock_irqrestore(&bond->lock, flags);
 
-	return (has_active_interface ? MII_LINK_READY : 0);
+	return (has_active_interface ? BMSR_LSTATUS : 0);
 }
 
 static int bond_open(struct net_device *dev)
@@ -797,8 +802,8 @@
 	new_slave->link_failure_count = 0;
 
 	/* check for initial state */
-	if ((miimon <= 0) || ((bond_check_dev_link(slave_dev) & MII_LINK_READY)
-		 == MII_LINK_READY)) {
+	if ((miimon <= 0) ||
+	    (bond_check_dev_link(slave_dev) == BMSR_LSTATUS)) {
 #ifdef BONDING_DEBUG
 		printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");
 #endif
@@ -1220,7 +1225,7 @@
 
 		switch (slave->link) {
 		case BOND_LINK_UP:	/* the link was up */
-			if ((link_state & MII_LINK_UP) == MII_LINK_UP) {
+			if (link_state == BMSR_LSTATUS) {
 				/* link stays up, tell that this one
 				   is immediately available */
 				if (IS_UP(dev) && (mindelay > -2)) {
@@ -1256,7 +1261,7 @@
 			   ensure proper action to be taken
 			*/
 		case BOND_LINK_FAIL:	/* the link has just gone down */
-			if ((link_state & MII_LINK_UP) == 0) {
+			if (link_state != BMSR_LSTATUS) {
 				/* link stays down */
 				if (slave->delay <= 0) {
 					/* link down for too long time */
@@ -1285,7 +1290,7 @@
 				} else {
 					slave->delay--;
 				}
-			} else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
+			} else {
 				/* link up again */
 				slave->link  = BOND_LINK_UP;
 				printk(KERN_INFO
@@ -1304,7 +1309,7 @@
 			}
 			break;
 		case BOND_LINK_DOWN:	/* the link was down */
-			if ((link_state & MII_LINK_READY) != MII_LINK_READY) {
+			if (link_state != BMSR_LSTATUS) {
 				/* the link stays down, nothing more to do */
 				break;
 			} else {	/* link going up */
@@ -1326,7 +1331,7 @@
 			   case there's something to do.
 			*/
 		case BOND_LINK_BACK:	/* the link has just come back */
-			if ((link_state & MII_LINK_UP) == 0) {
+			if (link_state != BMSR_LSTATUS) {
 				/* link down again */
 				slave->link  = BOND_LINK_DOWN;
 				printk(KERN_INFO
@@ -1335,8 +1340,7 @@
 					master->name,
 					(updelay - slave->delay) * miimon,
 					dev->name);
-			}
-			else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
+			} else {
 				/* link stays up */
 				if (slave->delay == 0) {
 					/* now the link has been up for long time enough */
@@ -2110,7 +2114,7 @@
 
 		len += sprintf(buf + len, "MII Status: ");
 		len += sprintf(buf + len, 
-				link == MII_LINK_READY ? "up\n" : "down\n");
+				link == BMSR_LSTATUS ? "up\n" : "down\n");
 		len += sprintf(buf + len, "MII Polling Interval (ms): %d\n", 
 				miimon);
 		len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
diff -Nru a/drivers/net/de600.c b/drivers/net/de600.c
--- a/drivers/net/de600.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/net/de600.c	Fri Oct 11 21:22:56 2002
@@ -1,5 +1,4 @@
-static const char version[] =
-	"de600.c: $Revision: 1.40 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
+static const char version[] = "de600.c: $Revision: 1.41-2.5 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
 /*
  *	de600.c
  *
@@ -18,10 +17,6 @@
  *	written by: Donald Becker <becker@super.org>
  *		(Now at <becker@scyld.com>)
  *
- *	compile-command:
- *	"gcc -D__KERNEL__  -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer \
- *	 -m486 -c de600.c
- *
  **************************************************************/
 /*
  *	This program is free software; you can redistribute it and/or modify
@@ -39,8 +34,9 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  **************************************************************/
+
 /* Add more time here if your adapter won't work OK: */
-#define DE600_SLOW_DOWN udelay(delay_time)
+#define DE600_SLOW_DOWN	udelay(delay_time)
 
  /*
  * If you still have trouble reading/writing to the adapter,
@@ -49,38 +45,6 @@
  */
 #define SLOW_IO_BY_JUMPING /* Looks "better" than dummy write to port 0x80 :-) */
 
-/*
- * If you want to enable automatic continuous checking for the DE600,
- * keep this #define enabled.
- * It doesn't cost much per packet, so I think it is worth it!
- * If you disagree, comment away the #define, and live with it...
- *
- */
-#define CHECK_LOST_DE600
-
-/*
- * Enable this #define if you want the adapter to do a "ifconfig down" on
- * itself when we have detected that something is possibly wrong with it.
- * The default behaviour is to retry with "adapter_init()" until success.
- * This should be used for debugging purposes only.
- * (Depends on the CHECK_LOST_DE600 above)
- *
- */
-#define SHUTDOWN_WHEN_LOST
-
-/*
- * See comment at "de600_rspace()"!
- * This is an *ugly* hack, but for now it achieves its goal of
- * faking a TCP flow-control that will not flood the poor DE600.
- *
- * Tricks TCP to announce a small max window (max 2 fast packets please :-)
- *
- * Comment away at your own risk!
- *
- * Update: Use the more general per-device maxwindow parameter instead.
- */
-#undef FAKE_SMALL_MAX
-
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifdef DE600_DEBUG
 #define PRINTK(x) if (de600_debug >= 2) printk x
@@ -88,7 +52,7 @@
 #define DE600_DEBUG 0
 #define PRINTK(x) /**/
 #endif
-
+
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -110,162 +74,25 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+#include "de600.h"
+
 static unsigned int de600_debug = DE600_DEBUG;
 MODULE_PARM(de600_debug, "i");
 MODULE_PARM_DESC(de600_debug, "DE-600 debug level (0-2)");
 
+static unsigned int check_lost = 1;
+MODULE_PARM(check_lost, "i");
+MODULE_PARM_DESC(check_lost, "If set then check for unplugged de600");
+
 static unsigned int delay_time = 10;
 MODULE_PARM(delay_time, "i");
 MODULE_PARM_DESC(delay_time, "DE-600 deley on I/O in microseconds");
 
-#ifdef FAKE_SMALL_MAX
-static unsigned long de600_rspace(struct sock *sk);
-#include <net/sock.h>
-#endif
-
-typedef unsigned char byte;
-
-/**************************************************
- *                                                *
- * Definition of D-Link Ethernet Pocket adapter   *
- *                                                *
- **************************************************/
-/*
- * D-Link Ethernet pocket adapter ports
- */
-/*
- * OK, so I'm cheating, but there are an awful lot of
- * reads and writes in order to get anything in and out
- * of the DE-600 with 4 bits at a time in the parallel port,
- * so every saved instruction really helps :-)
- *
- * That is, I don't care what the device struct says
- * but hope that Space.c will keep the rest of the drivers happy.
- */
-#ifndef DE600_IO
-#define DE600_IO 0x378
-#endif
-
-#define DATA_PORT	(DE600_IO)
-#define STATUS_PORT	(DE600_IO + 1)
-#define COMMAND_PORT	(DE600_IO + 2)
-
-#ifndef DE600_IRQ
-#define DE600_IRQ	7
-#endif
-/*
- * It really should look like this, and autoprobing as well...
- *
-#define DATA_PORT	(dev->base_addr + 0)
-#define STATUS_PORT	(dev->base_addr + 1)
-#define COMMAND_PORT	(dev->base_addr + 2)
-#define DE600_IRQ	dev->irq
- */
-
-/*
- * D-Link COMMAND_PORT commands
- */
-#define SELECT_NIC	0x04 /* select Network Interface Card */
-#define SELECT_PRN	0x1c /* select Printer */
-#define NML_PRN		0xec /* normal Printer situation */
-#define IRQEN		0x10 /* enable IRQ line */
-
-/*
- * D-Link STATUS_PORT
- */
-#define RX_BUSY		0x80
-#define RX_GOOD		0x40
-#define TX_FAILED16	0x10
-#define TX_BUSY		0x08
-
-/*
- * D-Link DATA_PORT commands
- * command in low 4 bits
- * data in high 4 bits
- * select current data nibble with HI_NIBBLE bit
- */
-#define WRITE_DATA	0x00 /* write memory */
-#define READ_DATA	0x01 /* read memory */
-#define STATUS		0x02 /* read  status register */
-#define COMMAND		0x03 /* write command register (see COMMAND below) */
-#define NULL_COMMAND	0x04 /* null command */
-#define RX_LEN		0x05 /* read  received packet length */
-#define TX_ADDR		0x06 /* set adapter transmit memory address */
-#define RW_ADDR		0x07 /* set adapter read/write memory address */
-#define HI_NIBBLE	0x08 /* read/write the high nibble of data,
-				or-ed with rest of command */
-
-/*
- * command register, accessed through DATA_PORT with low bits = COMMAND
- */
-#define RX_ALL		0x01 /* PROMISCUOUS */
-#define RX_BP		0x02 /* default: BROADCAST & PHYSICAL ADDRESS */
-#define RX_MBP		0x03 /* MULTICAST, BROADCAST & PHYSICAL ADDRESS */
-
-#define TX_ENABLE	0x04 /* bit 2 */
-#define RX_ENABLE	0x08 /* bit 3 */
-
-#define RESET		0x80 /* set bit 7 high */
-#define STOP_RESET	0x00 /* set bit 7 low */
-
-/*
- * data to command register
- * (high 4 bits in write to DATA_PORT)
- */
-#define RX_PAGE2_SELECT	0x10 /* bit 4, only 2 pages to select */
-#define RX_BASE_PAGE	0x20 /* bit 5, always set when specifying RX_ADDR */
-#define FLIP_IRQ	0x40 /* bit 6 */
-
-/*
- * D-Link adapter internal memory:
- *
- * 0-2K 1:st transmit page (send from pointer up to 2K)
- * 2-4K	2:nd transmit page (send from pointer up to 4K)
- *
- * 4-6K 1:st receive page (data from 4K upwards)
- * 6-8K 2:nd receive page (data from 6K upwards)
- *
- * 8K+	Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
- */
-#define MEM_2K		0x0800 /* 2048 */
-#define MEM_4K		0x1000 /* 4096 */
-#define MEM_6K		0x1800 /* 6144 */
-#define NODE_ADDRESS	0x2000 /* 8192 */
-
-#define RUNT 60		/* Too small Ethernet packet */
-
-/**************************************************
- *                                                *
- *             End of definition                  *
- *                                                *
- **************************************************/
-
-/*
- * Index to functions, as function prototypes.
- */
-/* Routines used internally. (See "convenience macros") */
-static byte	de600_read_status(struct net_device *dev);
-static byte	de600_read_byte(unsigned char type, struct net_device *dev);
-
-/* Put in the device structure. */
-static int	de600_open(struct net_device *dev);
-static int	de600_close(struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
-static int	de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
-
-/* Dispatch from interrupts. */
-static void	de600_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int	de600_tx_intr(struct net_device *dev, int irq_status);
-static void	de600_rx_intr(struct net_device *dev);
-
-/* Initialization */
-static void	trigger_interrupt(struct net_device *dev);
-int		de600_probe(struct net_device *dev);
-static int	adapter_init(struct net_device *dev);
 
 /*
  * D-Link driver variables:
  */
+
 static volatile int		rx_page;
 
 #define TX_PAGES 2
@@ -274,46 +101,11 @@
 static volatile int		tx_fifo_out;
 static volatile int		free_tx_pages = TX_PAGES;
 static int			was_down;
+static spinlock_t		de600_lock;
 
-/*
- * Convenience macros/functions for D-Link adapter
- */
-
-#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN
-#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN
-
-/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
-#define de600_put_byte(data) ( \
-	outb_p(((data) << 4)   | WRITE_DATA            , DATA_PORT), \
-	outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
-
-/*
- * The first two outb_p()'s below could perhaps be deleted if there
- * would be more delay in the last two. Not certain about it yet...
- */
-#define de600_put_command(cmd) ( \
-	outb_p(( rx_page        << 4)   | COMMAND            , DATA_PORT), \
-	outb_p(( rx_page        & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
-	outb_p(((rx_page | cmd) << 4)   | COMMAND            , DATA_PORT), \
-	outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
-
-#define de600_setup_address(addr,type) ( \
-	outb_p((((addr) << 4) & 0xf0) | type            , DATA_PORT), \
-	outb_p(( (addr)       & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
-	outb_p((((addr) >> 4) & 0xf0) | type            , DATA_PORT), \
-	outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
-
-#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
-
-/* Flip bit, only 2 pages */
-#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
-
-#define tx_page_adr(a) (((a) + 1) * MEM_2K)
-
-static inline byte
-de600_read_status(struct net_device *dev)
+static inline u8 de600_read_status(struct net_device *dev)
 {
-	byte status;
+	u8 status;
 
 	outb_p(STATUS, DATA_PORT);
 	status = inb(STATUS_PORT);
@@ -322,16 +114,16 @@
 	return status;
 }
 
-static inline byte
-de600_read_byte(unsigned char type, struct net_device *dev) { /* dev used by macros */
-	byte lo;
-
-	(void)outb_p((type), DATA_PORT);
+static inline u8 de600_read_byte(unsigned char type, struct net_device *dev)
+{
+	/* dev used by macros */
+	u8 lo;
+	outb_p((type), DATA_PORT);
 	lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
-	(void)outb_p((type) | HI_NIBBLE, DATA_PORT);
+	outb_p((type) | HI_NIBBLE, DATA_PORT);
 	return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
 }
-
+
 /*
  * Open/initialize the board.  This is called (in the current kernel)
  * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
@@ -340,26 +132,26 @@
  * registers that "should" only need to be set once at boot, so that
  * there is a non-reboot way to recover if something goes wrong.
  */
-static int
-de600_open(struct net_device *dev)
+
+static int de600_open(struct net_device *dev)
 {
+	unsigned long flags;
 	int ret = request_irq(DE600_IRQ, de600_interrupt, 0, dev->name, dev);
 	if (ret) {
-		printk ("%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
+		printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
 		return ret;
 	}
-
-	if (adapter_init(dev))
-		return -EIO;
-
-	return 0;
+	spin_lock_irqsave(&de600_lock, flags);
+	ret = adapter_init(dev);
+	spin_unlock_irqrestore(&de600_lock, flags);
+	return ret;
 }
 
 /*
  * The inverse routine to de600_open().
  */
-static int
-de600_close(struct net_device *dev)
+
+static int de600_close(struct net_device *dev)
 {
 	select_nic();
 	rx_page = 0;
@@ -367,21 +159,16 @@
 	de600_put_command(STOP_RESET);
 	de600_put_command(0);
 	select_prn();
-
-	if (netif_running(dev)) { /* perhaps not needed? */
-		free_irq(DE600_IRQ, dev);
-	}
+	free_irq(DE600_IRQ, dev);
 	return 0;
 }
 
-static struct net_device_stats *
-get_stats(struct net_device *dev)
+static struct net_device_stats *get_stats(struct net_device *dev)
 {
-    return (struct net_device_stats *)(dev->priv);
+	return (struct net_device_stats *)(dev->priv);
 }
 
-static inline void
-trigger_interrupt(struct net_device *dev)
+static inline void trigger_interrupt(struct net_device *dev)
 {
 	de600_put_command(FLIP_IRQ);
 	select_prn();
@@ -394,31 +181,28 @@
  * Copy a buffer to the adapter transmit page memory.
  * Start sending.
  */
-static int
-de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 
+static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	unsigned long flags;
 	int	transmit_from;
 	int	len;
 	int	tickssofar;
-	byte	*buffer = skb->data;
+	u8	*buffer = skb->data;
 
 	if (free_tx_pages <= 0) {	/* Do timeouts, to avoid hangs. */
 		tickssofar = jiffies - dev->trans_start;
-
 		if (tickssofar < 5)
 			return 1;
-
 		/* else */
-		printk("%s: transmit timed out (%d), %s?\n",
-			dev->name,
-			tickssofar,
-			"network cable problem"
-			);
+		printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
 		/* Restart the adapter. */
+		spin_lock_irqsave(&de600_lock, flags);
 		if (adapter_init(dev)) {
+			spin_unlock_irqrestore(&de600_lock, flags);
 			return 1;
 		}
+		spin_unlock_irqrestore(&de600_lock, flags);
 	}
 
 	/* Start real output */
@@ -427,23 +211,23 @@
 	if ((len = skb->len) < RUNT)
 		len = RUNT;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&de600_lock, flags);
 	select_nic();
 	tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
 	tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
 
-#ifdef CHECK_LOST_DE600
-	/* This costs about 40 instructions per packet... */
-	de600_setup_address(NODE_ADDRESS, RW_ADDR);
-	de600_read_byte(READ_DATA, dev);
-	if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
-		if (adapter_init(dev)) {
-			restore_flags(flags);
-			return 1;
+	if(check_lost)
+	{
+		/* This costs about 40 instructions per packet... */
+		de600_setup_address(NODE_ADDRESS, RW_ADDR);
+		de600_read_byte(READ_DATA, dev);
+		if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
+			if (adapter_init(dev)) {
+				spin_unlock_irqrestore(&de600_lock, flags);
+				return 1;
+			}
 		}
 	}
-#endif
 
 	de600_setup_address(transmit_from, RW_ADDR);
 	for ( ; len > 0; --len, ++buffer)
@@ -463,39 +247,31 @@
 			netif_stop_queue(dev);
 		select_prn();
 	}
-
-	restore_flags(flags);
-
-#ifdef FAKE_SMALL_MAX
-	/* This will "patch" the socket TCP proto at an early moment */
-	if (skb->sk && (skb->sk->protocol == IPPROTO_TCP) &&
-		(skb->sk->prot->rspace != &de600_rspace))
-		skb->sk->prot->rspace = de600_rspace; /* Ugh! */
-#endif
-
-	dev_kfree_skb (skb);
-
+	spin_unlock_irqrestore(&de600_lock, flags);
+	dev_kfree_skb(skb);
 	return 0;
 }
-
+
 /*
  * The typical workload of the driver:
  * Handle the network interface interrupts.
  */
-static void
-de600_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+
+static void de600_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device	*dev = dev_id;
-	byte		irq_status;
+	u8		irq_status;
 	int		retrig = 0;
 	int		boguscount = 0;
 
 	/* This might just as well be deleted now, no crummy drivers present :-) */
 	if ((dev == NULL) || (DE600_IRQ != irq)) {
-		printk("%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq);
+		printk(KERN_ERR "%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq);
 		return;
 	}
 
+	spin_lock(&de600_lock);
+	
 	select_nic();
 	irq_status = de600_read_status(dev);
 
@@ -523,15 +299,13 @@
 
 	/* Enable adapter interrupts */
 	select_prn();
-
 	if (retrig)
 		trigger_interrupt(dev);
-
+	spin_unlock(&de600_lock);
 	return;
 }
 
-static int
-de600_tx_intr(struct net_device *dev, int irq_status)
+static int de600_tx_intr(struct net_device *dev, int irq_status)
 {
 	/*
 	 * Returns 1 if tx still not done
@@ -565,18 +339,13 @@
 /*
  * We have a good packet, get it out of the adapter.
  */
-static void
-de600_rx_intr(struct net_device *dev)
+static void de600_rx_intr(struct net_device *dev)
 {
 	struct sk_buff	*skb;
-	unsigned long flags;
 	int		i;
 	int		read_from;
 	int		size;
-	register unsigned char	*buffer;
-
-	save_flags(flags);
-	cli();
+	unsigned char	*buffer;
 
 	/* Get size of received packet */
 	size = de600_read_byte(RX_LEN, dev);	/* low byte */
@@ -588,10 +357,8 @@
 	next_rx_page();
 	de600_put_command(RX_ENABLE);
 
-	restore_flags(flags);
-
 	if ((size < 32)  ||  (size > 1535)) {
-		printk("%s: Bogus packet size %d.\n", dev->name, size);
+		printk(KERN_WARNING "%s: Bogus packet size %d.\n", dev->name, size);
 		if (size > 10000)
 			adapter_init(dev);
 		return;
@@ -599,8 +366,7 @@
 
 	skb = dev_alloc_skb(size+2);
 	if (skb == NULL) {
-		printk("%s: Couldn't allocate a sk_buff of size %d.\n",
-			dev->name, size);
+		printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
 		return;
 	}
 	/* else */
@@ -627,13 +393,11 @@
 
 	/*
 	 * If any worth-while packets have been received, netif_rx()
-	 * has done a mark_bh(INET_BH) for us and will work on them
-	 * when we get to the bottom-half routine.
+	 * will work on them when we get to the tasklets.
 	 */
 }
 
-int __init 
-de600_probe(struct net_device *dev)
+int __init de600_probe(struct net_device *dev)
 {
 	int	i;
 	static struct net_device_stats de600_netstats;
@@ -641,7 +405,7 @@
 
 	SET_MODULE_OWNER(dev);
 
-	printk("%s: D-Link DE-600 pocket adapter", dev->name);
+	printk(KERN_INFO "%s: D-Link DE-600 pocket adapter", dev->name);
 	/* Alpha testers must have the version number to report bugs. */
 	if (de600_debug > 1)
 		printk(version);
@@ -682,12 +446,6 @@
 		return -ENODEV;
 	}
 
-#if 0 /* Not yet */
-	if (check_region(DE600_IO, 3)) {
-		printk(", port 0x%x busy\n", DE600_IO);
-		return -EBUSY;
-	}
-#endif
 	request_region(DE600_IO, 3, "de600");
 
 	printk(", Ethernet Address: %02X", dev->dev_addr[0]);
@@ -713,20 +471,15 @@
 	return 0;
 }
 
-static int
-adapter_init(struct net_device *dev)
+static int adapter_init(struct net_device *dev)
 {
 	int	i;
-       unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
 	select_nic();
 	rx_page = 0; /* used by RESET */
 	de600_put_command(RESET);
 	de600_put_command(STOP_RESET);
-#ifdef CHECK_LOST_DE600
+
 	/* Check if it is still there... */
 	/* Get the some bytes of the adapter ethernet address from the ROM */
 	de600_setup_address(NODE_ADDRESS, RW_ADDR);
@@ -734,32 +487,25 @@
 	if ((de600_read_byte(READ_DATA, dev) != 0xde) ||
 	    (de600_read_byte(READ_DATA, dev) != 0x15)) {
 	/* was: if (de600_read_status(dev) & 0xf0) { */
-		printk("Something has happened to the DE-600!  Please check it"
-#ifdef SHUTDOWN_WHEN_LOST
-			" and do a new ifconfig"
-#endif /* SHUTDOWN_WHEN_LOST */
-			"!\n");
-#ifdef SHUTDOWN_WHEN_LOST
+		printk("Something has happened to the DE-600!  Please check it and do a new ifconfig!\n");
 		/* Goodbye, cruel world... */
 		dev->flags &= ~IFF_UP;
 		de600_close(dev);
-#endif /* SHUTDOWN_WHEN_LOST */
 		was_down = 1;
 		netif_stop_queue(dev); /* Transmit busy...  */
-		restore_flags(flags);
 		return 1; /* failed */
 	}
-#endif /* CHECK_LOST_DE600 */
+
 	if (was_down) {
-		printk("Thanks, I feel much better now!\n");
+		printk(KERN_INFO "%s: Thanks, I feel much better now!\n", dev->name);
 		was_down = 0;
 	}
 
-	netif_start_queue(dev);
 	tx_fifo_in = 0;
 	tx_fifo_out = 0;
 	free_tx_pages = TX_PAGES;
 
+
 	/* set the ether address. */
 	de600_setup_address(NODE_ADDRESS, RW_ADDR);
 	for (i = 0; i < ETH_ALEN; i++)
@@ -771,82 +517,30 @@
 	/* Enable receiver */
 	de600_put_command(RX_ENABLE);
 	select_prn();
-	restore_flags(flags);
+
+	netif_start_queue(dev);
 
 	return 0; /* OK */
 }
 
-#ifdef FAKE_SMALL_MAX
-/*
- *	The new router code (coming soon 8-) ) will fix this properly.
- */
-#define DE600_MIN_WINDOW 1024
-#define DE600_MAX_WINDOW 2048
-#define DE600_TCP_WINDOW_DIFF 1024
-/*
- * Copied from "net/inet/sock.c"
- *
- * Sets a lower max receive window in order to achieve <= 2
- * packets arriving at the adapter in fast succession.
- * (No way that a DE-600 can keep up with a net saturated
- *  with packets homing in on it :-( )
- *
- * Since there are only 2 receive buffers in the DE-600
- * and it takes some time to copy from the adapter,
- * this is absolutely necessary for any TCP performance whatsoever!
- *
- * Note that the returned window info will never be smaller than
- * DE600_MIN_WINDOW, i.e. 1024
- * This differs from the standard function, that can return an
- * arbitrarily small window!
- */
-static unsigned long
-de600_rspace(struct sock *sk)
-{
-  int amt;
-
-  if (sk != NULL) {
-/*
- * Hack! You might want to play with commenting away the following line,
- * if you know what you do!
-  	sk->max_unacked = DE600_MAX_WINDOW - DE600_TCP_WINDOW_DIFF;
- */
-
-	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf-2*DE600_MIN_WINDOW) return(0);
-	amt = min_t(int, (sk->rcvbuf-atomic_read(&sk->rmem_alloc))/2/*-DE600_MIN_WINDOW*/, DE600_MAX_WINDOW);
-	if (amt < 0) return(0);
-	return(amt);
-  }
-  return(0);
-}
-#endif
-
-#ifdef MODULE
 static struct net_device de600_dev;
 
-int
-init_module(void)
+static int __init de600_init(void)
 {
+	spin_lock_init(&de600_lock);
 	de600_dev.init = de600_probe;
 	if (register_netdev(&de600_dev) != 0)
 		return -EIO;
 	return 0;
 }
 
-void
-cleanup_module(void)
+static void __exit de600_exit(void)
 {
 	unregister_netdev(&de600_dev);
 	release_region(DE600_IO, 3);
 }
-#endif /* MODULE */
 
-MODULE_LICENSE("GPL");
+module_init(de600_init);
+module_exit(de600_exit);
 
-/*
- * Local variables:
- *  kernel-compile-command: "gcc -D__KERNEL__ -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de600.c"
- *  module-compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de600.c"
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de600.c"
- * End:
- */
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/de600.h b/drivers/net/de600.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/de600.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,170 @@
+/**************************************************
+ *                                                *
+ * Definition of D-Link Ethernet Pocket adapter   *
+ *                                                *
+ **************************************************/
+/*
+ * D-Link Ethernet pocket adapter ports
+ */
+/*
+ * OK, so I'm cheating, but there are an awful lot of
+ * reads and writes in order to get anything in and out
+ * of the DE-600 with 4 bits at a time in the parallel port,
+ * so every saved instruction really helps :-)
+ */
+
+#ifndef DE600_IO
+#define DE600_IO	0x378
+#endif
+
+#define DATA_PORT	(DE600_IO)
+#define STATUS_PORT	(DE600_IO + 1)
+#define COMMAND_PORT	(DE600_IO + 2)
+
+#ifndef DE600_IRQ
+#define DE600_IRQ	7
+#endif
+/*
+ * It really should look like this, and autoprobing as well...
+ *
+#define DATA_PORT	(dev->base_addr + 0)
+#define STATUS_PORT	(dev->base_addr + 1)
+#define COMMAND_PORT	(dev->base_addr + 2)
+#define DE600_IRQ	dev->irq
+ */
+
+/*
+ * D-Link COMMAND_PORT commands
+ */
+#define SELECT_NIC	0x04 /* select Network Interface Card */
+#define SELECT_PRN	0x1c /* select Printer */
+#define NML_PRN		0xec /* normal Printer situation */
+#define IRQEN		0x10 /* enable IRQ line */
+
+/*
+ * D-Link STATUS_PORT
+ */
+#define RX_BUSY		0x80
+#define RX_GOOD		0x40
+#define TX_FAILED16	0x10
+#define TX_BUSY		0x08
+
+/*
+ * D-Link DATA_PORT commands
+ * command in low 4 bits
+ * data in high 4 bits
+ * select current data nibble with HI_NIBBLE bit
+ */
+#define WRITE_DATA	0x00 /* write memory */
+#define READ_DATA	0x01 /* read memory */
+#define STATUS		0x02 /* read  status register */
+#define COMMAND		0x03 /* write command register (see COMMAND below) */
+#define NULL_COMMAND	0x04 /* null command */
+#define RX_LEN		0x05 /* read  received packet length */
+#define TX_ADDR		0x06 /* set adapter transmit memory address */
+#define RW_ADDR		0x07 /* set adapter read/write memory address */
+#define HI_NIBBLE	0x08 /* read/write the high nibble of data,
+				or-ed with rest of command */
+
+/*
+ * command register, accessed through DATA_PORT with low bits = COMMAND
+ */
+#define RX_ALL		0x01 /* PROMISCUOUS */
+#define RX_BP		0x02 /* default: BROADCAST & PHYSICAL ADDRESS */
+#define RX_MBP		0x03 /* MULTICAST, BROADCAST & PHYSICAL ADDRESS */
+
+#define TX_ENABLE	0x04 /* bit 2 */
+#define RX_ENABLE	0x08 /* bit 3 */
+
+#define RESET		0x80 /* set bit 7 high */
+#define STOP_RESET	0x00 /* set bit 7 low */
+
+/*
+ * data to command register
+ * (high 4 bits in write to DATA_PORT)
+ */
+#define RX_PAGE2_SELECT	0x10 /* bit 4, only 2 pages to select */
+#define RX_BASE_PAGE	0x20 /* bit 5, always set when specifying RX_ADDR */
+#define FLIP_IRQ	0x40 /* bit 6 */
+
+/*
+ * D-Link adapter internal memory:
+ *
+ * 0-2K 1:st transmit page (send from pointer up to 2K)
+ * 2-4K	2:nd transmit page (send from pointer up to 4K)
+ *
+ * 4-6K 1:st receive page (data from 4K upwards)
+ * 6-8K 2:nd receive page (data from 6K upwards)
+ *
+ * 8K+	Adapter ROM (contains magic code and last 3 bytes of Ethernet address)
+ */
+#define MEM_2K		0x0800 /* 2048 */
+#define MEM_4K		0x1000 /* 4096 */
+#define MEM_6K		0x1800 /* 6144 */
+#define NODE_ADDRESS	0x2000 /* 8192 */
+
+#define RUNT 60		/* Too small Ethernet packet */
+
+/**************************************************
+ *                                                *
+ *             End of definition                  *
+ *                                                *
+ **************************************************/
+
+/*
+ * Index to functions, as function prototypes.
+ */
+/* Routines used internally. (See "convenience macros") */
+static u8	de600_read_status(struct net_device *dev);
+static u8	de600_read_byte(unsigned char type, struct net_device *dev);
+
+/* Put in the device structure. */
+static int	de600_open(struct net_device *dev);
+static int	de600_close(struct net_device *dev);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static int	de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+/* Dispatch from interrupts. */
+static void	de600_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int	de600_tx_intr(struct net_device *dev, int irq_status);
+static void	de600_rx_intr(struct net_device *dev);
+
+/* Initialization */
+static void	trigger_interrupt(struct net_device *dev);
+int		de600_probe(struct net_device *dev);
+static int	adapter_init(struct net_device *dev);
+
+/*
+ * Convenience macros/functions for D-Link adapter
+ */
+
+#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); DE600_SLOW_DOWN
+#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); DE600_SLOW_DOWN
+
+/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
+#define de600_put_byte(data) ( \
+	outb_p(((data) << 4)   | WRITE_DATA            , DATA_PORT), \
+	outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
+
+/*
+ * The first two outb_p()'s below could perhaps be deleted if there
+ * would be more delay in the last two. Not certain about it yet...
+ */
+#define de600_put_command(cmd) ( \
+	outb_p(( rx_page        << 4)   | COMMAND            , DATA_PORT), \
+	outb_p(( rx_page        & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
+	outb_p(((rx_page | cmd) << 4)   | COMMAND            , DATA_PORT), \
+	outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
+
+#define de600_setup_address(addr,type) ( \
+	outb_p((((addr) << 4) & 0xf0) | type            , DATA_PORT), \
+	outb_p(( (addr)       & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
+	outb_p((((addr) >> 4) & 0xf0) | type            , DATA_PORT), \
+	outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
+
+#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
+
+/* Flip bit, only 2 pages */
+#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
+
+#define tx_page_adr(a) (((a) + 1) * MEM_2K)
diff -Nru a/drivers/net/depca.c b/drivers/net/depca.c
--- a/drivers/net/depca.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/net/depca.c	Fri Oct 11 21:22:59 2002
@@ -267,8 +267,7 @@
 
 #include "depca.h"
 
-static char version[] __initdata =
-	"depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
+static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
 
 #ifdef DEPCA_DEBUG
 static int depca_debug = DEPCA_DEBUG;
@@ -276,7 +275,7 @@
 static int depca_debug = 1;
 #endif
 
-#define DEPCA_NDA 0xffe0            /* No Device Address */
+#define DEPCA_NDA 0xffe0	/* No Device Address */
 
 #define TX_TIMEOUT (1*HZ)
 
@@ -293,15 +292,15 @@
 **
 ** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
 */
-#define NUM_RX_DESC     8               /* Number of RX descriptors */
-#define NUM_TX_DESC     8               /* Number of TX descriptors */
-#define RX_BUFF_SZ	1536            /* Buffer size for each Rx buffer */
-#define TX_BUFF_SZ	1536            /* Buffer size for each Tx buffer */
+#define NUM_RX_DESC     8	/* Number of RX descriptors */
+#define NUM_TX_DESC     8	/* Number of TX descriptors */
+#define RX_BUFF_SZ	1536	/* Buffer size for each Rx buffer */
+#define TX_BUFF_SZ	1536	/* Buffer size for each Tx buffer */
 
 /*
 ** EISA bus defines
 */
-#define DEPCA_EISA_IO_PORTS 0x0c00       /* I/O port base address, slot 0 */
+#define DEPCA_EISA_IO_PORTS 0x0c00	/* I/O port base address, slot 0 */
 #define MAX_EISA_SLOTS 16
 #define EISA_SLOT_INC 0x1000
 
@@ -328,7 +327,7 @@
                          "DE422",\
                          ""}
 static enum {
-  DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
+	DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
 } adapter;
 
 /*
@@ -340,81 +339,81 @@
 /*
 ** Memory Alignment. Each descriptor is 4 longwords long. To force a
 ** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
-** DESC_ALIGN. ALIGN aligns the start address of the private memory area
+** DESC_ALIGN. DEPCA_ALIGN aligns the start address of the private memory area
 ** and hence the RX descriptor ring's first entry. 
 */
-#define ALIGN4      ((u_long)4 - 1)       /* 1 longword align */
-#define ALIGN8      ((u_long)8 - 1)       /* 2 longword (quadword) align */
-#define ALIGN         ALIGN8              /* Keep the LANCE happy... */
+#define DEPCA_ALIGN4      ((u_long)4 - 1)	/* 1 longword align */
+#define DEPCA_ALIGN8      ((u_long)8 - 1)	/* 2 longword (quadword) align */
+#define DEPCA_ALIGN         DEPCA_ALIGN8	/* Keep the LANCE happy... */
 
 /*
 ** The DEPCA Rx and Tx ring descriptors. 
 */
 struct depca_rx_desc {
-    volatile s32 base;
-    s16 buf_length;		/* This length is negative 2's complement! */
-    s16 msg_length;		/* This length is "normal". */
+	volatile s32 base;
+	s16 buf_length;		/* This length is negative 2's complement! */
+	s16 msg_length;		/* This length is "normal". */
 };
 
 struct depca_tx_desc {
-    volatile s32 base;
-    s16 length;		        /* This length is negative 2's complement! */
-    s16 misc;                   /* Errors and TDR info */
+	volatile s32 base;
+	s16 length;		/* This length is negative 2's complement! */
+	s16 misc;		/* Errors and TDR info */
 };
 
-#define LA_MASK 0x0000ffff      /* LANCE address mask for mapping network RAM
+#define LA_MASK 0x0000ffff	/* LANCE address mask for mapping network RAM
 				   to LANCE memory address space */
 
 /*
 ** The Lance initialization block, described in databook, in common memory.
 */
 struct depca_init {
-    u16 mode;	                /* Mode register */
-    u8  phys_addr[ETH_ALEN];	/* Physical ethernet address */
-    u8  mcast_table[8];	        /* Multicast Hash Table. */
-    u32 rx_ring;     	        /* Rx ring base pointer & ring length */
-    u32 tx_ring;	        /* Tx ring base pointer & ring length */
+	u16 mode;		/* Mode register */
+	u8 phys_addr[ETH_ALEN];	/* Physical ethernet address */
+	u8 mcast_table[8];	/* Multicast Hash Table. */
+	u32 rx_ring;		/* Rx ring base pointer & ring length */
+	u32 tx_ring;		/* Tx ring base pointer & ring length */
 };
 
 #define DEPCA_PKT_STAT_SZ 16
-#define DEPCA_PKT_BIN_SZ  128                /* Should be >=100 unless you
-                                                increase DEPCA_PKT_STAT_SZ */
+#define DEPCA_PKT_BIN_SZ  128	/* Should be >=100 unless you
+				   increase DEPCA_PKT_STAT_SZ */
 struct depca_private {
-    char devname[DEPCA_STRLEN];    /* Device Product String                  */
-    char adapter_name[DEPCA_STRLEN];/* /proc/ioports string                  */
-    char adapter;                  /* Adapter type                           */
-    char mca_slot;                 /* MCA slot, if MCA else -1               */
-    struct depca_init	init_block;/* Shadow Initialization block            */
+	char devname[DEPCA_STRLEN];	/* Device Product String                  */
+	char adapter_name[DEPCA_STRLEN];	/* /proc/ioports string                  */
+	char adapter;		/* Adapter type                           */
+	char mca_slot;		/* MCA slot, if MCA else -1               */
+	struct depca_init init_block;	/* Shadow Initialization block            */
 /* CPU address space fields */
-    struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
-    struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
-    void *rx_buff[NUM_RX_DESC];    /* CPU virt address of sh'd memory buffs  */
-    void *tx_buff[NUM_TX_DESC];    /* CPU virt address of sh'd memory buffs  */
-    void *sh_mem;                  /* CPU mapped virt address of device RAM  */
+	struct depca_rx_desc *rx_ring;	/* Pointer to start of RX descriptor ring */
+	struct depca_tx_desc *tx_ring;	/* Pointer to start of TX descriptor ring */
+	void *rx_buff[NUM_RX_DESC];	/* CPU virt address of sh'd memory buffs  */
+	void *tx_buff[NUM_TX_DESC];	/* CPU virt address of sh'd memory buffs  */
+	void *sh_mem;		/* CPU mapped virt address of device RAM  */
 /* Device address space fields */
-    u_long device_ram_start;       /* Start of RAM in device addr space      */
+	u_long device_ram_start;	/* Start of RAM in device addr space      */
 /* Offsets used in both address spaces */
-    u_long rx_ring_offset;         /* Offset from start of RAM to rx_ring    */
-    u_long tx_ring_offset;         /* Offset from start of RAM to tx_ring    */
-    u_long buffs_offset;	   /* LANCE Rx and Tx buffers start address. */
+	u_long rx_ring_offset;	/* Offset from start of RAM to rx_ring    */
+	u_long tx_ring_offset;	/* Offset from start of RAM to tx_ring    */
+	u_long buffs_offset;	/* LANCE Rx and Tx buffers start address. */
 /* Kernel-only (not device) fields */
-    int	rx_new, tx_new;		   /* The next free ring entry               */
-    int rx_old, tx_old;	           /* The ring entries to be free()ed.       */
-    struct net_device_stats stats;
-    spinlock_t lock;
-    struct {                       /* Private stats counters                 */
-	u32 bins[DEPCA_PKT_STAT_SZ];
-	u32 unicast;
-	u32 multicast;
-	u32 broadcast;
-	u32 excessive_collisions;
-	u32 tx_underruns;
-	u32 excessive_underruns;
-    } pktStats;
-    int txRingMask;                /* TX ring mask                           */
-    int rxRingMask;                /* RX ring mask                           */
-    s32 rx_rlen;                   /* log2(rxRingMask+1) for the descriptors */
-    s32 tx_rlen;                   /* log2(txRingMask+1) for the descriptors */
+	int rx_new, tx_new;	/* The next free ring entry               */
+	int rx_old, tx_old;	/* The ring entries to be free()ed.       */
+	struct net_device_stats stats;
+	spinlock_t lock;
+	struct {		/* Private stats counters                 */
+		u32 bins[DEPCA_PKT_STAT_SZ];
+		u32 unicast;
+		u32 multicast;
+		u32 broadcast;
+		u32 excessive_collisions;
+		u32 tx_underruns;
+		u32 excessive_underruns;
+	} pktStats;
+	int txRingMask;		/* TX ring mask                           */
+	int rxRingMask;		/* RX ring mask                           */
+	s32 rx_rlen;		/* log2(rxRingMask+1) for the descriptors */
+	s32 tx_rlen;		/* log2(txRingMask+1) for the descriptors */
 };
 
 /*
@@ -431,61 +430,61 @@
 /*
 ** Public Functions
 */
-static int    depca_open(struct net_device *dev);
-static int    depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void   depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int    depca_close(struct net_device *dev);
-static int    depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void   depca_tx_timeout (struct net_device *dev);
+static int depca_open(struct net_device *dev);
+static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int depca_close(struct net_device *dev);
+static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void depca_tx_timeout(struct net_device *dev);
 static struct net_device_stats *depca_get_stats(struct net_device *dev);
-static void   set_multicast_list(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
 
 /*
 ** Private functions
 */
-static int    depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot);
-static void   depca_init_ring(struct net_device *dev);
-static int    depca_rx(struct net_device *dev);
-static int    depca_tx(struct net_device *dev);
-
-static void   LoadCSRs(struct net_device *dev);
-static int    InitRestartDepca(struct net_device *dev);
-static void   DepcaSignature(char *name, u_long paddr);
-static int    DevicePresent(u_long ioaddr);
-static int    get_hw_addr(struct net_device *dev);
-static int    EISA_signature(char *name, s32 eisa_id);
-static void   SetMulticastFilter(struct net_device *dev);
-static void   isa_probe(struct net_device *dev, u_long iobase);
-static void   eisa_probe(struct net_device *dev, u_long iobase);
-#ifdef CONFIG_MCA      
-static void   mca_probe(struct net_device *dev, u_long iobase);
+static int depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot);
+static void depca_init_ring(struct net_device *dev);
+static int depca_rx(struct net_device *dev);
+static int depca_tx(struct net_device *dev);
+
+static void LoadCSRs(struct net_device *dev);
+static int InitRestartDepca(struct net_device *dev);
+static void DepcaSignature(char *name, u_long paddr);
+static int DevicePresent(u_long ioaddr);
+static int get_hw_addr(struct net_device *dev);
+static int EISA_signature(char *name, s32 eisa_id);
+static void SetMulticastFilter(struct net_device *dev);
+static void isa_probe(struct net_device *dev, u_long iobase);
+static void eisa_probe(struct net_device *dev, u_long iobase);
+#ifdef CONFIG_MCA
+static void mca_probe(struct net_device *dev, u_long iobase);
 #endif
 static struct net_device *alloc_device(struct net_device *dev, u_long iobase);
-static int    depca_dev_index(char *s);
-static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *));
-static int    load_packet(struct net_device *dev, struct sk_buff *skb);
-static void   depca_dbg_open(struct net_device *dev);
+static int depca_dev_index(char *s);
+static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *));
+static int load_packet(struct net_device *dev, struct sk_buff *skb);
+static void depca_dbg_open(struct net_device *dev);
 
 #ifdef MODULE
-int           init_module(void);
-void          cleanup_module(void);
-static int    autoprobed = 1, loading_module = 1;
+int init_module(void);
+void cleanup_module(void);
+static int autoprobed = 1, loading_module = 1;
 # else
-static u_char de1xx_irq[] __initdata = {2,3,4,5,7,9,0};
-static u_char de2xx_irq[] __initdata = {5,9,10,11,15,0};
-static u_char de422_irq[] __initdata = {5,9,10,11,0};
+static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
+static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
+static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
 static u_char *depca_irq;
-static int    autoprobed, loading_module;
-#endif /* MODULE */
+static int autoprobed, loading_module;
+#endif				/* MODULE */
 
-static char   name[DEPCA_STRLEN];
-static int    num_depcas, num_eth;
-static int    mem;                       /* For loadable module assignment
-                                              use insmod mem=0x????? .... */
-static char   *adapter_name; /* = '\0';     If no PROM when loadable module
-					      use insmod adapter_name=DE??? ...
-					      bss initializes this to zero
-					   */
+static char name[DEPCA_STRLEN];
+static int num_depcas, num_eth;
+static int mem;			/* For loadable module assignment
+				   use insmod mem=0x????? .... */
+static char *adapter_name;	/* = '\0';     If no PROM when loadable module
+				   use insmod adapter_name=DE??? ...
+				   bss initializes this to zero
+				 */
 /*
 ** Miscellaneous defines...
 */
@@ -493,49 +492,48 @@
     outw(CSR0, DEPCA_ADDR);\
     outw(STOP, DEPCA_DATA)
 
-int __init 
-depca_probe(struct net_device *dev)
+int __init depca_probe(struct net_device *dev)
 {
-  int tmp = num_depcas, status = -ENODEV;
-  u_long iobase = dev->base_addr;
+	int tmp = num_depcas, status = -ENODEV;
+	u_long iobase = dev->base_addr;
 
-  SET_MODULE_OWNER(dev);
+	SET_MODULE_OWNER(dev);
 
-  if ((iobase == 0) && loading_module){
-    printk("Autoprobing is not supported when loading a module based driver.\n");
-    status = -EIO;
-  } else {
-#ifdef CONFIG_MCA      
-    mca_probe(dev, iobase);
+	if ((iobase == 0) && loading_module) {
+		printk("Autoprobing is not supported when loading a module based driver.\n");
+		status = -EIO;
+	} else {
+#ifdef CONFIG_MCA
+		mca_probe(dev, iobase);
 #endif
-    isa_probe(dev, iobase);
-    eisa_probe(dev, iobase);
+		isa_probe(dev, iobase);
+		eisa_probe(dev, iobase);
 
-    if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
-      printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, 
-	                                                               iobase);
-    }
-
-    /*
-    ** Walk the device list to check that at least one device
-    ** initialised OK
-    */
-    for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
+		if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
+			printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, iobase);
+		}
 
-    if (dev->priv) status = 0;
-    if (iobase == 0) autoprobed = 1;
-  }
+		/*
+		   ** Walk the device list to check that at least one device
+		   ** initialised OK
+		 */
+		for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
+
+		if (dev->priv)
+			status = 0;
+		if (iobase == 0)
+			autoprobed = 1;
+	}
 
-  return status;
+	return status;
 }
 
-static int __init 
-depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
+static int __init depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
 {
 	struct depca_private *lp;
-	int i, j, offset, netRAM, mem_len, status=0;
+	int i, j, offset, netRAM, mem_len, status = 0;
 	s16 nicsr;
-	u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+	u_long mem_start = 0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
 
 	STOP_DEPCA;
 
@@ -553,19 +551,17 @@
 		DepcaSignature(name, mem_start);
 	} while (!mem && mem_base[mem_chkd] && (adapter == unknown));
 
-	if ((adapter == unknown) || !mem_start) { /* DEPCA device not found */
+	if ((adapter == unknown) || !mem_start) {	/* DEPCA device not found */
 		return -ENXIO;
 	}
 
 	dev->base_addr = ioaddr;
 
 	if (mca_slot != -1) {
-		printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name, 
-		                                          ioaddr, mca_slot);
-	} else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) { /* EISA slot address */
-		printk("%s: %s at 0x%04lx (EISA slot %d)", 
-		       dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
-	} else {                             /* ISA port address */
+		printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name, ioaddr, mca_slot);
+	} else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) {	/* EISA slot address */
+		printk("%s: %s at 0x%04lx (EISA slot %d)", dev->name, name, ioaddr, (int) ((ioaddr >> 12) & 0x0f));
+	} else {		/* ISA port address */
 		printk("%s: %s at 0x%04lx", dev->name, name, ioaddr);
 	}
 
@@ -575,7 +571,7 @@
 		printk("      which has an Ethernet PROM CRC error.\n");
 		return -ENXIO;
 	}
-	for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
+	for (i = 0; i < ETH_ALEN - 1; i++) {	/* get the ethernet address */
 		printk("%2.2x:", dev->dev_addr[i]);
 	}
 	printk("%2.2x", dev->dev_addr[i]);
@@ -586,19 +582,16 @@
 		netRAM = 128;
 	offset = 0x0000;
 
-	/* Shared Memory Base Address */ 
+	/* Shared Memory Base Address */
 	if (nicsr & BUF) {
-		offset = 0x8000;        /* 32kbyte RAM offset*/
-		nicsr &= ~BS;           /* DEPCA RAM in top 32k */
+		offset = 0x8000;	/* 32kbyte RAM offset */
+		nicsr &= ~BS;	/* DEPCA RAM in top 32k */
 		netRAM -= 32;
 	}
-	mem_start += offset;            /* (E)ISA start address */
-	if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) +
-			NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) +
-			sizeof(struct depca_init)))
-	    > (netRAM<<10)) {
-		printk(",\n       requests %dkB RAM: only %dkB is available!\n",
-		        (mem_len >> 10), netRAM);
+	mem_start += offset;	/* (E)ISA start address */
+	if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
+	    > (netRAM << 10)) {
+		printk(",\n       requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
 		return -ENXIO;
 	}
 
@@ -609,21 +602,20 @@
 		nicsr |= SHE;
 		outb(nicsr, DEPCA_NICSR);
 	}
- 
+
 	/* Define the device private memory */
 	dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
 	if (dev->priv == NULL)
 		return -ENOMEM;
-	lp = (struct depca_private *)dev->priv;
-	memset((char *)dev->priv, 0, sizeof(struct depca_private));
+	lp = (struct depca_private *) dev->priv;
+	memset((char *) dev->priv, 0, sizeof(struct depca_private));
 	lp->adapter = adapter;
 	lp->mca_slot = mca_slot;
 	lp->lock = SPIN_LOCK_UNLOCKED;
- 	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+	sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
 	status = -EBUSY;
 	if (!request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name)) {
-		printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n",
-		       DEPCA_TOTAL_SIZE, ioaddr);
+		printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n", DEPCA_TOTAL_SIZE, ioaddr);
 		goto out_priv;
 	}
 
@@ -635,17 +627,17 @@
 		goto out_region;
 	}
 	lp->device_ram_start = mem_start & LA_MASK;
-	
+
 	offset = 0;
 	offset += sizeof(struct depca_init);
 
 	/* Tx & Rx descriptors (aligned to a quadword boundary) */
-	offset = (offset + ALIGN) & ~ALIGN;
-	lp->rx_ring = (struct depca_rx_desc *)(lp->sh_mem + offset);
+	offset = (offset + DEPCA_ALIGN) & ~DEPCA_ALIGN;
+	lp->rx_ring = (struct depca_rx_desc *) (lp->sh_mem + offset);
 	lp->rx_ring_offset = offset;
 
 	offset += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
-	lp->tx_ring = (struct depca_tx_desc *)(lp->sh_mem + offset);
+	lp->tx_ring = (struct depca_tx_desc *) (lp->sh_mem + offset);
 	lp->tx_ring_offset = offset;
 
 	offset += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
@@ -657,14 +649,14 @@
 	lp->txRingMask = NUM_TX_DESC - 1;
 
 	/* Calculate Tx/Rx RLEN size for the descriptors. */
-	for (i=0, j = lp->rxRingMask; j>0; i++) {
+	for (i = 0, j = lp->rxRingMask; j > 0; i++) {
 		j >>= 1;
 	}
-	lp->rx_rlen = (s32)(i << 29);
-	for (i=0, j = lp->txRingMask; j>0; i++) {
+	lp->rx_rlen = (s32) (i << 29);
+	for (i = 0, j = lp->txRingMask; j > 0; i++) {
 		j >>= 1;
 	}
-	lp->tx_rlen = (s32)(i << 29);
+	lp->tx_rlen = (s32) (i << 29);
 
 	/* Load the initialisation block */
 	depca_init_ring(dev);
@@ -673,7 +665,7 @@
 	LoadCSRs(dev);
 
 	/* Enable DEPCA board interrupts for autoprobing */
-	nicsr = ((nicsr & ~IM)|IEN);
+	nicsr = ((nicsr & ~IM) | IEN);
 	outb(nicsr, DEPCA_NICSR);
 
 	/* To auto-IRQ we enable the initialization-done and DMA err,
@@ -706,9 +698,10 @@
 
 		/* Trigger an initialization just for the interrupt. */
 		outw(INEA | INIT, DEPCA_DATA);
-	  
+
 		delay = jiffies + HZ/50;
-		while (time_before(jiffies, delay)) ;
+		while (time_before(jiffies, delay))
+			yield();
 		irqnum = probe_irq_off(irq_mask);
 
 		status = -ENXIO;
@@ -716,19 +709,19 @@
 			printk(" and failed to detect IRQ line.\n");
 			goto out_region;
 		} else {
-			for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++)
+			for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++)
 				if (irqnum == depca_irq[i]) {
 					dev->irq = irqnum;
 					printk(" and uses IRQ%d.\n", dev->irq);
 				}
-	      
+
 			status = -ENXIO;
 			if (!dev->irq) {
 				printk(" but incorrect IRQ line detected.\n");
 				goto out_region;
 			}
 		}
-#endif /* MODULE */
+#endif				/* MODULE */
 	} else {
 		printk(" and assigned IRQ%d.\n", dev->irq);
 	}
@@ -752,65 +745,63 @@
 	/* Fill in the generic field of the device structure. */
 	ether_setup(dev);
 	return 0;
-out_region:
+      out_region:
 	release_region(ioaddr, DEPCA_TOTAL_SIZE);
-out_priv:
+      out_priv:
 	kfree(dev->priv);
 	dev->priv = NULL;
 	return status;
 }
-
 
-static int
-depca_open(struct net_device *dev)
+
+static int depca_open(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  s16 nicsr;
-  int status = 0;
-
-  STOP_DEPCA;
-  nicsr = inb(DEPCA_NICSR);
-
-  /* Make sure the shadow RAM is enabled */
-  if (lp->adapter != DEPCA) {
-    nicsr |= SHE;
-    outb(nicsr, DEPCA_NICSR);
-  }
-
-  /* Re-initialize the DEPCA... */
-  depca_init_ring(dev);
-  LoadCSRs(dev);
-
-  depca_dbg_open(dev);
-
-  if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) {
-    printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
-    status = -EAGAIN;
-  } else {
-
-    /* Enable DEPCA board interrupts and turn off LED */
-    nicsr = ((nicsr & ~IM & ~LED)|IEN);
-    outb(nicsr, DEPCA_NICSR);
-    outw(CSR0,DEPCA_ADDR);
-    
-    netif_start_queue(dev);
-    
-    status = InitRestartDepca(dev);
-
-    if (depca_debug > 1){
-      printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
-      printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR));
-    }
-  }
-  return status;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+	s16 nicsr;
+	int status = 0;
+
+	STOP_DEPCA;
+	nicsr = inb(DEPCA_NICSR);
+
+	/* Make sure the shadow RAM is enabled */
+	if (lp->adapter != DEPCA) {
+		nicsr |= SHE;
+		outb(nicsr, DEPCA_NICSR);
+	}
+
+	/* Re-initialize the DEPCA... */
+	depca_init_ring(dev);
+	LoadCSRs(dev);
+
+	depca_dbg_open(dev);
+
+	if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) {
+		printk("depca_open(): Requested IRQ%d is busy\n", dev->irq);
+		status = -EAGAIN;
+	} else {
+
+		/* Enable DEPCA board interrupts and turn off LED */
+		nicsr = ((nicsr & ~IM & ~LED) | IEN);
+		outb(nicsr, DEPCA_NICSR);
+		outw(CSR0, DEPCA_ADDR);
+
+		netif_start_queue(dev);
+
+		status = InitRestartDepca(dev);
+
+		if (depca_debug > 1) {
+			printk("CSR0: 0x%4.4x\n", inw(DEPCA_DATA));
+			printk("nicsr: 0x%02x\n", inb(DEPCA_NICSR));
+		}
+	}
+	return status;
 }
 
 /* Initialize the lance Rx and Tx descriptor rings. */
-static void
-depca_init_ring(struct net_device *dev)
+static void depca_init_ring(struct net_device *dev)
 {
-	struct depca_private *lp = (struct depca_private *)dev->priv;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
 	u_int i;
 	u_long offset;
 
@@ -822,17 +813,15 @@
 
 	/* Initialize the base address and length of each buffer in the ring */
 	for (i = 0; i <= lp->rxRingMask; i++) {
-		offset = lp->buffs_offset + i*RX_BUFF_SZ;
-		writel((lp->device_ram_start + offset) | R_OWN,
-		       &lp->rx_ring[i].base);
+		offset = lp->buffs_offset + i * RX_BUFF_SZ;
+		writel((lp->device_ram_start + offset) | R_OWN, &lp->rx_ring[i].base);
 		writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
 		lp->rx_buff[i] = lp->sh_mem + offset;
 	}
 
 	for (i = 0; i <= lp->txRingMask; i++) {
-		offset = lp->buffs_offset + (i + lp->rxRingMask+1)*TX_BUFF_SZ;
-		writel((lp->device_ram_start + offset) & 0x00ffffff,
-	               &lp->tx_ring[i].base);
+		offset = lp->buffs_offset + (i + lp->rxRingMask + 1) * TX_BUFF_SZ;
+		writel((lp->device_ram_start + offset) & 0x00ffffff, &lp->tx_ring[i].base);
 		lp->tx_buff[i] = lp->sh_mem + offset;
 	}
 
@@ -846,30 +835,29 @@
 		lp->init_block.phys_addr[i] = dev->dev_addr[i];
 	}
 
-	lp->init_block.mode = 0x0000;            /* Enable the Tx and Rx */
+	lp->init_block.mode = 0x0000;	/* Enable the Tx and Rx */
 }
 
 
-static void depca_tx_timeout (struct net_device *dev)
+static void depca_tx_timeout(struct net_device *dev)
 {
 	u_long ioaddr = dev->base_addr;
 
-	printk ("%s: transmit timed out, status %04x, resetting.\n",
-		dev->name, inw (DEPCA_DATA));
+	printk("%s: transmit timed out, status %04x, resetting.\n", dev->name, inw(DEPCA_DATA));
 
 	STOP_DEPCA;
-	depca_init_ring (dev);
-	LoadCSRs (dev);
+	depca_init_ring(dev);
+	LoadCSRs(dev);
 	dev->trans_start = jiffies;
-	netif_wake_queue (dev);
-	InitRestartDepca (dev);
+	netif_wake_queue(dev);
+	InitRestartDepca(dev);
 }
 
 
 /* 
 ** Writes a socket buffer to TX descriptor ring and starts transmission 
 */
-static int depca_start_xmit (struct sk_buff *skb, struct net_device *dev)
+static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct depca_private *lp = (struct depca_private *) dev->priv;
 	u_long ioaddr = dev->base_addr;
@@ -879,32 +867,32 @@
 	if (skb->len < 1)
 		goto out;
 
-	netif_stop_queue (dev);
+	netif_stop_queue(dev);
 
 	if (TX_BUFFS_AVAIL) {	/* Fill in a Tx ring entry */
-		status = load_packet (dev, skb);
+		status = load_packet(dev, skb);
 
 		if (!status) {
 			/* Trigger an immediate send demand. */
-			outw (CSR0, DEPCA_ADDR);
-			outw (INEA | TDMD, DEPCA_DATA);
+			outw(CSR0, DEPCA_ADDR);
+			outw(INEA | TDMD, DEPCA_DATA);
 
 			dev->trans_start = jiffies;
-			dev_kfree_skb (skb);
+			dev_kfree_skb(skb);
 		}
 		if (TX_BUFFS_AVAIL)
-			netif_start_queue (dev);
+			netif_start_queue(dev);
 	} else
 		status = -1;
 
-out:
+      out:
 	return status;
 }
 
 /*
 ** The DEPCA interrupt handler. 
 */
-static void depca_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
 	struct depca_private *lp;
@@ -912,308 +900,301 @@
 	u_long ioaddr;
 
 	if (dev == NULL) {
-		printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+		printk("depca_interrupt(): irq %d for unknown device.\n", irq);
 		return;
 	}
 
 	lp = (struct depca_private *) dev->priv;
 	ioaddr = dev->base_addr;
 
-	spin_lock (&lp->lock);
+	spin_lock(&lp->lock);
 
 	/* mask the DEPCA board interrupts and turn on the LED */
-	nicsr = inb (DEPCA_NICSR);
+	nicsr = inb(DEPCA_NICSR);
 	nicsr |= (IM | LED);
-	outb (nicsr, DEPCA_NICSR);
+	outb(nicsr, DEPCA_NICSR);
 
-	outw (CSR0, DEPCA_ADDR);
-	csr0 = inw (DEPCA_DATA);
+	outw(CSR0, DEPCA_ADDR);
+	csr0 = inw(DEPCA_DATA);
 
 	/* Acknowledge all of the current interrupt sources ASAP. */
-	outw (csr0 & INTE, DEPCA_DATA);
+	outw(csr0 & INTE, DEPCA_DATA);
 
 	if (csr0 & RINT)	/* Rx interrupt (packet arrived) */
-		depca_rx (dev);
+		depca_rx(dev);
 
 	if (csr0 & TINT)	/* Tx interrupt (packet sent) */
-		depca_tx (dev);
+		depca_tx(dev);
 
 	/* Any resources available? */
 	if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
-		netif_wake_queue (dev);
+		netif_wake_queue(dev);
 	}
 
 	/* Unmask the DEPCA board interrupts and turn off the LED */
 	nicsr = (nicsr & ~IM & ~LED);
-	outb (nicsr, DEPCA_NICSR);
+	outb(nicsr, DEPCA_NICSR);
 
-	spin_unlock (&lp->lock);
+	spin_unlock(&lp->lock);
 }
 
 
-static int
-depca_rx(struct net_device *dev)
+static int depca_rx(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  int i, entry;
-  s32 status;
-
-  for (entry=lp->rx_new; 
-       !(readl(&lp->rx_ring[entry].base) & R_OWN);
-       entry=lp->rx_new){
-    status = readl(&lp->rx_ring[entry].base) >> 16 ;
-    if (status & R_STP) {                      /* Remember start of frame */
-      lp->rx_old = entry;
-    }
-    if (status & R_ENP) {                      /* Valid frame status */
-      if (status & R_ERR) {	               /* There was an error. */
-	lp->stats.rx_errors++;                 /* Update the error stats. */
-	if (status & R_FRAM) lp->stats.rx_frame_errors++;
-	if (status & R_OFLO) lp->stats.rx_over_errors++;
-	if (status & R_CRC)  lp->stats.rx_crc_errors++;
-	if (status & R_BUFF) lp->stats.rx_fifo_errors++;
-      } else {	
-	short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
-	struct sk_buff *skb;
-
-	skb = dev_alloc_skb(pkt_len+2);
-	if (skb != NULL) {
-	  unsigned char *buf;
-	  skb_reserve(skb,2);               /* 16 byte align the IP header */
-	  buf = skb_put(skb,pkt_len);
-	  skb->dev = dev;
-	  if (entry < lp->rx_old) {         /* Wrapped buffer */
-	    len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
-	    memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
-	    memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len-len);
-	  } else {                          /* Linear buffer */
-	    memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
-	  }
-
-	  /* 
-	  ** Notify the upper protocol layers that there is another 
-	  ** packet to handle
-	  */
-	  skb->protocol=eth_type_trans(skb,dev);
-	  netif_rx(skb);
-
-	  /*
-	  ** Update stats
-	  */
-	  dev->last_rx = jiffies;
-	  lp->stats.rx_packets++;
-	  lp->stats.rx_bytes += pkt_len;
-	  for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) {
-	    if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) {
-	      lp->pktStats.bins[i]++;
-	      i = DEPCA_PKT_STAT_SZ;
-	    }
-	  }
-	  if (buf[0] & 0x01) {              /* Multicast/Broadcast */
-	    if ((*(s16 *)&buf[0] == -1) &&
-		(*(s16 *)&buf[2] == -1) &&
-		(*(s16 *)&buf[4] == -1)) {
-	      lp->pktStats.broadcast++;
-	    } else {
-	      lp->pktStats.multicast++;
-	    }
-	  } else if ((*(s16 *)&buf[0] == *(s16 *)&dev->dev_addr[0]) &&
-		     (*(s16 *)&buf[2] == *(s16 *)&dev->dev_addr[2]) &&
-		     (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
-	    lp->pktStats.unicast++;
-	  }
-	  
-	  lp->pktStats.bins[0]++;           /* Duplicates stats.rx_packets */
-	  if (lp->pktStats.bins[0] == 0) {  /* Reset counters */
-	    memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
-	  }
-	} else {
-	  printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-	  lp->stats.rx_dropped++;	/* Really, deferred. */
-	  break;
-	}
-      }
-      /* Change buffer ownership for this last frame, back to the adapter */
-      for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) {
-	writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, 
-	                                        &lp->rx_ring[lp->rx_old].base);
-      }
-      writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
-    }
-
-    /*
-    ** Update entry information
-    */
-    lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
-    }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	int i, entry;
+	s32 status;
 
-    return 0;
+	for (entry = lp->rx_new; !(readl(&lp->rx_ring[entry].base) & R_OWN); entry = lp->rx_new) {
+		status = readl(&lp->rx_ring[entry].base) >> 16;
+		if (status & R_STP) {	/* Remember start of frame */
+			lp->rx_old = entry;
+		}
+		if (status & R_ENP) {	/* Valid frame status */
+			if (status & R_ERR) {	/* There was an error. */
+				lp->stats.rx_errors++;	/* Update the error stats. */
+				if (status & R_FRAM)
+					lp->stats.rx_frame_errors++;
+				if (status & R_OFLO)
+					lp->stats.rx_over_errors++;
+				if (status & R_CRC)
+					lp->stats.rx_crc_errors++;
+				if (status & R_BUFF)
+					lp->stats.rx_fifo_errors++;
+			} else {
+				short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
+				struct sk_buff *skb;
+
+				skb = dev_alloc_skb(pkt_len + 2);
+				if (skb != NULL) {
+					unsigned char *buf;
+					skb_reserve(skb, 2);	/* 16 byte align the IP header */
+					buf = skb_put(skb, pkt_len);
+					skb->dev = dev;
+					if (entry < lp->rx_old) {	/* Wrapped buffer */
+						len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
+						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
+						memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len - len);
+					} else {	/* Linear buffer */
+						memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
+					}
+
+					/* 
+					   ** Notify the upper protocol layers that there is another 
+					   ** packet to handle
+					 */
+					skb->protocol = eth_type_trans(skb, dev);
+					netif_rx(skb);
+
+					/*
+					   ** Update stats
+					 */
+					dev->last_rx = jiffies;
+					lp->stats.rx_packets++;
+					lp->stats.rx_bytes += pkt_len;
+					for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
+						if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
+							lp->pktStats.bins[i]++;
+							i = DEPCA_PKT_STAT_SZ;
+						}
+					}
+					if (buf[0] & 0x01) {	/* Multicast/Broadcast */
+						if ((*(s16 *) & buf[0] == -1) && (*(s16 *) & buf[2] == -1) && (*(s16 *) & buf[4] == -1)) {
+							lp->pktStats.broadcast++;
+						} else {
+							lp->pktStats.multicast++;
+						}
+					} else if ((*(s16 *) & buf[0] == *(s16 *) & dev->dev_addr[0]) && (*(s16 *) & buf[2] == *(s16 *) & dev->dev_addr[2]) && (*(s16 *) & buf[4] == *(s16 *) & dev->dev_addr[4])) {
+						lp->pktStats.unicast++;
+					}
+
+					lp->pktStats.bins[0]++;	/* Duplicates stats.rx_packets */
+					if (lp->pktStats.bins[0] == 0) {	/* Reset counters */
+						memset((char *) &lp->pktStats, 0, sizeof(lp->pktStats));
+					}
+				} else {
+					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+					lp->stats.rx_dropped++;	/* Really, deferred. */
+					break;
+				}
+			}
+			/* Change buffer ownership for this last frame, back to the adapter */
+			for (; lp->rx_old != entry; lp->rx_old = (++lp->rx_old) & lp->rxRingMask) {
+				writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN, &lp->rx_ring[lp->rx_old].base);
+			}
+			writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
+		}
+
+		/*
+		   ** Update entry information
+		 */
+		lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
+	}
+
+	return 0;
 }
 
 /*
 ** Buffer sent - check for buffer errors.
 */
-static int
-depca_tx(struct net_device *dev)
+static int depca_tx(struct net_device *dev)
+{
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	int entry;
+	s32 status;
+	u_long ioaddr = dev->base_addr;
+
+	for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
+		status = readl(&lp->tx_ring[entry].base) >> 16;
+
+		if (status < 0) {	/* Packet not yet sent! */
+			break;
+		} else if (status & T_ERR) {	/* An error occurred. */
+			status = readl(&lp->tx_ring[entry].misc);
+			lp->stats.tx_errors++;
+			if (status & TMD3_RTRY)
+				lp->stats.tx_aborted_errors++;
+			if (status & TMD3_LCAR)
+				lp->stats.tx_carrier_errors++;
+			if (status & TMD3_LCOL)
+				lp->stats.tx_window_errors++;
+			if (status & TMD3_UFLO)
+				lp->stats.tx_fifo_errors++;
+			if (status & (TMD3_BUFF | TMD3_UFLO)) {
+				/* Trigger an immediate send demand. */
+				outw(CSR0, DEPCA_ADDR);
+				outw(INEA | TDMD, DEPCA_DATA);
+			}
+		} else if (status & (T_MORE | T_ONE)) {
+			lp->stats.collisions++;
+		} else {
+			lp->stats.tx_packets++;
+		}
+
+		/* Update all the pointers */
+		lp->tx_old = (++lp->tx_old) & lp->txRingMask;
+	}
+
+	return 0;
+}
+
+static int depca_close(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  int entry;
-  s32 status;
-  u_long ioaddr = dev->base_addr;
-
-  for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
-    status = readl(&lp->tx_ring[entry].base) >> 16 ;
-
-    if (status < 0) {                          /* Packet not yet sent! */
-      break;
-    } else if (status & T_ERR) {               /* An error occurred. */
-      status = readl(&lp->tx_ring[entry].misc);
-      lp->stats.tx_errors++;
-      if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
-      if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
-      if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
-      if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
-      if (status & (TMD3_BUFF | TMD3_UFLO)) {
-	/* Trigger an immediate send demand. */
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	s16 nicsr;
+	u_long ioaddr = dev->base_addr;
+
+	netif_stop_queue(dev);
+
 	outw(CSR0, DEPCA_ADDR);
-	outw(INEA | TDMD, DEPCA_DATA);
-      }
-    } else if (status & (T_MORE | T_ONE)) {
-      lp->stats.collisions++;
-    } else {
-      lp->stats.tx_packets++;
-    }
-
-    /* Update all the pointers */
-    lp->tx_old = (++lp->tx_old) & lp->txRingMask;
-  }
-
-  return 0;
-}
-
-static int
-depca_close(struct net_device *dev)
-{
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  s16 nicsr;
-  u_long ioaddr = dev->base_addr;
-
-  netif_stop_queue(dev);
-
-  outw(CSR0, DEPCA_ADDR);
-
-  if (depca_debug > 1) {
-    printk("%s: Shutting down ethercard, status was %2.2x.\n",
-	   dev->name, inw(DEPCA_DATA));
-  }
-
-  /* 
-  ** We stop the DEPCA here -- it occasionally polls
-  ** memory if we don't. 
-  */
-  outw(STOP, DEPCA_DATA);
-
-  /*
-  ** Give back the ROM in case the user wants to go to DOS
-  */
-  if (lp->adapter != DEPCA) {
-    nicsr = inb(DEPCA_NICSR);
-    nicsr &= ~SHE;
-    outb(nicsr, DEPCA_NICSR);
-  }
-
-  /*
-  ** Free the associated irq
-  */
-  free_irq(dev->irq, dev);
-  return 0;
+
+	if (depca_debug > 1) {
+		printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
+	}
+
+	/* 
+	   ** We stop the DEPCA here -- it occasionally polls
+	   ** memory if we don't. 
+	 */
+	outw(STOP, DEPCA_DATA);
+
+	/*
+	   ** Give back the ROM in case the user wants to go to DOS
+	 */
+	if (lp->adapter != DEPCA) {
+		nicsr = inb(DEPCA_NICSR);
+		nicsr &= ~SHE;
+		outb(nicsr, DEPCA_NICSR);
+	}
+
+	/*
+	   ** Free the associated irq
+	 */
+	free_irq(dev->irq, dev);
+	return 0;
 }
 
 static void LoadCSRs(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
 
-  outw(CSR1, DEPCA_ADDR);                /* initialisation block address LSW */
-  outw((u16)lp->device_ram_start, DEPCA_DATA);
-  outw(CSR2, DEPCA_ADDR);                /* initialisation block address MSW */
-  outw((u16)(lp->device_ram_start >> 16), DEPCA_DATA);
-  outw(CSR3, DEPCA_ADDR);                /* ALE control */
-  outw(ACON, DEPCA_DATA);
+	outw(CSR1, DEPCA_ADDR);	/* initialisation block address LSW */
+	outw((u16) lp->device_ram_start, DEPCA_DATA);
+	outw(CSR2, DEPCA_ADDR);	/* initialisation block address MSW */
+	outw((u16) (lp->device_ram_start >> 16), DEPCA_DATA);
+	outw(CSR3, DEPCA_ADDR);	/* ALE control */
+	outw(ACON, DEPCA_DATA);
 
-  outw(CSR0, DEPCA_ADDR);                /* Point back to CSR0 */
+	outw(CSR0, DEPCA_ADDR);	/* Point back to CSR0 */
 
-  return;
+	return;
 }
 
 static int InitRestartDepca(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  int i, status=0;
-
-  /* Copy the shadow init_block to shared memory */
-  memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+	int i, status = 0;
 
-  outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
-  outw(INIT, DEPCA_DATA);                /* initialize DEPCA */
+	/* Copy the shadow init_block to shared memory */
+	memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
 
-  /* wait for lance to complete initialisation */
-  for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); 
+	outw(CSR0, DEPCA_ADDR);	/* point back to CSR0 */
+	outw(INIT, DEPCA_DATA);	/* initialize DEPCA */
 
-  if (i!=100) {
-    /* clear IDON by writing a "1", enable interrupts and start lance */
-    outw(IDON | INEA | STRT, DEPCA_DATA);
-    if (depca_debug > 2) {
-      printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
-	     dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
-    }
-  } else {
-    printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
-	     dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
-    status = -1;
-  }
+	/* wait for lance to complete initialisation */
+	for (i = 0; (i < 100) && !(inw(DEPCA_DATA) & IDON); i++);
+
+	if (i != 100) {
+		/* clear IDON by writing a "1", enable interrupts and start lance */
+		outw(IDON | INEA | STRT, DEPCA_DATA);
+		if (depca_debug > 2) {
+			printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
+		}
+	} else {
+		printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n", dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
+		status = -1;
+	}
 
-  return status;
+	return status;
 }
 
-static struct net_device_stats *
-depca_get_stats(struct net_device *dev)
+static struct net_device_stats *depca_get_stats(struct net_device *dev)
 {
-    struct depca_private *lp = (struct depca_private *)dev->priv;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
 
-    /* Null body since there is no framing error counter */
+	/* Null body since there is no framing error counter */
 
-    return &lp->stats;
+	return &lp->stats;
 }
 
 /*
 ** Set or clear the multicast filter for this adaptor.
 */
-static void
-set_multicast_list(struct net_device *dev)
+static void set_multicast_list(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  
-  if (dev) {
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);  /* Wait for the ring to empty */
-
-    STOP_DEPCA;                       /* Temporarily stop the depca.  */
-    depca_init_ring(dev);             /* Initialize the descriptor rings */
-
-    if (dev->flags & IFF_PROMISC) {   /* Set promiscuous mode */
-      lp->init_block.mode |= PROM;
-    } else {
-      SetMulticastFilter(dev);
-      lp->init_block.mode &= ~PROM;   /* Unset promiscuous mode */
-    }
-
-    LoadCSRs(dev);                    /* Reload CSR3 */
-    InitRestartDepca(dev);            /* Resume normal operation. */
-    netif_start_queue(dev);           /* Unlock the TX ring */
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+
+	if (dev) {
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new);	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+
+		if (dev->flags & IFF_PROMISC) {	/* Set promiscuous mode */
+			lp->init_block.mode |= PROM;
+		} else {
+			SetMulticastFilter(dev);
+			lp->init_block.mode &= ~PROM;	/* Unset promiscuous mode */
+		}
+
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+	}
 }
 
 /*
@@ -1224,274 +1205,277 @@
 */
 static void SetMulticastFilter(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  struct dev_mc_list *dmi=dev->mc_list;
-  char *addrs;
-  int i, j, bit, byte;
-  u16 hashcode;
-  u32 crc;
-
-  if (dev->flags & IFF_ALLMULTI) {         /* Set all multicast bits */
-    for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
-      lp->init_block.mcast_table[i] = (char)0xff;
-    }
-  } else {
-    for (i=0; i<(HASH_TABLE_LEN>>3); i++){ /* Clear the multicast table */
-      lp->init_block.mcast_table[i]=0;
-    }
-                                           /* Add multicast addresses */
-    for (i=0;i<dev->mc_count;i++) {        /* for each address in the list */
-      addrs=dmi->dmi_addr;
-      dmi=dmi->next;
-      if ((*addrs & 0x01) == 1) {          /* multicast address? */ 
-        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);
-	}                                      
-	
-	
-	byte = hashcode >> 3;              /* bit[3-5] -> byte in filter */
-	bit = 1 << (hashcode & 0x07);      /* bit[0-2] -> bit in byte */
-	lp->init_block.mcast_table[byte] |= bit;
-      }
-    }
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct dev_mc_list *dmi = dev->mc_list;
+	char *addrs;
+	int i, j, bit, byte;
+	u16 hashcode;
+	u32 crc;
+
+	if (dev->flags & IFF_ALLMULTI) {	/* Set all multicast bits */
+		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
+			lp->init_block.mcast_table[i] = (char) 0xff;
+		}
+	} else {
+		for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {	/* Clear the multicast table */
+			lp->init_block.mcast_table[i] = 0;
+		}
+		/* Add multicast addresses */
+		for (i = 0; i < dev->mc_count; i++) {	/* for each address in the list */
+			addrs = dmi->dmi_addr;
+			dmi = dmi->next;
+			if ((*addrs & 0x01) == 1) {	/* multicast address? */
+				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);
+				}
+
 
-  return;
+				byte = hashcode >> 3;	/* bit[3-5] -> byte in filter */
+				bit = 1 << (hashcode & 0x07);	/* bit[0-2] -> bit in byte */
+				lp->init_block.mcast_table[byte] |= bit;
+			}
+		}
+	}
+
+	return;
 }
 
 #ifdef CONFIG_MCA
 /*
 ** Microchannel bus I/O device probe
 */
-static void __init 
-mca_probe(struct net_device *dev, u_long ioaddr)
+static void __init mca_probe(struct net_device *dev, u_long ioaddr)
 {
-    unsigned char pos[2];
-    unsigned char where;
-    unsigned long iobase;
-    int irq;
-    int slot = 0;
-
-    /*
-    ** See if we've been here before.
-    */
-    if ((!ioaddr && autoprobed) || (ioaddr && !loading_module)) return;   
+	unsigned char pos[2];
+	unsigned char where;
+	unsigned long iobase;
+	int irq;
+	int slot = 0;
 
-    if (MCA_bus) {
 	/*
-	** Search for the adapter.  If an address has been given, search 
-	** specifically for the card at that address.  Otherwise find the
-	** first card in the system.
-	*/
-	while ((dev!=NULL) && 
-	       ((slot=mca_find_adapter(DE212_ID, slot)) != MCA_NOTFOUND)) {
-	    pos[0] = mca_read_stored_pos(slot, 2);
-	    pos[1] = mca_read_stored_pos(slot, 3);
-
-	    /*
-	    ** IO of card is handled by bits 1 and 2 of pos0.    
-	    **
-	    **    bit2 bit1    IO
-	    **       0    0    0x2c00
-	    **       0    1    0x2c10
-	    **       1    0    0x2c20
-	    **       1    1    0x2c30
-	    */
-	    where = (pos[0] & 6) >> 1;
-	    iobase = 0x2c00 + (0x10 * where);
-	       
-	    if ((ioaddr) && (ioaddr != iobase)) {
-		/*
-		** Card was found, but not at the right IO location. Continue 
-		** scanning from the next MCA slot up for another card.
-		*/
-		slot++;
-		continue;
-	    }
-
-	    /*
-	    ** Found the adapter we were looking for. Now start setting it up.
-	    ** 
-	    ** First work on decoding the IRQ.  It's stored in the lower 4 bits
-	    ** of pos1.  Bits are as follows (from the ADF file):
-	    **
-	    **      Bits           
-	    **   3   2   1   0    IRQ 
-	    **   --------------------
-	    **   0   0   1   0     5
-	    **   0   0   0   1     9
-	    **   0   1   0   0    10
-	    **   1   0   0   0    11
-	    **/
-	    where = pos[1] & 0x0f;
-	    switch(where) {       
-	    case 1:
-		irq = 9;
-		break;
-	    case 2:
-		irq = 5;
-		break;
-	    case 4:
-		irq = 10;
-		break;
-	    case 8:
-		irq = 11;
-		break;
-	    default:
-		printk("%s: mca_probe IRQ error.  You should never get here (%d).\n", dev->name, where);
+	   ** See if we've been here before.
+	 */
+	if ((!ioaddr && autoprobed) || (ioaddr && !loading_module))
 		return;
-	    }  
- 
-	    /*
-	    ** Shared memory address of adapter is stored in bits 3-5 of pos0.
-	    ** They are mapped as follows:
-	    **
-	    **    Bit
-	    **   5  4  3       Memory Addresses
-	    **   0  0  0       C0000-CFFFF (64K)
-	    **   1  0  0       C8000-CFFFF (32K)
-	    **   0  0  1       D0000-DFFFF (64K)
-	    **   1  0  1       D8000-DFFFF (32K)
-	    **   0  1  0       E0000-EFFFF (64K)
-	    **   1  1  0       E8000-EFFFF (32K)
-	    */ 
-	    where = (pos[0] & 0x18) >> 3; 
-	    mem = 0xc0000 + (where * 0x10000);
-	    if (pos[0] & 0x20) {
-		mem += 0x8000;
-	    }
-       
-	    /*
-	    ** Get everything allocated and initialized...  (almost just
-	    ** like the ISA and EISA probes)
-	    */
-	    if (DevicePresent(iobase) != 0) {
+
+	if (MCA_bus) {
 		/*
-		** If the MCA configuration says the card should be here,
-		** it really should be here.
-		*/
-		printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not
-responding.\n", dev->name, iobase);
-	    }
-       
-	    if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
-		if ((dev = alloc_device(dev, iobase)) != NULL) {
-		    dev->irq = irq;
-		    if (depca_hw_init(dev, iobase, slot) == 0) {       
+		   ** Search for the adapter.  If an address has been given, search 
+		   ** specifically for the card at that address.  Otherwise find the
+		   ** first card in the system.
+		 */
+		while ((dev != NULL) && ((slot = mca_find_adapter(DE212_ID, slot)) != MCA_NOTFOUND)) {
+			pos[0] = mca_read_stored_pos(slot, 2);
+			pos[1] = mca_read_stored_pos(slot, 3);
+
+			/*
+			   ** IO of card is handled by bits 1 and 2 of pos0.    
+			   **
+			   **    bit2 bit1    IO
+			   **       0    0    0x2c00
+			   **       0    1    0x2c10
+			   **       1    0    0x2c20
+			   **       1    1    0x2c30
+			 */
+			where = (pos[0] & 6) >> 1;
+			iobase = 0x2c00 + (0x10 * where);
+
+			if ((ioaddr) && (ioaddr != iobase)) {
+				/*
+				   ** Card was found, but not at the right IO location. Continue 
+				   ** scanning from the next MCA slot up for another card.
+				 */
+				slot++;
+				continue;
+			}
+
 			/*
-			** Adapter initialized correctly:  Name it in
-			** /proc/mca.
-			*/
-			mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
-			mca_mark_as_used(slot);
-			num_depcas++;
-		    }
-		    num_eth++;
-		}
-	    } else if (autoprobed) {
-		printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
-	    }
-       
-	    /*
-	    ** If this is a probe by a module, return after setting up the
-	    ** given card.
-	    */
-	    if (ioaddr) return;
-       
-	    /*
-	    ** Set up to check the next slot and loop.
-	    */
-	    slot++;
+			   ** Found the adapter we were looking for. Now start setting it up.
+			   ** 
+			   ** First work on decoding the IRQ.  It's stored in the lower 4 bits
+			   ** of pos1.  Bits are as follows (from the ADF file):
+			   **
+			   **      Bits           
+			   **   3   2   1   0    IRQ 
+			   **   --------------------
+			   **   0   0   1   0     5
+			   **   0   0   0   1     9
+			   **   0   1   0   0    10
+			   **   1   0   0   0    11
+			   * */
+			where = pos[1] & 0x0f;
+			switch (where) {
+			case 1:
+				irq = 9;
+				break;
+			case 2:
+				irq = 5;
+				break;
+			case 4:
+				irq = 10;
+				break;
+			case 8:
+				irq = 11;
+				break;
+			default:
+				printk("%s: mca_probe IRQ error.  You should never get here (%d).\n", dev->name, where);
+				return;
+			}
+
+			/*
+			   ** Shared memory address of adapter is stored in bits 3-5 of pos0.
+			   ** They are mapped as follows:
+			   **
+			   **    Bit
+			   **   5  4  3       Memory Addresses
+			   **   0  0  0       C0000-CFFFF (64K)
+			   **   1  0  0       C8000-CFFFF (32K)
+			   **   0  0  1       D0000-DFFFF (64K)
+			   **   1  0  1       D8000-DFFFF (32K)
+			   **   0  1  0       E0000-EFFFF (64K)
+			   **   1  1  0       E8000-EFFFF (32K)
+			 */
+			where = (pos[0] & 0x18) >> 3;
+			mem = 0xc0000 + (where * 0x10000);
+			if (pos[0] & 0x20) {
+				mem += 0x8000;
+			}
+
+			/*
+			   ** Get everything allocated and initialized...  (almost just
+			   ** like the ISA and EISA probes)
+			 */
+			if (DevicePresent(iobase) != 0) {
+				/*
+				   ** If the MCA configuration says the card should be here,
+				   ** it really should be here.
+				 */
+				printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not responding.\n", dev->name, iobase);
+			}
+
+			if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+				if ((dev = alloc_device(dev, iobase)) != NULL) {
+					dev->irq = irq;
+					if (depca_hw_init(dev, iobase, slot) == 0) {
+						/*
+						   ** Adapter initialized correctly:  Name it in
+						   ** /proc/mca.
+						 */
+						mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
+						mca_mark_as_used(slot);
+						num_depcas++;
+					}
+					num_eth++;
+				}
+			} else if (autoprobed) {
+				printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
+			}
+
+			/*
+			   ** If this is a probe by a module, return after setting up the
+			   ** given card.
+			 */
+			if (ioaddr)
+				return;
+
+			/*
+			   ** Set up to check the next slot and loop.
+			 */
+			slot++;
+		}
 	}
-    }
 
-    return;
+	return;
 }
 #endif
 
 /*
 ** ISA bus I/O device probe
 */
-static void __init 
-isa_probe(struct net_device *dev, u_long ioaddr)
+static void __init isa_probe(struct net_device *dev, u_long ioaddr)
 {
-  int i = num_depcas, maxSlots;
-  s32 ports[] = DEPCA_IO_PORTS;
+	int i = num_depcas, maxSlots;
+	s32 ports[] = DEPCA_IO_PORTS;
 
-  if (!ioaddr && autoprobed) return ;          /* Been here before ! */
-  if (ioaddr > 0x400) return;                  /* EISA Address */
-  if (i >= MAX_NUM_DEPCAS) return;             /* Too many ISA adapters */
-
-  if (ioaddr == 0) {                           /* Autoprobing */
-    maxSlots = MAX_NUM_DEPCAS;
-  } else {                                     /* Probe a specific location */
-    ports[i] = ioaddr;
-    maxSlots = i + 1;
-  }
-
-  for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
-    if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
-      if (DevicePresent(ports[i]) == 0) { 
-	if ((dev = alloc_device(dev, ports[i])) != NULL) {
-	  if (depca_hw_init(dev, ports[i], -1) == 0) {
-	    num_depcas++;
-	  }
-	  num_eth++;
-	}
-      }
-    } else if (autoprobed) {
-      printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]);
-    }
-  }
+	if (!ioaddr && autoprobed)
+		return;		/* Been here before ! */
+	if (ioaddr > 0x400)
+		return;		/* EISA Address */
+	if (i >= MAX_NUM_DEPCAS)
+		return;		/* Too many ISA adapters */
+
+	if (ioaddr == 0) {	/* Autoprobing */
+		maxSlots = MAX_NUM_DEPCAS;
+	} else {		/* Probe a specific location */
+		ports[i] = ioaddr;
+		maxSlots = i + 1;
+	}
+
+	for (; (i < maxSlots) && (dev != NULL) && ports[i]; i++) {
+		if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+			if (DevicePresent(ports[i]) == 0) {
+				if ((dev = alloc_device(dev, ports[i])) != NULL) {
+					if (depca_hw_init(dev, ports[i], -1) == 0) {
+						num_depcas++;
+					}
+					num_eth++;
+				}
+			}
+		} else if (autoprobed) {
+			printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]);
+		}
+	}
 
-  return;
+	return;
 }
 
 /*
 ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
 ** the motherboard. Upto 15 EISA devices are supported.
 */
-static void __init 
-eisa_probe(struct net_device *dev, u_long ioaddr)
+static void __init eisa_probe(struct net_device *dev, u_long ioaddr)
 {
-  int i, maxSlots;
-  u_long iobase;
-  char name[DEPCA_STRLEN];
-
-  if (!ioaddr && autoprobed) return ;            /* Been here before ! */
-  if ((ioaddr < 0x400) && (ioaddr > 0)) return;  /* ISA Address */
-
-  if (ioaddr == 0) {                           /* Autoprobing */
-    iobase = EISA_SLOT_INC;                    /* Get the first slot address */
-    i = 1;
-    maxSlots = MAX_EISA_SLOTS;
-  } else {                                     /* Probe a specific location */
-    iobase = ioaddr;
-    i = (ioaddr >> 12);
-    maxSlots = i + 1;
-  }
-  if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
-
-  for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
-    if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
-      if (EISA_signature(name, EISA_ID)) {
-	if (DevicePresent(iobase) == 0) { 
-	  if ((dev = alloc_device(dev, iobase)) != NULL) {
-	    if (depca_hw_init(dev, iobase, -1) == 0) {
-	      num_depcas++;
-	    }
-	    num_eth++;
-	  }
-	}
-      }
-    } else if (autoprobed) {
-      printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
-    }
-  }
+	int i, maxSlots;
+	u_long iobase;
+	char name[DEPCA_STRLEN];
+
+	if (!ioaddr && autoprobed)
+		return;		/* Been here before ! */
+	if ((ioaddr < 0x400) && (ioaddr > 0))
+		return;		/* ISA Address */
+
+	if (ioaddr == 0) {	/* Autoprobing */
+		iobase = EISA_SLOT_INC;	/* Get the first slot address */
+		i = 1;
+		maxSlots = MAX_EISA_SLOTS;
+	} else {		/* Probe a specific location */
+		iobase = ioaddr;
+		i = (ioaddr >> 12);
+		maxSlots = i + 1;
+	}
+	if ((iobase & 0x0fff) == 0)
+		iobase += DEPCA_EISA_IO_PORTS;
+
+	for (; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
+		if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+			if (EISA_signature(name, EISA_ID)) {
+				if (DevicePresent(iobase) == 0) {
+					if ((dev = alloc_device(dev, iobase)) != NULL) {
+						if (depca_hw_init(dev, iobase, -1) == 0) {
+							num_depcas++;
+						}
+						num_eth++;
+					}
+				}
+			}
+		} else if (autoprobed) {
+			printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
+		}
+	}
 
-  return;
+	return;
 }
 
 /*
@@ -1500,89 +1484,87 @@
 ** are not available then insert a new device structure at the end of
 ** the current list.
 */
-static struct net_device * __init 
-alloc_device(struct net_device *dev, u_long iobase)
+static struct net_device *__init alloc_device(struct net_device *dev, u_long iobase)
 {
-    struct net_device *adev = NULL;
-    int fixed = 0, new_dev = 0;
+	struct net_device *adev = NULL;
+	int fixed = 0, new_dev = 0;
 
-    num_eth = depca_dev_index(dev->name);
-    if (loading_module) return dev;
-    
-    while (1) {
-	if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr==0)) && !adev) {
-	    adev=dev;
-	} else if ((dev->priv == NULL) && (dev->base_addr==iobase)) {
-	    fixed = 1;
-	} else {
-	    if (dev->next == NULL) {
-		new_dev = 1;
-	    } else if (strncmp(dev->next->name, "eth", 3) != 0) {
-		new_dev = 1;
-	    }
-	}
-	if ((dev->next == NULL) || new_dev || fixed) break;
-	dev = dev->next;
-	num_eth++;
-    }
-    if (adev && !fixed) {
-	dev = adev;
 	num_eth = depca_dev_index(dev->name);
-	new_dev = 0;
-    }
+	if (loading_module)
+		return dev;
 
-    if (((dev->next == NULL) &&  
-	((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) ||
-	new_dev) {
-	num_eth++;                         /* New device */
-	dev = insert_device(dev, iobase, depca_probe);
-    }
-    
-    return dev;
+	while (1) {
+		if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0)) && !adev) {
+			adev = dev;
+		} else if ((dev->priv == NULL) && (dev->base_addr == iobase)) {
+			fixed = 1;
+		} else {
+			if (dev->next == NULL) {
+				new_dev = 1;
+			} else if (strncmp(dev->next->name, "eth", 3) != 0) {
+				new_dev = 1;
+			}
+		}
+		if ((dev->next == NULL) || new_dev || fixed)
+			break;
+		dev = dev->next;
+		num_eth++;
+	}
+	if (adev && !fixed) {
+		dev = adev;
+		num_eth = depca_dev_index(dev->name);
+		new_dev = 0;
+	}
+
+	if (((dev->next == NULL) && ((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) || new_dev) {
+		num_eth++;	/* New device */
+		dev = insert_device(dev, iobase, depca_probe);
+	}
+
+	return dev;
 }
 
 /*
 ** If at end of eth device list and can't use current entry, malloc
 ** one up. If memory could not be allocated, print an error message.
 */
-static struct net_device * __init 
-insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *))
+static struct net_device *__init insert_device(struct net_device *dev, u_long iobase, int (*init) (struct net_device *))
 {
-    struct net_device *new;
+	struct net_device *new;
 
-    new = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
-    if (new == NULL) {
-	printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
-	return NULL;
-    } else {
-	new->next = dev->next;
-	dev->next = new;
-	dev = dev->next;               /* point to the new device */
-	if (num_eth > 9999) {
-	    sprintf(dev->name,"eth????");/* New device name */
+	new = (struct net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	if (new == NULL) {
+		printk("eth%d: Device not initialised, insufficient memory\n", num_eth);
+		return NULL;
 	} else {
-	    sprintf(dev->name,"eth%d", num_eth);/* New device name */
+		new->next = dev->next;
+		dev->next = new;
+		dev = dev->next;	/* point to the new device */
+		if (num_eth > 9999) {
+			sprintf(dev->name, "eth????");	/* New device name */
+		} else {
+			sprintf(dev->name, "eth%d", num_eth);	/* New device name */
+		}
+		dev->base_addr = iobase;	/* assign the io address */
+		dev->init = init;	/* initialisation routine */
 	}
-	dev->base_addr = iobase;       /* assign the io address */
-	dev->init = init;              /* initialisation routine */
-    }
 
-    return dev;
+	return dev;
 }
 
-static int __init 
-depca_dev_index(char *s)
+static int __init depca_dev_index(char *s)
 {
-    int i=0, j=0;
+	int i = 0, j = 0;
 
-    for (;*s; s++) {
-	if (isdigit(*s)) {
-	    j=1;
-	    i = (i * 10) + (*s - '0');
-	} else if (j) break;
-    }
+	for (; *s; s++) {
+		if (isdigit(*s)) {
+			j = 1;
+			i = (i * 10) + (*s - '0');
+		} else if (j)
+			break;
+	}
 
-    return i;
+	return i;
 }
 
 /*
@@ -1590,50 +1572,51 @@
 ** and Boot (readb) ROM. This will also give us a clue to the network RAM
 ** base address.
 */
-static void __init 
-DepcaSignature(char *name, u_long paddr)
+static void __init DepcaSignature(char *name, u_long paddr)
 {
-  u_int i,j,k;
-  const char *signatures[] = DEPCA_SIGNATURE;
-  void *ptr;
-  char tmpstr[16];
-
-  /* Copy the first 16 bytes of ROM */
-  ptr = ioremap(paddr + 0xc000, 16);
-  if (ptr == NULL) {
-	  printk(KERN_ERR "depca: I/O remap failed at %lx\n", paddr+0xc000);
-	  adapter = unknown;
-	  return;
-  }
-  for (i=0;i<16;i++) {
-    tmpstr[i] = readb(ptr + i);
-  }
-  iounmap(ptr);
-
-  /* Check if PROM contains a valid string */
-  for (i=0;*signatures[i]!='\0';i++) {
-    for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
-      if (signatures[i][k] == tmpstr[j]) {              /* track signature */
-	k++;
-      } else {                     /* lost signature; begin search again */
-	k=0;
-      }
-    }
-    if (k == strlen(signatures[i])) break;
-  }
-
-  /* Check if name string is valid, provided there's no PROM */
-  if (*name && (i == unknown)) {
-    for (i=0;*signatures[i]!='\0';i++) {
-      if (strcmp(name,signatures[i]) == 0) break;
-    }
-  }
-
-  /* Update search results */
-  strcpy(name,signatures[i]);
-  adapter = i;
+	u_int i, j, k;
+	const char *signatures[] = DEPCA_SIGNATURE;
+	void *ptr;
+	char tmpstr[16];
+
+	/* Copy the first 16 bytes of ROM */
+	ptr = ioremap(paddr + 0xc000, 16);
+	if (ptr == NULL) {
+		printk(KERN_ERR "depca: I/O remap failed at %lx\n", paddr + 0xc000);
+		adapter = unknown;
+		return;
+	}
+	for (i = 0; i < 16; i++) {
+		tmpstr[i] = readb(ptr + i);
+	}
+	iounmap(ptr);
+
+	/* Check if PROM contains a valid string */
+	for (i = 0; *signatures[i] != '\0'; i++) {
+		for (j = 0, k = 0; j < 16 && k < strlen(signatures[i]); j++) {
+			if (signatures[i][k] == tmpstr[j]) {	/* track signature */
+				k++;
+			} else {	/* lost signature; begin search again */
+				k = 0;
+			}
+		}
+		if (k == strlen(signatures[i]))
+			break;
+	}
 
-  return;
+	/* Check if name string is valid, provided there's no PROM */
+	if (*name && (i == unknown)) {
+		for (i = 0; *signatures[i] != '\0'; i++) {
+			if (strcmp(name, signatures[i]) == 0)
+				break;
+		}
+	}
+
+	/* Update search results */
+	strcpy(name, signatures[i]);
+	adapter = i;
+
+	return;
 }
 
 /*
@@ -1651,52 +1634,52 @@
 ** PROM address counter is correctly positioned at the start of the
 ** ethernet address for later read out.
 */
-static int __init 
-DevicePresent(u_long ioaddr)
+static int __init DevicePresent(u_long ioaddr)
 {
-  union {
-    struct {
-      u32 a;
-      u32 b;
-    } llsig;
-    char Sig[sizeof(u32) << 1];
-  } dev;
-  short sigLength=0;
-  s8 data;
-  s16 nicsr;
-  int i, j, status = 0;
-
-  data = inb(DEPCA_PROM);                /* clear counter on DEPCA */
-  data = inb(DEPCA_PROM);                /* read data */
-
-  if (data == 0x08) {                    /* Enable counter on DEPCA */
-    nicsr = inb(DEPCA_NICSR);
-    nicsr |= AAC;
-    outb(nicsr, DEPCA_NICSR);
-  }
-  
-  dev.llsig.a = ETH_PROM_SIG;
-  dev.llsig.b = ETH_PROM_SIG;
-  sigLength = sizeof(u32) << 1;
-
-  for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
-    data = inb(DEPCA_PROM);
-    if (dev.Sig[j] == data) {    /* track signature */
-      j++;
-    } else {                     /* lost signature; begin search again */
-      if (data == dev.Sig[0]) {  /* rare case.... */
-	j=1;
-      } else {
-	j=0;
-      }
-    }
-  }
-
-  if (j!=sigLength) {
-    status = -ENODEV;           /* search failed */
-  }
+	union {
+		struct {
+			u32 a;
+			u32 b;
+		} llsig;
+		char Sig[sizeof(u32) << 1];
+	}
+	dev;
+	short sigLength = 0;
+	s8 data;
+	s16 nicsr;
+	int i, j, status = 0;
+
+	data = inb(DEPCA_PROM);	/* clear counter on DEPCA */
+	data = inb(DEPCA_PROM);	/* read data */
 
-  return status;
+	if (data == 0x08) {	/* Enable counter on DEPCA */
+		nicsr = inb(DEPCA_NICSR);
+		nicsr |= AAC;
+		outb(nicsr, DEPCA_NICSR);
+	}
+
+	dev.llsig.a = ETH_PROM_SIG;
+	dev.llsig.b = ETH_PROM_SIG;
+	sigLength = sizeof(u32) << 1;
+
+	for (i = 0, j = 0; j < sigLength && i < PROBE_LENGTH + sigLength - 1; i++) {
+		data = inb(DEPCA_PROM);
+		if (dev.Sig[j] == data) {	/* track signature */
+			j++;
+		} else {	/* lost signature; begin search again */
+			if (data == dev.Sig[0]) {	/* rare case.... */
+				j = 1;
+			} else {
+				j = 0;
+			}
+		}
+	}
+
+	if (j != sigLength) {
+		status = -ENODEV;	/* search failed */
+	}
+
+	return status;
 }
 
 /*
@@ -1704,33 +1687,36 @@
 ** reason: access the upper half of the PROM with x=0; access the lower half
 ** with x=1.
 */
-static int __init 
-get_hw_addr(struct net_device *dev)
+static int __init get_hw_addr(struct net_device *dev)
 {
-  u_long ioaddr = dev->base_addr;
-  int i, k, tmp, status = 0;
-  u_short j, x, chksum;
-
-  x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
-
-  for (i=0,k=0,j=0;j<3;j++) {
-    k <<= 1 ;
-    if (k > 0xffff) k-=0xffff;
-
-    k += (u_char) (tmp = inb(DEPCA_PROM + x));
-    dev->dev_addr[i++] = (u_char) tmp;
-    k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
-    dev->dev_addr[i++] = (u_char) tmp;
+	u_long ioaddr = dev->base_addr;
+	int i, k, tmp, status = 0;
+	u_short j, x, chksum;
 
-    if (k > 0xffff) k-=0xffff;
-  }
-  if (k == 0xffff) k=0;
+	x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
 
-  chksum = (u_char) inb(DEPCA_PROM + x);
-  chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
-  if (k != chksum) status = -1;
+	for (i = 0, k = 0, j = 0; j < 3; j++) {
+		k <<= 1;
+		if (k > 0xffff)
+			k -= 0xffff;
+
+		k += (u_char) (tmp = inb(DEPCA_PROM + x));
+		dev->dev_addr[i++] = (u_char) tmp;
+		k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
+		dev->dev_addr[i++] = (u_char) tmp;
+
+		if (k > 0xffff)
+			k -= 0xffff;
+	}
+	if (k == 0xffff)
+		k = 0;
+
+	chksum = (u_char) inb(DEPCA_PROM + x);
+	chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
+	if (k != chksum)
+		status = -1;
 
-  return status;
+	return status;
 }
 
 /*
@@ -1738,165 +1724,161 @@
 */
 static int load_packet(struct net_device *dev, struct sk_buff *skb)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  int i, entry, end, len, status = 0;
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	int i, entry, end, len, status = 0;
 
-  entry = lp->tx_new;  		               /* Ring around buffer number. */
-  end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
-  if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */
-    /* 
-    ** Caution: the write order is important here... don't set up the
-    ** ownership rights until all the other information is in place.
-    */
-    if (end < entry) {                         /* wrapped buffer */
-      len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
-      memcpy_toio(lp->tx_buff[entry], skb->data, len);
-      memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
-    } else {                                   /* linear buffer */
-      memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
-    }
-
-    /* set up the buffer descriptors */
-    len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-    for (i = entry; i != end; i = (++i) & lp->txRingMask) {
-                                               /* clean out flags */
-      writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
-      writew(0x0000, &lp->tx_ring[i].misc);    /* clears other error flags */
-      writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */
-      len -= TX_BUFF_SZ;
-    }
-                                               /* clean out flags */
-    writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
-    writew(0x0000, &lp->tx_ring[end].misc);    /* clears other error flags */
-    writew(-len, &lp->tx_ring[end].length);    /* packet length in last buff */
-
-                                               /* start of packet */
-    writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
-                                               /* end of packet */
-    writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
-
-    for (i=end; i!=entry; --i) {
-                                               /* ownership of packet */
-      writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
-      if (i == 0) i=lp->txRingMask+1;
-    }   
-    writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
- 
-    lp->tx_new = (++end) & lp->txRingMask;     /* update current pointers */
-  } else {
-    status = -1;
-  }
+	entry = lp->tx_new;	/* Ring around buffer number. */
+	end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
+	if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {	/* Enough room? */
+		/* 
+		   ** Caution: the write order is important here... don't set up the
+		   ** ownership rights until all the other information is in place.
+		 */
+		if (end < entry) {	/* wrapped buffer */
+			len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
+			memcpy_toio(lp->tx_buff[entry], skb->data, len);
+			memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
+		} else {	/* linear buffer */
+			memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
+		}
 
-  return status;
+		/* set up the buffer descriptors */
+		len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+		for (i = entry; i != end; i = (++i) & lp->txRingMask) {
+			/* clean out flags */
+			writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
+			writew(0x0000, &lp->tx_ring[i].misc);	/* clears other error flags */
+			writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);	/* packet length in buffer */
+			len -= TX_BUFF_SZ;
+		}
+		/* clean out flags */
+		writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
+		writew(0x0000, &lp->tx_ring[end].misc);	/* clears other error flags */
+		writew(-len, &lp->tx_ring[end].length);	/* packet length in last buff */
+
+		/* start of packet */
+		writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
+		/* end of packet */
+		writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
+
+		for (i = end; i != entry; --i) {
+			/* ownership of packet */
+			writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
+			if (i == 0)
+				i = lp->txRingMask + 1;
+		}
+		writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
+
+		lp->tx_new = (++end) & lp->txRingMask;	/* update current pointers */
+	} else {
+		status = -1;
+	}
+
+	return status;
 }
 
 /*
 ** Look for a particular board name in the EISA configuration space
 */
-static int __init 
-EISA_signature(char *name, s32 eisa_id)
+static int __init EISA_signature(char *name, s32 eisa_id)
 {
-  u_int i;
-  const char *signatures[] = DEPCA_SIGNATURE;
-  char ManCode[DEPCA_STRLEN];
-  union {
-    s32 ID;
-    char Id[4];
-  } Eisa;
-  int status = 0;
-
-  *name = '\0';
-  Eisa.ID = inl(eisa_id);
-
-  ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
-  ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
-  ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
-  ManCode[3]=(( Eisa.Id[2]&0x0f)+0x30);
-  ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
-  ManCode[5]='\0';
-
-  for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
-    if (strstr(ManCode, signatures[i]) != NULL) {
-      strcpy(name,ManCode);
-      status = 1;
-    }
-  }
+	u_int i;
+	const char *signatures[] = DEPCA_SIGNATURE;
+	char ManCode[DEPCA_STRLEN];
+	union {
+		s32 ID;
+		char Id[4];
+	} Eisa;
+	int status = 0;
+
+	*name = '\0';
+	Eisa.ID = inl(eisa_id);
+
+	ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40);
+	ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40);
+	ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30);
+	ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30);
+	ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30);
+	ManCode[5] = '\0';
+
+	for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) {
+		if (strstr(ManCode, signatures[i]) != NULL) {
+			strcpy(name, ManCode);
+			status = 1;
+		}
+	}
 
-  return status;
+	return status;
 }
 
 static void depca_dbg_open(struct net_device *dev)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  u_long ioaddr = dev->base_addr;
-  struct depca_init *p = &lp->init_block;
-  int i; 
-
-  if (depca_debug > 1){
-    /* Do not copy the shadow init block into shared memory */
-    /* Debugging should not affect normal operation! */
-    /* The shadow init block will get copied across during InitRestartDepca */
-    printk("%s: depca open with irq %d\n",dev->name,dev->irq);
-    printk("Descriptor head addresses (CPU):\n");
-    printk("        0x%lx  0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring);
-    printk("Descriptor addresses (CPU):\nRX: ");
-    for (i=0;i<lp->rxRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
-      }
-    }
-    printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
-    printk("TX: ");
-    for (i=0;i<lp->txRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
-      }
-    }
-    printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
-    printk("\nDescriptor buffers (Device):\nRX: ");
-    for (i=0;i<lp->rxRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
-      }
-    }
-    printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
-    printk("TX: ");
-    for (i=0;i<lp->txRingMask;i++){
-      if (i < 3) {
-	printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
-      }
-    }
-    printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
-    printk("Initialisation block at 0x%8.8lx(Phys)\n",virt_to_phys(lp->sh_mem));
-    printk("        mode: 0x%4.4x\n",p->mode);
-    printk("        physical address: ");
-    for (i=0;i<ETH_ALEN-1;i++){
-      printk("%2.2x:", p->phys_addr[i]);
-    }
-    printk("%2.2x\n", p->phys_addr[i]);
-    printk("        multicast hash table: ");
-    for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){
-      printk("%2.2x:", p->mcast_table[i]);
-    }
-    printk("%2.2x\n", p->mcast_table[i]);
-    printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
-    printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
-    printk("buffers (Phys): 0x%8.8lx\n",virt_to_phys(lp->sh_mem)+lp->buffs_offset);
-    printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", 
-	   (int)lp->rxRingMask + 1, 
-	   lp->rx_rlen);
-    printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", 
-	   (int)lp->txRingMask + 1, 
-	   lp->tx_rlen);
-    outw(CSR2,DEPCA_ADDR);
-    printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
-    outw(CSR1,DEPCA_ADDR);
-    printk("%4.4x\n",inw(DEPCA_DATA));
-    outw(CSR3,DEPCA_ADDR);
-    printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	u_long ioaddr = dev->base_addr;
+	struct depca_init *p = &lp->init_block;
+	int i;
 
-  return;
+	if (depca_debug > 1) {
+		/* Do not copy the shadow init block into shared memory */
+		/* Debugging should not affect normal operation! */
+		/* The shadow init block will get copied across during InitRestartDepca */
+		printk("%s: depca open with irq %d\n", dev->name, dev->irq);
+		printk("Descriptor head addresses (CPU):\n");
+		printk("        0x%lx  0x%lx\n", (u_long) lp->rx_ring, (u_long) lp->tx_ring);
+		printk("Descriptor addresses (CPU):\nRX: ");
+		for (i = 0; i < lp->rxRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
+			}
+		}
+		printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
+		printk("TX: ");
+		for (i = 0; i < lp->txRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
+			}
+		}
+		printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
+		printk("\nDescriptor buffers (Device):\nRX: ");
+		for (i = 0; i < lp->rxRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8x  ", readl(&lp->rx_ring[i].base));
+			}
+		}
+		printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
+		printk("TX: ");
+		for (i = 0; i < lp->txRingMask; i++) {
+			if (i < 3) {
+				printk("0x%8.8x  ", readl(&lp->tx_ring[i].base));
+			}
+		}
+		printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
+		printk("Initialisation block at 0x%8.8lx(Phys)\n", virt_to_phys(lp->sh_mem));
+		printk("        mode: 0x%4.4x\n", p->mode);
+		printk("        physical address: ");
+		for (i = 0; i < ETH_ALEN - 1; i++) {
+			printk("%2.2x:", p->phys_addr[i]);
+		}
+		printk("%2.2x\n", p->phys_addr[i]);
+		printk("        multicast hash table: ");
+		for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
+			printk("%2.2x:", p->mcast_table[i]);
+		}
+		printk("%2.2x\n", p->mcast_table[i]);
+		printk("        rx_ring at: 0x%8.8x\n", p->rx_ring);
+		printk("        tx_ring at: 0x%8.8x\n", p->tx_ring);
+		printk("buffers (Phys): 0x%8.8lx\n", virt_to_phys(lp->sh_mem) + lp->buffs_offset);
+		printk("Ring size:\nRX: %d  Log2(rxRingMask): 0x%8.8x\n", (int) lp->rxRingMask + 1, lp->rx_rlen);
+		printk("TX: %d  Log2(txRingMask): 0x%8.8x\n", (int) lp->txRingMask + 1, lp->tx_rlen);
+		outw(CSR2, DEPCA_ADDR);
+		printk("CSR2&1: 0x%4.4x", inw(DEPCA_DATA));
+		outw(CSR1, DEPCA_ADDR);
+		printk("%4.4x\n", inw(DEPCA_DATA));
+		outw(CSR3, DEPCA_ADDR);
+		printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA));
+	}
+
+	return;
 }
 
 /*
@@ -1906,177 +1888,196 @@
 */
 static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-  struct depca_private *lp = (struct depca_private *)dev->priv;
-  struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
-  int i, status = 0;
-  u_long ioaddr = dev->base_addr;
-  union {
-    u8  addr[(HASH_TABLE_LEN * ETH_ALEN)];
-    u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-    u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
-  } tmp;
-
-  switch(ioc->cmd) {
-  case DEPCA_GET_HWADDR:             /* Get the hardware address */
-    for (i=0; i<ETH_ALEN; i++) {
-      tmp.addr[i] = dev->dev_addr[i];
-    }
-    ioc->len = ETH_ALEN;
-    if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-      return -EFAULT;
-    break;
-
-  case DEPCA_SET_HWADDR:             /* Set the hardware address */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
-      return -EFAULT;
-    for (i=0; i<ETH_ALEN; i++) {
-      dev->dev_addr[i] = tmp.addr[i];
-    }
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);    /* Wait for the ring to empty */
-
-    STOP_DEPCA;                         /* Temporarily stop the depca.  */
-    depca_init_ring(dev);               /* Initialize the descriptor rings */
-    LoadCSRs(dev);                      /* Reload CSR3 */
-    InitRestartDepca(dev);              /* Resume normal operation. */
-    netif_start_queue(dev);             /* Unlock the TX ring */
-    break;
-
-  case DEPCA_SET_PROM:               /* Set Promiscuous Mode */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);    /* Wait for the ring to empty */
-
-    STOP_DEPCA;                         /* Temporarily stop the depca.  */
-    depca_init_ring(dev);               /* Initialize the descriptor rings */
-    lp->init_block.mode |= PROM;        /* Set promiscuous mode */
-
-    LoadCSRs(dev);                      /* Reload CSR3 */
-    InitRestartDepca(dev);              /* Resume normal operation. */
-    netif_start_queue(dev);             /* Unlock the TX ring */
-    break;
-
-  case DEPCA_CLR_PROM:               /* Clear Promiscuous Mode */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    netif_stop_queue(dev);
-    while(lp->tx_old != lp->tx_new);    /* Wait for the ring to empty */
-
-    STOP_DEPCA;                         /* Temporarily stop the depca.  */
-    depca_init_ring(dev);               /* Initialize the descriptor rings */
-    lp->init_block.mode &= ~PROM;       /* Clear promiscuous mode */
-
-    LoadCSRs(dev);                      /* Reload CSR3 */
-    InitRestartDepca(dev);              /* Resume normal operation. */
-    netif_start_queue(dev);             /* Unlock the TX ring */
-    break;
-
-  case DEPCA_SAY_BOO:                /* Say "Boo!" to the kernel log file */
-    printk("%s: Boo!\n", dev->name);
-    break;
-
-  case DEPCA_GET_MCA:                /* Get the multicast address table */
-    ioc->len = (HASH_TABLE_LEN >> 3);
-    if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
-      return -EFAULT;
-    break;
-
-  case DEPCA_SET_MCA:                /* Set a multicast address */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
-      return -EFAULT;
-    set_multicast_list(dev);
-    break;
-
-  case DEPCA_CLR_MCA:                /* Clear all multicast addresses */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    set_multicast_list(dev);
-    break;
-
-  case DEPCA_MCA_EN:                 /* Enable pass all multicast addressing */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-      set_multicast_list(dev);
-    break;
-
-  case DEPCA_GET_STATS:              /* Get the driver statistics */
-    cli();
-    ioc->len = sizeof(lp->pktStats);
-    if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
-      status = -EFAULT;
-    sti();
-    break;
-
-  case DEPCA_CLR_STATS:              /* Zero out the driver statistics */
-    if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    cli();
-    memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-    sti();
-    break;
-
-  case DEPCA_GET_REG:                /* Get the DEPCA Registers */
-    i=0;
-    tmp.sval[i++] = inw(DEPCA_NICSR);
-    outw(CSR0, DEPCA_ADDR);              /* status register */
-    tmp.sval[i++] = inw(DEPCA_DATA);
-    memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
-    ioc->len = i+sizeof(struct depca_init);
-    if (copy_to_user(ioc->data, tmp.addr, ioc->len))
-      return -EFAULT;
-    break;
-
-  default:
-    return -EOPNOTSUPP;
-  }
+	struct depca_private *lp = (struct depca_private *) dev->priv;
+	struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
+	int i, status = 0;
+	u_long ioaddr = dev->base_addr;
+	union {
+		u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
+		u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+		u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+	} tmp;
+	unsigned long flags;
+	void *buf;
+
+	switch (ioc->cmd) {
+	case DEPCA_GET_HWADDR:	/* Get the hardware address */
+		for (i = 0; i < ETH_ALEN; i++) {
+			tmp.addr[i] = dev->dev_addr[i];
+		}
+		ioc->len = ETH_ALEN;
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			return -EFAULT;
+		break;
 
-  return status;
+	case DEPCA_SET_HWADDR:	/* Set the hardware address */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
+			return -EFAULT;
+		for (i = 0; i < ETH_ALEN; i++) {
+			dev->dev_addr[i] = tmp.addr[i];
+		}
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+		break;
+
+	case DEPCA_SET_PROM:	/* Set Promiscuous Mode */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+		lp->init_block.mode |= PROM;	/* Set promiscuous mode */
+
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+		break;
+
+	case DEPCA_CLR_PROM:	/* Clear Promiscuous Mode */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		netif_stop_queue(dev);
+		while (lp->tx_old != lp->tx_new)
+			cpu_relax();	/* Wait for the ring to empty */
+
+		STOP_DEPCA;	/* Temporarily stop the depca.  */
+		depca_init_ring(dev);	/* Initialize the descriptor rings */
+		lp->init_block.mode &= ~PROM;	/* Clear promiscuous mode */
+
+		LoadCSRs(dev);	/* Reload CSR3 */
+		InitRestartDepca(dev);	/* Resume normal operation. */
+		netif_start_queue(dev);	/* Unlock the TX ring */
+		break;
+
+	case DEPCA_SAY_BOO:	/* Say "Boo!" to the kernel log file */
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		printk("%s: Boo!\n", dev->name);
+		break;
+
+	case DEPCA_GET_MCA:	/* Get the multicast address table */
+		ioc->len = (HASH_TABLE_LEN >> 3);
+		if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
+			return -EFAULT;
+		break;
+
+	case DEPCA_SET_MCA:	/* Set a multicast address */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (ioc->len >= HASH_TABLE_LEN)
+			return -EINVAL;
+		if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
+			return -EFAULT;
+		set_multicast_list(dev);
+		break;
+
+	case DEPCA_CLR_MCA:	/* Clear all multicast addresses */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		set_multicast_list(dev);
+		break;
+
+	case DEPCA_MCA_EN:	/* Enable pass all multicast addressing */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		set_multicast_list(dev);
+		break;
+
+	case DEPCA_GET_STATS:	/* Get the driver statistics */
+		ioc->len = sizeof(lp->pktStats);
+		buf = kmalloc(ioc->len, GFP_KERNEL);
+		if(!buf)
+			return -ENOMEM;
+		spin_lock_irqsave(&lp->lock, flags);
+		memcpy(buf, &lp->pktStats, ioc->len);
+		spin_unlock_irqrestore(&lp->lock, flags);
+		if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
+			status = -EFAULT;
+		kfree(buf);
+		break;
+
+	case DEPCA_CLR_STATS:	/* Zero out the driver statistics */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		spin_lock_irqsave(&lp->lock, flags);
+		memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+		spin_unlock_irqrestore(&lp->lock, flags);
+		break;
+
+	case DEPCA_GET_REG:	/* Get the DEPCA Registers */
+		i = 0;
+		tmp.sval[i++] = inw(DEPCA_NICSR);
+		outw(CSR0, DEPCA_ADDR);	/* status register */
+		tmp.sval[i++] = inw(DEPCA_DATA);
+		memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
+		ioc->len = i + sizeof(struct depca_init);
+		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			return -EFAULT;
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return status;
 }
 
 #ifdef MODULE
 static struct net_device thisDepca;
-static int irq=7;	/* EDIT THESE LINE FOR YOUR CONFIGURATION */
-static int io=0x200;    /* Or use the irq= io= options to insmod */
+static int irq = 7;		/* EDIT THESE LINE FOR YOUR CONFIGURATION */
+static int io = 0x200;		/* Or use the irq= io= options to insmod */
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(irq, "DEPCA IRQ number");
 MODULE_PARM_DESC(io, "DEPCA I/O base address");
 
-/* See depca_probe() for autoprobe messages when a module */	
-int
-init_module(void)
+/* See depca_probe() for autoprobe messages when a module */
+int init_module(void)
 {
-  thisDepca.irq=irq;
-  thisDepca.base_addr=io;
-  thisDepca.init = depca_probe;
+	thisDepca.irq = irq;
+	thisDepca.base_addr = io;
+	thisDepca.init = depca_probe;
 
-  if (register_netdev(&thisDepca) != 0)
-    return -EIO;
+	if (register_netdev(&thisDepca) != 0)
+		return -EIO;
 
-  return 0;
+	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
-  struct depca_private *lp = thisDepca.priv;
+	struct depca_private *lp = thisDepca.priv;
 
-  unregister_netdev(&thisDepca);
-  if (lp) {
-    iounmap(lp->sh_mem);
-#ifdef CONFIG_MCA      
-    if(lp->mca_slot != -1)
-      mca_mark_as_unused(lp->mca_slot);
-#endif                 
-    kfree(lp);
-    thisDepca.priv = NULL;
-  }
-  thisDepca.irq=0;
+	unregister_netdev(&thisDepca);
+	if (lp) {
+		iounmap(lp->sh_mem);
+#ifdef CONFIG_MCA
+		if (lp->mca_slot != -1)
+			mca_mark_as_unused(lp->mca_slot);
+#endif
+		kfree(lp);
+		thisDepca.priv = NULL;
+	}
+	thisDepca.irq = 0;
 
-  release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
+	release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
 }
-#endif /* MODULE */
+#endif				/* MODULE */
 MODULE_LICENSE("GPL");
-
 
+
 /*
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c depca.c"
diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/net/e1000/e1000_main.c	Fri Oct 11 21:22:55 2002
@@ -135,7 +135,7 @@
 static void e1000_exit_module(void);
 static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 static void e1000_remove(struct pci_dev *pdev);
-static void e1000_sw_init(struct e1000_adapter *adapter);
+static int e1000_sw_init(struct e1000_adapter *adapter);
 static int e1000_open(struct net_device *netdev);
 static int e1000_close(struct net_device *netdev);
 static int e1000_setup_tx_resources(struct e1000_adapter *adapter);
@@ -415,7 +415,8 @@
 
 	/* setup the private structure */
 
-	e1000_sw_init(adapter);
+	if(e1000_sw_init(adapter))
+		goto err_sw_init;
 
 	if(adapter->hw.mac_type >= e1000_82543) {
 		netdev->features = NETIF_F_SG |
@@ -500,6 +501,7 @@
 	cards_found++;
 	return 0;
 
+err_sw_init:
 err_eeprom:
 	iounmap(adapter->hw.hw_addr);
 err_ioremap:
@@ -555,7 +557,7 @@
  * OS network device settings (MTU size).
  **/
 
-static void __devinit
+static int __devinit
 e1000_sw_init(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
@@ -564,11 +566,11 @@
 
 	/* PCI config space info */
 
-	pci_read_config_word(pdev, PCI_VENDOR_ID, &hw->vendor_id);
-	pci_read_config_word(pdev, PCI_DEVICE_ID, &hw->device_id);
-	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, 
-	                     &hw->subsystem_vendor_id);
-	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_id);
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_id = pdev->subsystem_device;
+
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
 	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
 
@@ -581,7 +583,7 @@
 
 	if (e1000_set_mac_type(hw)) {
 		E1000_ERR("Unknown MAC Type\n");
-		BUG();
+		return -1;
 	}
 
 	/* flow control settings */
@@ -622,6 +624,8 @@
 
 	atomic_set(&adapter->irq_sem, 1);
 	spin_lock_init(&adapter->stats_lock);
+
+	return 0;
 }
 
 /**
diff -Nru a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
--- a/drivers/net/ewrk3.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/net/ewrk3.c	Fri Oct 11 21:22:57 2002
@@ -76,6 +76,7 @@
    kernel with the ewrk3 configuration turned off and reboot.
    5) insmod ewrk3.o
    [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
+   [Adam Kropelin: now accepts irq=x1,x2 io=y1,y2 for multiple cards]
    6) run the net startup bits for your new eth?? interface manually
    (usually /etc/rc.inet[12] at boot time).
    7) enjoy!
@@ -130,10 +131,12 @@
    Add new multicasting code.
    0.41    20-Jan-96   Fix IRQ set up problem reported by
    <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>
-   0.45	   19-Jul-02	  fix unaligned access on alpha <martin@bruli.net>
+   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>
+   0.45    19-Jul-02   fix unaligned access on alpha <martin@bruli.net>
+   0.46    10-Oct-02   cli/sti removal <VDA@port.imtp.ilyichevsk.odessa.ua>
+   Multiple NIC support when module <akropel1@rochester.rr.com>
 
    =========================================================================
  */
@@ -167,7 +170,7 @@
 #include "ewrk3.h"
 
 static char version[] __initdata =
-"ewrk3.c:v0.43a 2001/02/04 davies@maniac.ultranet.com\n";
+"ewrk3.c:v0.46 2002/10/09 davies@maniac.ultranet.com\n";
 
 #ifdef EWRK3_DEBUG
 static int ewrk3_debug = EWRK3_DEBUG;
@@ -196,6 +199,7 @@
 #define EWRK3_IOP_INC 0x20	/* I/O address increment */
 #define EWRK3_TOTAL_SIZE 0x20	/* required I/O address length */
 
+/* If you change this, remember to also change MODULE_PARM array limits */
 #ifndef MAX_NUM_EWRK3S
 #define MAX_NUM_EWRK3S 21
 #endif
@@ -1716,6 +1720,11 @@
 		break;
 	case EWRK3_SET_MCA:	/* Set a multicast address */
 		if (capable(CAP_NET_ADMIN)) {
+			if (ioc->len > 1024)
+			{
+				status = -EINVAL;
+				break;
+			}
 			if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
 				status = -EFAULT;
 				break;
@@ -1843,35 +1852,62 @@
 }
 
 #ifdef MODULE
-static struct net_device thisEthwrk;
-static int io = 0x300;		/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-static int irq = 5;		/* or use the insmod io= irq= options           */
-
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address");
-MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number");
+static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];
+static int ndevs;
+static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };		/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int irq[MAX_NUM_EWRK3S+1] = { 5, 0, };		/* or use the insmod io= irq= options           */
+
+/* '21' below should really be 'MAX_NUM_EWRK3S' */
+MODULE_PARM(io, "0-21i");
+MODULE_PARM(irq, "0-21i");
+MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)");
+MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)");
 
 int init_module(void)
 {
-	thisEthwrk.base_addr = io;
-	thisEthwrk.irq = irq;
-	thisEthwrk.init = ewrk3_probe;
-	if (register_netdev(&thisEthwrk) != 0)
-		return -EIO;
-	return 0;
+	int i=0;
+
+	while( io[i] && irq[i] ) {
+		ewrk3_devs[ndevs] = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+		if (!ewrk3_devs[ndevs])
+			goto error; 
+		memset(ewrk3_devs[ndevs], 0, sizeof(struct net_device));
+		ewrk3_devs[ndevs]->base_addr = io[i];
+		ewrk3_devs[ndevs]->irq = irq[i];
+		ewrk3_devs[ndevs]->init = ewrk3_probe;
+
+		if (register_netdev(ewrk3_devs[ndevs]) == 0)
+			ndevs++;
+		else
+			kfree(ewrk3_devs[ndevs]);
+
+		i++;
+	}
+
+	return ndevs ? 0 : -EIO;
+
+error:
+	cleanup_module();
+	return -ENOMEM;
 }
 
 void cleanup_module(void)
 {
-	unregister_netdev(&thisEthwrk);
-	if (thisEthwrk.priv) {
-		kfree(thisEthwrk.priv);
-		thisEthwrk.priv = NULL;
-	}
-	thisEthwrk.irq = 0;
+	int i;
 
-	release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE);
+	for( i=0; i<ndevs; i++ )
+	{
+		unregister_netdev(ewrk3_devs[i]);
+		if (ewrk3_devs[i]->priv) {
+			kfree(ewrk3_devs[i]->priv);
+			ewrk3_devs[i]->priv = NULL;
+		}
+		ewrk3_devs[i]->irq = 0;
+
+		release_region(ewrk3_devs[i]->base_addr, EWRK3_TOTAL_SIZE);
+		kfree(ewrk3_devs[i]);
+		ewrk3_devs[i] = NULL;
+	}
 }
 #endif				/* MODULE */
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
--- a/drivers/net/gt96100eth.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/net/gt96100eth.c	Fri Oct 11 21:23:02 2002
@@ -267,7 +267,7 @@
 		gt96100_delay(1);
 
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n");
+			printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
 			return -ENODEV;
 		}
 	}
@@ -281,7 +281,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": timeout!!\n");
+			printk(KERN_ERR "%s: timeout!!\n", __FUNCTION__);
 			return -ENODEV;
 		}
 	}
@@ -333,7 +333,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n");
+			printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
 			return -1;
 		}
 	}
@@ -350,7 +350,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int i;
 
-	dbg(0, __FUNCTION__ ": txno/txni/cnt=%d/%d/%d\n",
+	dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__,
 	    gp->tx_next_out, gp->tx_next_in, gp->tx_count);
 
 	for (i=0; i<TX_RING_SIZE; i++)
@@ -363,7 +363,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int i;
 
-	dbg(0, __FUNCTION__ ": rxno=%d\n", gp->rx_next_out);
+	dbg(0, "%s: rxno=%d\n", __FUNCTION__, gp->rx_next_out);
 
 	for (i=0; i<RX_RING_SIZE; i++)
 		dump_rx_desc(0, dev, i);
@@ -414,9 +414,8 @@
 	unsigned char* skbdata;
     
 	if (dbg_lvl <= GT96100_DEBUG) {
-		dbg(dbg_lvl, __FUNCTION__
-		    ": skb=%p, skb->data=%p, skb->len=%d\n",
-		    skb, skb->data, skb->len);
+		dbg(dbg_lvl, "%s: skb=%p, skb->data=%p, skb->len=%d\n",
+		    __FUNCTION__, skb, skb->data, skb->len);
 
 		skbdata = (unsigned char*)KSEG1ADDR(skb->data);
     
@@ -446,11 +445,11 @@
 	tblEntry1 |= (u32)addr[4] << 11;
 	tblEntry1 |= (u32)addr[3] << 19;
 	tblEntry1 |= ((u32)addr[2] & 0x1f) << 27;
-	dbg(3, __FUNCTION__ ": tblEntry1=%x\n", tblEntry1);
+	dbg(3, "%s: tblEntry1=%x\n", __FUNCTION__, tblEntry1);
 	tblEntry0 = ((u32)addr[2] >> 5) & 0x07;
 	tblEntry0 |= (u32)addr[1] << 3;
 	tblEntry0 |= (u32)addr[0] << 11;
-	dbg(3, __FUNCTION__ ": tblEntry0=%x\n", tblEntry0);
+	dbg(3, "%s: tblEntry0=%x\n", __FUNCTION__, tblEntry0);
 
 #if 0
 
@@ -464,7 +463,7 @@
 			((ctmp&0x20)<<1) | ((ctmp&0x40)>>1);
 	}
 
-	dump_hw_addr(3, dev, __FUNCTION__ ": nib swap/invt addr=", hash_ea);
+	dump_hw_addr(3, dev, "%s: nib swap/invt addr=", __FUNCTION__, hash_ea);
     
 	if (gp->hash_mode == 0) {
 		hashResult = ((u16)hash_ea[0] & 0xfc) << 7;
@@ -478,19 +477,19 @@
 		return -1; // don't support hash mode 1
 	}
 
-	dbg(3, __FUNCTION__ ": hashResult=%x\n", hashResult);
+	dbg(3, "%s: hashResult=%x\n", __FUNCTION__, hashResult);
 
 	tblEntryAddr =
 		(u32 *)(&gp->hash_table[((u32)hashResult & 0x7ff) << 3]);
     
-	dbg(3, __FUNCTION__ ": tblEntryAddr=%p\n", tblEntryAddr);
+	dbg(3, "%s: tblEntryAddr=%p\n", tblEntryAddr, __FUNCTION__);
 
 	for (i=0; i<HASH_HOP_NUMBER; i++) {
 		if ((*tblEntryAddr & hteValid) &&
 		    !(*tblEntryAddr & hteSkip)) {
 			// This entry is already occupied, go to next entry
 			tblEntryAddr += 2;
-			dbg(3, __FUNCTION__ ": skipping to %p\n",
+			dbg(3, "%s: skipping to %p\n", __FUNCTION__, 
 			    tblEntryAddr);
 		} else {
 			memset(tblEntryAddr, 0, 8);
@@ -501,7 +500,7 @@
 	}
 
 	if (i >= HASH_HOP_NUMBER) {
-		err(__FUNCTION__ ": expired!\n");
+		err("%s: expired!\n", __FUNCTION__);
 		return -1; // Couldn't find an unused entry
 	}
 
@@ -563,7 +562,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int timedout = 100; // wait up to 100 msec for hard stop to complete
 
-	dbg(3, __FUNCTION__ "\n");
+	dbg(3, "%s\n", __FUNCTION__);
 
 	// Return if neither Rx or Tx abort bits are set
 	if (!(abort_bits & (sdcmrAR | sdcmrAT)))
@@ -577,7 +576,7 @@
 	// abort any Rx/Tx DMA immediately
 	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);
 
-	dbg(3, __FUNCTION__ ": SDMA comm = %x\n",
+	dbg(3, "%s: SDMA comm = %x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
 
 	// wait for abort to complete
@@ -586,7 +585,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			err(__FUNCTION__ ": timeout!!\n");
+			err("%s: timeout!!\n", __FUNCTION__);
 			break;
 		}
 	}
@@ -600,7 +599,7 @@
 {
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 
-	dbg(3, __FUNCTION__ "\n");
+	dbg(3, "%s\n", __FUNCTION__);
 
 	disable_ether_irq(dev);
 
@@ -712,8 +711,7 @@
 	struct net_device *dev = NULL;
     
 	if (gtif->irq < 0) {
-		printk(KERN_ERR __FUNCTION__
-		       ": irq unknown - probing not supported\n");
+		printk(KERN_ERR "%s: irq unknown - probing not supported\n", __FUNCTION_);
 		return -ENODEV;
 	}
     
@@ -737,13 +735,12 @@
 	// probe for the external PHY
 	if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 ||
 	    (phy_id2 = read_MII(phy_addr, 3)) <= 0) {
-		printk(KERN_ERR __FUNCTION__
-		       ": no PHY found on MII%d\n", port_num);
+		printk(KERN_ERR "%s: no PHY found on MII%d\n", __FUNCTION__, port_num);
 		return -ENODEV;
 	}
 	
 	if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) {
-		printk(KERN_ERR __FUNCTION__ ": request_region failed\n");
+		printk(KERN_ERR "%s: request_region failed\n", __FUNCTION__);
 		return -EBUSY;
 	}
 
@@ -756,7 +753,7 @@
 	dev->irq = gtif->irq;
 
 	if ((retval = parse_mac_addr(dev, gtif->mac_str))) {
-		err(__FUNCTION__ ": MAC address parse failed\n");
+		err("%s: MAC address parse failed\n", __FUNCTION__);
 		retval = -EINVAL;
 		goto free_region;
 	}
@@ -820,7 +817,7 @@
 		}
 	}
     
-	dbg(3, __FUNCTION__ ": rx_ring=%p, tx_ring=%p\n",
+	dbg(3, "%s: rx_ring=%p, tx_ring=%p\n", __FUNCTION__,
 	    gp->rx_ring, gp->tx_ring);
 
 	// Allocate Rx Hash Table
@@ -837,7 +834,7 @@
 		}
 	}
     
-	dbg(3, __FUNCTION__ ": hash=%p\n", gp->hash_table);
+	dbg(3, "%s: hash=%p\n", __FUNCTION__, gp->hash_table);
 
 	spin_lock_init(&gp->lock);
     
@@ -860,7 +857,7 @@
 	if (dev->priv != NULL)
 		kfree (dev->priv);
 	kfree (dev);
-	err(__FUNCTION__ " failed.  Returns %d\n", retval);
+	err("%s failed.  Returns %d\n", __FUNCTION__, retval);
 	return retval;
 }
 
@@ -967,10 +964,10 @@
 	u32 tmp;
 	u16 mii_reg;
     
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
-	dbg(3, __FUNCTION__ ": scs10_lo=%4x, scs10_hi=%4x\n",
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
+	dbg(3, "%s: scs10_lo=%4x, scs10_hi=%4x\n", __FUNCTION__, 
 	    GT96100_READ(0x8), GT96100_READ(0x10));
-	dbg(3, __FUNCTION__ ": scs32_lo=%4x, scs32_hi=%4x\n",
+	dbg(3, "%s: scs32_lo=%4x, scs32_hi=%4x\n", __FUNCTION__,
 	    GT96100_READ(0x18), GT96100_READ(0x20));
     
 	// Stop and disable Port
@@ -985,7 +982,7 @@
 	tmp |= (1<<31);
 #endif
 	GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp);
-	dbg(3, __FUNCTION__ ": CIU Config=%x/%x\n",
+	dbg(3, "%s: CIU Config=%x/%x\n", __FUNCTION__, 
 	    tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));
 
 	// Set routing.
@@ -1010,19 +1007,19 @@
 	gt96100_add_hash_entry(dev, dev->dev_addr);
 	// Set-up DMA ptr to hash table
 	GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);
-	dbg(3, __FUNCTION__ ": Hash Tbl Ptr=%x\n",
+	dbg(3, "%s: Hash Tbl Ptr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));
 
 	// Setup Tx
 	reset_tx(dev);
 
-	dbg(3, __FUNCTION__ ": Curr Tx Desc Ptr0=%x\n",
+	dbg(3, "%s: Curr Tx Desc Ptr0=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0));
 
 	// Setup Rx
 	reset_rx(dev);
 
-	dbg(3, __FUNCTION__ ": 1st/Curr Rx Desc Ptr0=%x/%x\n",
+	dbg(3, "%s: 1st/Curr Rx Desc Ptr0=%x/%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0),
 	    GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));
 
@@ -1034,7 +1031,7 @@
 	mii_reg |= 2;  /* enable mii interrupt */
 	write_MII(gp->phy_addr, 0x11, mii_reg);
 	
-	dbg(3, __FUNCTION__ ": PhyAD=%x\n",
+	dbg(3, "%s: PhyAD=%x\n", __FUNCTION__,
 	    GT96100_READ(GT96100_ETH_PHY_ADDR_REG));
 
 	// setup DMA
@@ -1049,17 +1046,17 @@
 			 sdcrBLMR | sdcrBLMT |
 			 (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
 #endif
-	dbg(3, __FUNCTION__ ": SDMA Config=%x\n",
+	dbg(3, "%s: SDMA Config=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));
 
 	// start Rx DMA
 	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
-	dbg(3, __FUNCTION__ ": SDMA Comm=%x\n",
+	dbg(3, "%s: SDMA Comm=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
     
 	// enable this port (set hash size to 1/2K)
 	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);
-	dbg(3, __FUNCTION__ ": Port Config=%x\n",
+	dbg(3, "%s: Port Config=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));
     
 	/*
@@ -1079,7 +1076,7 @@
 			 pcxrFCTL | pcxrFCTLen | pcxrFLP |
 			 pcxrPRIOrxOverride | pcxrMIBclrMode);
     
-	dbg(3, __FUNCTION__ ": Port Config Ext=%x\n",
+	dbg(3, "%s: Port Config Ext=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));
 
 	netif_start_queue(dev);
@@ -1101,7 +1098,7 @@
     
 	MOD_INC_USE_COUNT;
 
-	dbg(2, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(2, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	// Initialize and startup the GT-96100 ethernet port
 	if ((retval = gt96100_init(dev))) {
@@ -1118,7 +1115,7 @@
 		return retval;
 	}
 	
-	dbg(2, __FUNCTION__ ": Initialization done.\n");
+	dbg(2, "%s: Initialization done.\n", __FUNCTION__);
 
 	return 0;
 }
@@ -1126,7 +1123,7 @@
 static int
 gt96100_close(struct net_device *dev)
 {
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	// stop the device
 	if (netif_device_present(dev)) {
@@ -1152,7 +1149,7 @@
 
 	nextIn = gp->tx_next_in;
 
-	dbg(3, __FUNCTION__ ": nextIn=%d\n", nextIn);
+	dbg(3, "%s: nextIn=%d\n", __FUNCTION__, nextIn);
     
 	if (gp->tx_count >= TX_RING_SIZE) {
 		warn("Tx Ring full, pkt dropped.\n");
@@ -1162,14 +1159,14 @@
 	}
     
 	if (!(gp->last_psr & psrLink)) {
-		err(__FUNCTION__ ": Link down, pkt dropped.\n");
+		err("%s: Link down, pkt dropped.\n", __FUNCTION__);
 		gp->stats.tx_dropped++;
 		spin_unlock_irqrestore(&gp->lock, flags);
 		return 1;
 	}
     
 	if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) {
-		err(__FUNCTION__ ": device owns descriptor, pkt dropped.\n");
+		err("%s: device owns descriptor, pkt dropped.\n", __FUNCTION__);
 		gp->stats.tx_dropped++;
 		// stop the queue, so Tx timeout can fix it
 		netif_stop_queue(dev);
@@ -1222,7 +1219,7 @@
 	gt96100_rd_t *rd;
 	u32 cmdstat;
     
-	dbg(3, __FUNCTION__ ": dev=%p, status=%x\n", dev, status);
+	dbg(3, "%s: dev=%p, status=%x\n", __FUNCTION__, dev, status);
 
 	cdp = (GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0)
 	       - gp->rx_ring_dma) / sizeof(gt96100_rd_t);
@@ -1237,7 +1234,7 @@
 		rd = &gp->rx_ring[nextOut];
 		cmdstat = dma32_to_cpu(rd->cmdstat);
 	
-		dbg(4, __FUNCTION__ ": Rx desc cmdstat=%x, nextOut=%d\n",
+		dbg(4, "%s: Rx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
 		    cmdstat, nextOut);
 
 		if (cmdstat & (u32)rxOwn) {
@@ -1279,8 +1276,7 @@
 				 * the deal with this packet? Good question,
 				 * let's dump it out.
 				 */
-				err(__FUNCTION__
-				    ": desc not first and last!\n");
+				err("%s: desc not first and last!\n", __FUNCTION__);
 				dump_rx_desc(0, dev, nextOut);
 			}
 			cmdstat |= (u32)rxOwn;
@@ -1294,8 +1290,7 @@
 		/* Create new skb. */
 		skb = dev_alloc_skb(pkt_len+2);
 		if (skb == NULL) {
-			err(__FUNCTION__
-			    ": Memory squeeze, dropping packet.\n");
+			err("%s: Memory squeeze, dropping packet.\n", __FUNCTION__);
 			gp->stats.rx_dropped++;
 			cmdstat |= (u32)rxOwn;
 			rd->cmdstat = cpu_to_dma32(cmdstat);
@@ -1317,7 +1312,7 @@
 	}
     
 	if (nextOut == gp->rx_next_out)
-		dbg(3, __FUNCTION__ ": RxCDP did not increment?\n");
+		dbg(3, "%s: RxCDP did not increment?\n", __FUNCTION__);
 
 	gp->rx_next_out = nextOut;
 	return 0;
@@ -1345,7 +1340,7 @@
 		td = &gp->tx_ring[nextOut];
 		cmdstat = dma32_to_cpu(td->cmdstat);
 	
-		dbg(3, __FUNCTION__ ": Tx desc cmdstat=%x, nextOut=%d\n",
+		dbg(3, "%s: Tx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
 		    cmdstat, nextOut);
 	
 		if (cmdstat & (u32)txOwn) {
@@ -1358,7 +1353,7 @@
 	
 		// increment Tx error stats
 		if (cmdstat & (u32)txErrorSummary) {
-			dbg(2, __FUNCTION__ ": Tx error, cmdstat = %x\n",
+			dbg(2, "%s: Tx error, cmdstat = %x\n", __FUNCTION__,
 			    cmdstat);
 			gp->stats.tx_errors++;
 			if (cmdstat & (u32)txReTxLimit)
@@ -1379,8 +1374,7 @@
 			gp->tx_full = 0;
 			if (gp->last_psr & psrLink) {
 				netif_wake_queue(dev);
-				dbg(2, __FUNCTION__
-				    ": Tx Ring was full, queue waked\n");
+				dbg(2, "%s: Tx Ring was full, queue waked\n", __FUNCTION_);
 			}
 		}
 	
@@ -1389,24 +1383,24 @@
 	
 		// free the skb
 		if (gp->tx_skbuff[nextOut]) {
-			dbg(3, __FUNCTION__ ": good Tx, skb=%p\n",
+			dbg(3, "%s: good Tx, skb=%p\n", __FUNCTION__,
 			    gp->tx_skbuff[nextOut]);
 			dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
 			gp->tx_skbuff[nextOut] = NULL;
 		} else {
-			err(__FUNCTION__ ": no skb!\n");
+			err("%s: no skb!\n", __FUNCTION__);
 		}
 	}
 
 	gp->tx_next_out = nextOut;
 
 	if (gt96100_check_tx_consistent(gp)) {
-		err(__FUNCTION__ ": Tx queue inconsistent!\n");
+		err("%s: Tx queue inconsistent!\n", __FUNCTION__);
 	}
     
 	if ((status & icrTxEndLow) && gp->tx_count != 0) {
 		// we must restart the DMA
-		dbg(3, __FUNCTION__ ": Restarting Tx DMA\n");
+		dbg(3, "%s: Restarting Tx DMA\n", __FUNCTION__);
 		GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
 				 sdcmrERD | sdcmrTXDL);
 	}
@@ -1421,11 +1415,11 @@
 	u32 status;
     
 	if (dev == NULL) {
-		err(__FUNCTION__ ": null dev ptr\n");
+		err("%s: null dev ptr\n", __FUNCTION__);
 		return;
 	}
 
-	dbg(3, __FUNCTION__ ": entry, icr=%x\n",
+	dbg(3, "%s: entry, icr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
 
 	spin_lock(&gp->lock);
@@ -1460,13 +1454,13 @@
 		
 				if ((psr & psrLink) && !gp->tx_full &&
 				    netif_queue_stopped(dev)) {
-					dbg(0, __FUNCTION__
-					    ": Link up, waking queue.\n");
+					dbg(0, ": Link up, waking queue.\n",
+					    __FUNCTION_);
 					netif_wake_queue(dev);
 				} else if (!(psr & psrLink) &&
 					   !netif_queue_stopped(dev)) {
-					dbg(0, __FUNCTION__
-					    "Link down, stopping queue.\n");
+					dbg(0, "Link down, stopping queue.\n",
+					    __FUNCTION__);
 					netif_stop_queue(dev);
 				}
 
@@ -1486,13 +1480,13 @@
 	
 		// Now check TX errors (RX errors were handled in gt96100_rx)
 		if (status & icrTxErrorLow) {
-			err(__FUNCTION__ ": Tx resource error\n");
+			err("%s: Tx resource error\n", __FUNCTION__);
 			if (--gp->intr_work_done == 0)
 				break;
 		}
 	
 		if (status & icrTxUdr) {
-			err(__FUNCTION__ ": Tx underrun error\n");
+			err("%s: Tx underrun error\n", __FUNCTION__);
 			if (--gp->intr_work_done == 0)
 				break;
 		}
@@ -1501,10 +1495,10 @@
 	if (gp->intr_work_done == 0) {
 		// ACK any remaining pending interrupts
 		GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0);
-		dbg(3, __FUNCTION__ ": hit max work\n");
+		dbg(3, "%s: hit max work\n", __FUNCTION__);
 	}
     
-	dbg(3, __FUNCTION__ ": exit, icr=%x\n",
+	dbg(3, "%s: exit, icr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
 
 	spin_unlock(&gp->lock);
@@ -1543,7 +1537,7 @@
 	unsigned long flags;
 	//struct dev_mc_list *mcptr;
     
-	dbg(3, __FUNCTION__ ": dev=%p, flags=%x\n", dev, dev->flags);
+	dbg(3, "%s: dev=%p, flags=%x\n", __FUNCTION__, dev, dev->flags);
 
 	// stop the Receiver DMA
 	abort(dev, sdcmrAR);
@@ -1586,7 +1580,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	unsigned long flags;
 
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	if (netif_device_present(dev)) {
 		spin_lock_irqsave (&gp->lock, flags);
diff -Nru a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h
--- a/drivers/net/gt96100eth.h	Fri Oct 11 21:22:54 2002
+++ b/drivers/net/gt96100eth.h	Fri Oct 11 21:22:54 2002
@@ -27,6 +27,7 @@
 #ifndef _GT96100ETH_H
 #define _GT96100ETH_H
 
+#include <linux/config.h>
 #include <asm/galileo-boards/gt96100.h>
 
 #define dbg(lvl, format, arg...) \
diff -Nru a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
--- a/drivers/net/ioc3-eth.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/net/ioc3-eth.c	Fri Oct 11 21:22:52 2002
@@ -26,6 +26,7 @@
  *    which workarounds are required for them?  Do we ever have Lucent's?
  *  o For the 2.5 branch kill the mii-tool ioctls.
  */
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
@@ -1275,10 +1276,10 @@
 
 	if (ip->rxr == NULL) {
 		/* Allocate and initialize rx ring.  4kb = 512 entries  */
-		ip->rxr = (unsigned long *) get_free_page(GFP_ATOMIC);
+		ip->rxr = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
 		rxr = (unsigned long *) ip->rxr;
 		if (!rxr)
-			printk("ioc3_alloc_rings(): get_free_page() failed!\n");
+			printk("ioc3_alloc_rings(): get_zeroed_page() failed!\n");
 
 		/* Now the rx buffers.  The RX ring may be larger but
 		   we only allocate 16 buffers for now.  Need to tune
@@ -1310,7 +1311,7 @@
 		/* Allocate and initialize tx rings.  16kb = 128 bufs.  */
 		ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2);
 		if (!ip->txr)
-			printk("ioc3_alloc_rings(): get_free_page() failed!\n");
+			printk("ioc3_alloc_rings(): __get_free_pages() failed!\n");
 		ip->tx_pi = 0;
 		ip->tx_ci = 0;
 	}
diff -Nru a/drivers/net/irda/Config.help b/drivers/net/irda/Config.help
--- a/drivers/net/irda/Config.help	Fri Oct 11 21:22:51 2002
+++ b/drivers/net/irda/Config.help	Fri Oct 11 21:22:51 2002
@@ -55,12 +55,22 @@
   <file:Documentation/modules.txt>.  The module will be called
   nsc-ircc.o.
 
-CONFIG_TOSHIBA_FIR
+CONFIG_TOSHIBA_OLD
   Say Y here if you want to build support for the Toshiba Type-O IR
   chipset.  This chipset is used by the Toshiba Libretto 100CT, and
-  many more laptops.  If you want to compile it as a module, say M
-  here and read <file:Documentation/modules.txt>.  The module will be
-  called toshoboe.o.
+  many more laptops. This driver is obsolete, will no more be
+  maintained and will be removed in favor of the new driver.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called toshoboe.o.
+
+CONFIG_TOSHIBA_FIR
+  Say Y here if you want to build support for the Toshiba Type-O IR
+  and Donau oboe chipsets. These chipsets are used by the Toshiba
+  Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called donauboe.o.
 
 CONFIG_SMC_IRCC_FIR
   Say Y here if you want to build support for the SMC Infrared
@@ -165,3 +175,18 @@
   the normal 9-pin serial port connector, and can currently only be
   used by IrTTY. To activate support for ACTiSYS IR-200L dongles
   you will have to start irattach like this: "irattach -d act200l".
+
+Mobile Action MA600 dongle (Experimental)
+CONFIG_MA600_DONGLE
+  Say Y here if you want to build support for the Mobile Action MA600
+  dongle.  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  The MA600 dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  tested on IrCOMM.  To activate support for MA600 dongles you will
+  have to insert "irattach -d ma600" in the /etc/irda/drivers script.
+  Note: irutils 0.9.15 requires no modification. irutils 0.9.9 needs
+  modification. For more information, download the following tar gzip
+  file.
+
+  There is a pre-compiled module on
+  <http://engsvr.ust.hk/~eetwl95/download/ma600-2.4.x.tar.gz>
diff -Nru a/drivers/net/irda/Config.in b/drivers/net/irda/Config.in
--- a/drivers/net/irda/Config.in	Fri Oct 11 21:23:03 2002
+++ b/drivers/net/irda/Config.in	Fri Oct 11 21:23:03 2002
@@ -28,6 +28,7 @@
 dep_tristate 'IrDA USB dongles (EXPERIMENTAL)' CONFIG_USB_IRDA $CONFIG_IRDA $CONFIG_USB $CONFIG_EXPERIMENTAL
 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 (old driver)' CONFIG_TOSHIBA_OLD $CONFIG_IRDA
 dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
 dep_tristate 'SMC IrCC (EXPERIMENTAL)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
diff -Nru a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
--- a/drivers/net/irda/Makefile	Fri Oct 11 21:22:57 2002
+++ b/drivers/net/irda/Makefile	Fri Oct 11 21:22:57 2002
@@ -13,7 +13,8 @@
 obj-$(CONFIG_NSC_FIR)		+= nsc-ircc.o
 obj-$(CONFIG_WINBOND_FIR)	+= w83977af_ir.o
 obj-$(CONFIG_SA1100_FIR)	+= sa1100_ir.o
-obj-$(CONFIG_TOSHIBA_FIR)	+= toshoboe.o
+obj-$(CONFIG_TOSHIBA_OLD)	+= toshoboe.o
+obj-$(CONFIG_TOSHIBA_FIR)	+= donauboe.o
 obj-$(CONFIG_SMC_IRCC_FIR)	+= smc-ircc.o	irport.o
 obj-$(CONFIG_ALI_FIR)		+= ali-ircc.o
 obj-$(CONFIG_VLSI_FIR)		+= vlsi_ir.o
diff -Nru a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/donauboe.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1850 @@
+/*****************************************************************
+ *
+ * Filename:		donauboe.c
+ * Version: 		2.17
+ * Description:   Driver for the Toshiba OBOE (or type-O or 701)
+ *                FIR Chipset, also supports the DONAUOBOE (type-DO
+ *                or d01) FIR chipset which as far as I know is
+ *                register compatible.
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * Modified:      Paul Bristow <paul.bristow@technologist.com>
+ * Modified:      Mon Nov 11 19:10:05 1999
+ * Modified:      James McKenzie <james@fishsoup.dhs.org>
+ * Modified:      Thu Mar 16 12:49:00 2000 (Substantial rewrite)
+ * Modified:      Sat Apr 29 00:23:03 2000 (Added DONAUOBOE support)
+ * Modified:      Wed May 24 23:45:02 2000 (Fixed chipio_t structure)
+ * Modified: 2.13 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.13 dim jan 07 21:57:39 2001 (tested with kernel 2.4 & irnet/ppp)
+ * Modified: 2.14 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.14 lun fev 05 17:55:59 2001 (adapted to patch-2.4.1-pre8-irda1)
+ * Modified: 2.15 Martin Lucina <mato@kotelna.sk>
+ * Modified: 2.15 Fri Jun 21 20:40:59 2002 (sync with 2.4.18, substantial fixes)
+ * Modified: 2.16 Martin Lucina <mato@kotelna.sk>
+ * Modified: 2.16 Sat Jun 22 18:54:29 2002 (fix freeregion, default to verbose)
+ * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.17 jeu sep 12 08:50:20 2002 (save_flags();cli(); replaced by spinlocks)
+ *
+ *     Copyright (c) 1999 James McKenzie, All Rights Reserved.
+ *
+ *     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.
+ *
+ *     Neither James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is
+ *     provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Libretto 100/110CT and many more.
+ *     Toshiba refers to this chip as the type-O IR port,
+ *     or the type-DO IR port.
+ *
+ ********************************************************************/
+
+/* Look at toshoboe.h (currently in include/net/irda) for details of */
+/* Where to get documentation on the chip         */
+
+
+static char *rcsid =
+  "$Id: donauboe.c V2.17 jeu sep 12 08:50:20 2002 $";
+
+/* See below for a description of the logic in this driver */
+
+/* Is irda_crc16_table[] exported? not yet */
+/* define this if you get errors about multiple defns of irda_crc16_table */
+#undef CRC_EXPORTED
+
+/* User servicable parts */
+/* Enable the code which probes the chip and does a few tests */
+/* Probe code is very useful for understanding how the hardware works */
+/* Use it with various combinations of TT_LEN, RX_LEN */
+/* Strongly recomended, disable if the probe fails on your machine */
+/* and send me <james@fishsoup.dhs.org> the output of dmesg */
+#define DO_PROBE 1
+
+/* Trace Transmit ring, interrupts, Receive ring or not ? */
+#define PROBE_VERBOSE 1
+
+/* Debug option, examine sent and received raw data */
+/* Irdadump is better, but does not see all packets. enable it if you want. */
+#undef DUMP_PACKETS
+
+/* MIR mode has not been tested. Some behaviour is different */
+/* Seems to work against an Ericsson R520 for me. -Martin */
+#define USE_MIR
+
+/* Schedule back to back hardware transmits wherever possible, otherwise */
+/* we need an interrupt for every frame, unset if oboe works for a bit and */
+/* then hangs */
+#define OPTIMIZE_TX
+
+/* Set the number of slots in the rings */
+/* If you get rx/tx fifo overflows at high bitrates, you can try increasing */
+/* these */
+
+#define RING_SIZE (OBOE_RING_SIZE_RX8 | OBOE_RING_SIZE_TX8)
+#define TX_SLOTS    8
+#define RX_SLOTS    8
+
+
+/* Less user servicable parts below here */
+
+/* Test, Transmit and receive buffer sizes, adjust at your peril */
+/* remarks: nfs usually needs 1k blocks */
+/* remarks: in SIR mode, CRC is received, -> RX_LEN=TX_LEN+2 */
+/* remarks: test accepts large blocks. Standard is 0x80 */
+/* When TT_LEN > RX_LEN (SIR mode) data is stored in successive slots. */
+/* When 3 or more slots are needed for each test packet, */
+/* data received in the first slots is overwritten, even */
+/* if OBOE_CTL_RX_HW_OWNS is not set, without any error! */
+#define TT_LEN      0x80
+#define TX_LEN      0xc00
+#define RX_LEN      0xc04
+/* Real transmitted length (SIR mode) is about 14+(2%*TX_LEN) more */
+/* long than user-defined length (see async_wrap_skb) and is less then 4K */
+/* Real received length is (max RX_LEN) differs from user-defined */
+/* length only b the CRC (2 or 4 bytes) */
+#define BUF_SAFETY  0x7a
+#define RX_BUF_SZ   (RX_LEN)
+#define TX_BUF_SZ   (TX_LEN+BUF_SAFETY)
+
+
+/* Logic of the netdev part of this driver                             */
+
+/* The RX ring is filled with buffers, when a packet arrives           */
+/* it is DMA'd into the buffer which is marked used and RxDone called  */
+/* RxDone forms an skb (and checks the CRC if in SIR mode) and ships   */
+/* the packet off upstairs */
+
+/* The transmitter on the oboe chip can work in one of two modes       */
+/* for each ring->tx[] the transmitter can either                      */
+/* a) transmit the packet, leave the trasmitter enabled and proceed to */
+/*    the next ring                                                    */
+/* OR                                                                  */
+/* b) transmit the packet, switch off the transmitter and issue TxDone */
+
+/* All packets are entered into the ring in mode b), if the ring was   */
+/* empty the transmitter is started.                                   */
+
+/* If OPTIMIZE_TX is defined then in TxDone if the ring contains       */
+/* more than one packet, all but the last are set to mode a) [HOWEVER  */
+/* the hardware may not notice this, this is why we start in mode b) ] */
+/* then restart the transmitter                                        */
+
+/* If OPTIMIZE_TX is not defined then we just restart the transmitter  */
+/* if the ring isn't empty */
+
+/* Speed changes are delayed until the TxRing is empty                 */
+/* mtt is handled by generating packets with bad CRCs, before the data */
+
+/* TODO: */
+/* check the mtt works ok      */
+/* finish the watchdog         */
+
+/* No user servicable parts below here */
+
+#define STATIC static
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+//#include <net/irda/irmod.h>
+//#include <net/irda/irlap_frame.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/crc.h>
+
+#include "donauboe.h"
+
+#define INB(port)       inb_p(port)
+#define OUTB(val,port)  outb_p(val,port)
+#define OUTBP(val,port) outb_p(val,port)
+
+#define PROMPT  OUTB(OBOE_PROMPT_BIT,OBOE_PROMPT);
+
+#if PROBE_VERBOSE
+#define PROBE_DEBUG(args...) (printk (args))
+#else
+#define PROBE_DEBUG(args...) ;
+#endif
+
+/* Set the DMA to be byte at a time */
+#define CONFIG0H_DMA_OFF OBOE_CONFIG0H_RCVANY
+#define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC
+#define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX
+
+static struct pci_device_id toshoboe_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl);
+
+#define DRIVER_NAME "toshoboe"
+static char *driver_name = DRIVER_NAME;
+
+static int max_baud = 4000000;
+static int do_probe = DO_PROBE;
+
+
+/**********************************************************************/
+/* Fcs code */
+
+#ifdef CRC_EXPORTED
+extern __u16 const irda_crc16_table[];
+#else
+static __u16 const irda_crc16_table[256] = {
+  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+#endif
+
+STATIC int
+toshoboe_checkfcs (unsigned char *buf, int len)
+{
+  int i;
+  union
+  {
+    __u16 value;
+    __u8 bytes[2];
+  }
+  fcs;
+
+  fcs.value = INIT_FCS;
+
+  for (i = 0; i < len; ++i)
+    fcs.value = irda_fcs (fcs.value, *(buf++));
+
+  return (fcs.value == GOOD_FCS);
+}
+
+/***********************************************************************/
+/* Generic chip handling code */
+#ifdef DUMP_PACKETS
+static unsigned char dump[50];
+STATIC void 
+_dumpbufs (unsigned char *data, int len, char tete)
+{
+int i,j;
+char head=tete;
+for (i=0;i<len;i+=16) {
+    for (j=0;j<16 && i+j<len;j++) { sprintf(&dump[3*j],"%02x.",data[i+j]); }
+    dump [3*j]=0;
+    IRDA_DEBUG (2, "%c%s\n",head , dump);
+    head='+'; 
+    }
+}
+#endif
+
+/* Dump the registers */
+STATIC void
+toshoboe_dumpregs (struct toshoboe_cb *self)
+{
+  __u32 ringbase;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ringbase = INB (OBOE_RING_BASE0) << 10;
+  ringbase |= INB (OBOE_RING_BASE1) << 18;
+  ringbase |= INB (OBOE_RING_BASE2) << 26;
+
+  printk (KERN_ERR DRIVER_NAME ": Register dump:\n");
+  printk (KERN_ERR "Interrupts: Tx:%d Rx:%d TxUnder:%d RxOver:%d Sip:%d\n",
+          self->int_tx, self->int_rx, self->int_txunder, self->int_rxover,
+          self->int_sip);
+  printk (KERN_ERR "RX %02x TX %02x RingBase %08x\n",
+          INB (OBOE_RXSLOT), INB (OBOE_TXSLOT), ringbase);
+  printk (KERN_ERR "RING_SIZE %02x IER %02x ISR %02x\n",
+          INB (OBOE_RING_SIZE), INB (OBOE_IER), INB (OBOE_ISR));
+  printk (KERN_ERR "CONFIG1 %02x STATUS %02x\n",
+          INB (OBOE_CONFIG1), INB (OBOE_STATUS));
+  printk (KERN_ERR "CONFIG0 %02x%02x ENABLE %02x%02x\n",
+          INB (OBOE_CONFIG0H), INB (OBOE_CONFIG0L),
+          INB (OBOE_ENABLEH), INB (OBOE_ENABLEL));
+  printk (KERN_ERR "NEW_PCONFIG %02x%02x CURR_PCONFIG %02x%02x\n",
+          INB (OBOE_NEW_PCONFIGH), INB (OBOE_NEW_PCONFIGL),
+          INB (OBOE_CURR_PCONFIGH), INB (OBOE_CURR_PCONFIGL));
+  printk (KERN_ERR "MAXLEN %02x%02x RXCOUNT %02x%02x\n",
+          INB (OBOE_MAXLENH), INB (OBOE_MAXLENL),
+          INB (OBOE_RXCOUNTL), INB (OBOE_RXCOUNTH));
+
+  if (self->ring)
+    {
+      int i;
+      ringbase = virt_to_bus (self->ring);
+      printk (KERN_ERR "Ring at %08x:\n", ringbase);
+      printk (KERN_ERR "RX:");
+      for (i = 0; i < RX_SLOTS; ++i)
+        printk (" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control);
+      printk ("\n");
+      printk (KERN_ERR "TX:");
+      for (i = 0; i < RX_SLOTS; ++i)
+        printk (" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control);
+      printk ("\n");
+    }
+}
+
+/*Don't let the chip look at memory */
+STATIC void
+toshoboe_disablebm (struct toshoboe_cb *self)
+{
+  __u8 command;
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
+  command &= ~PCI_COMMAND_MASTER;
+  pci_write_config_byte (self->pdev, PCI_COMMAND, command);
+
+}
+
+/* Shutdown the chip and point the taskfile reg somewhere else */
+STATIC void
+toshoboe_stopchip (struct toshoboe_cb *self)
+{
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  /*Disable interrupts */
+  OUTB (0x0, OBOE_IER);
+  /*Disable DMA, Disable Rx, Disable Tx */
+  OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
+  /*Disable SIR MIR FIR, Tx and Rx */
+  OUTB (0x00, OBOE_ENABLEH);
+  /*Point the ring somewhere safe */
+  OUTB (0x3f, OBOE_RING_BASE2);
+  OUTB (0xff, OBOE_RING_BASE1);
+  OUTB (0xff, OBOE_RING_BASE0);
+
+  OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+  OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+
+  /*Acknoledge any pending interrupts */
+  OUTB (0xff, OBOE_ISR);
+
+  /*Why */
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  /*switch it off */
+  OUTB (OBOE_CONFIG1_OFF, OBOE_CONFIG1);
+
+  toshoboe_disablebm (self);
+}
+
+/* Transmitter initialization */
+STATIC void
+toshoboe_start_DMA (struct toshoboe_cb *self, int opts)
+{
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTB (CONFIG0H_DMA_ON | opts,  OBOE_CONFIG0H);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+  PROMPT;
+}
+
+/*Set the baud rate */
+STATIC void
+toshoboe_setbaud (struct toshoboe_cb *self)
+{
+  __u16 pconfig = 0;
+  __u8 config0l = 0;
+
+  IRDA_DEBUG (2, "%s(%d/%d)\n", __FUNCTION__, self->speed, self->io.speed);
+
+  switch (self->speed)
+    {
+    case 2400:
+    case 4800:
+    case 9600:
+    case 19200:
+    case 38400:
+    case 57600:
+    case 115200:
+#ifdef USE_MIR
+    case 1152000:
+#endif
+    case 4000000:
+      break;
+    default:
+
+      printk (KERN_ERR DRIVER_NAME ": switch to unsupported baudrate %d\n",
+              self->speed);
+      return;
+    }
+
+  switch (self->speed)
+    {
+      /* For SIR the preamble is done by adding XBOFs */
+      /* to the packet */
+      /* set to filtered SIR mode, filter looks for BOF and EOF */
+    case 2400:
+      pconfig |= 47 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 4800:
+      pconfig |= 23 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 9600:
+      pconfig |= 11 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 19200:
+      pconfig |= 5 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 38400:
+      pconfig |= 2 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 57600:
+      pconfig |= 1 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 115200:
+      pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    default:
+      /*Set to packet based reception */
+      OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+      OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+      break;
+    }
+
+  switch (self->speed)
+    {
+    case 2400:
+    case 4800:
+    case 9600:
+    case 19200:
+    case 38400:
+    case 57600:
+    case 115200:
+      config0l = OBOE_CONFIG0L_ENSIR;
+      if (self->async)
+        {
+          /*Set to character based reception */
+          /*System will lock if MAXLEN=0 */
+          /*so have to be careful */
+          OUTB (0x01, OBOE_MAXLENH);
+          OUTB (0x01, OBOE_MAXLENL);
+          OUTB (0x00, OBOE_MAXLENH);
+        }
+      else
+        {
+          /*Set to packet based reception */
+          config0l |= OBOE_CONFIG0L_ENSIRF;
+          OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+          OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+        }
+      break;
+
+#ifdef USE_MIR
+      /* MIR mode */
+      /* Set for 16 bit CRC and enable MIR */
+      /* Preamble now handled by the chip */
+    case 1152000:
+      pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 8 << OBOE_PCONFIG_WIDTHSHIFT;
+      pconfig |= 1 << OBOE_PCONFIG_PREAMBLESHIFT;
+      config0l = OBOE_CONFIG0L_CRC16 | OBOE_CONFIG0L_ENMIR;
+      break;
+#endif
+      /* FIR mode */
+      /* Set for 32 bit CRC and enable FIR */
+      /* Preamble handled by the chip */
+    case 4000000:
+      pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
+      /* Documentation says 14, but toshiba use 15 in their drivers */
+      pconfig |= 15 << OBOE_PCONFIG_PREAMBLESHIFT;
+      config0l = OBOE_CONFIG0L_ENFIR;
+      break;
+    }
+
+  /* Copy into new PHY config buffer */
+  OUTBP (pconfig >> 8, OBOE_NEW_PCONFIGH);
+  OUTB (pconfig & 0xff, OBOE_NEW_PCONFIGL);
+  OUTB (config0l, OBOE_CONFIG0L);
+
+  /* Now make OBOE copy from new PHY to current PHY */
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+  PROMPT;
+
+  /* speed change executed */
+  self->new_speed = 0;
+  self->io.speed = self->speed;
+}
+
+/*Let the chip look at memory */
+STATIC void
+toshoboe_enablebm (struct toshoboe_cb *self)
+{
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+  pci_set_master (self->pdev);
+}
+
+/*setup the ring */
+STATIC void
+toshoboe_initring (struct toshoboe_cb *self)
+{
+  int i;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->ring->tx[i].len = 0;
+      self->ring->tx[i].control = 0x00;
+      self->ring->tx[i].address = virt_to_bus (self->tx_bufs[i]);
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->ring->rx[i].len = RX_LEN;
+      self->ring->rx[i].len = 0;
+      self->ring->rx[i].address = virt_to_bus (self->rx_bufs[i]);
+      self->ring->rx[i].control = OBOE_CTL_RX_HW_OWNS;
+    }
+}
+
+STATIC void
+toshoboe_resetptrs (struct toshoboe_cb *self)
+{
+  /* Can reset pointers by twidling DMA */
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTBP (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  self->rxs = inb_p (OBOE_RXSLOT) & OBOE_SLOT_MASK;
+  self->txs = inb_p (OBOE_TXSLOT) & OBOE_SLOT_MASK;
+}
+
+/* Called in locked state */
+STATIC void
+toshoboe_initptrs (struct toshoboe_cb *self)
+{
+
+  /* spin_lock_irqsave(self->spinlock, flags); */
+  /* save_flags (flags); */
+
+  /* Can reset pointers by twidling DMA */
+  toshoboe_resetptrs (self);
+
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  self->txpending = 0;
+
+  /* spin_unlock_irqrestore(self->spinlock, flags); */
+  /* restore_flags (flags); */
+}
+
+/* Wake the chip up and get it looking at the rings */
+/* Called in locked state */
+STATIC void
+toshoboe_startchip (struct toshoboe_cb *self)
+{
+  __u32 physaddr;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  toshoboe_initring (self);
+  toshoboe_enablebm (self);
+  OUTBP (OBOE_CONFIG1_RESET, OBOE_CONFIG1);
+  OUTBP (OBOE_CONFIG1_ON, OBOE_CONFIG1);
+
+  /* Stop the clocks */
+  OUTB (0, OBOE_ENABLEH);
+
+  /*Set size of rings */
+  OUTB (RING_SIZE, OBOE_RING_SIZE);
+
+  /*Acknoledge any pending interrupts */
+  OUTB (0xff, OBOE_ISR);
+
+  /*Enable ints */
+  OUTB (OBOE_INT_TXDONE  | OBOE_INT_RXDONE |
+        OBOE_INT_TXUNDER | OBOE_INT_RXOVER | OBOE_INT_SIP , OBOE_IER);
+
+  /*Acknoledge any pending interrupts */
+  OUTB (0xff, OBOE_ISR);
+
+  /*Set the maximum packet length to 0xfff (4095) */
+  OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+  OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+
+  /*Shutdown DMA */
+  OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
+
+  /*Find out where the rings live */
+  physaddr = virt_to_bus (self->ring);
+
+  ASSERT ((physaddr & 0x3ff) == 0,
+          printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n");
+          return;);
+
+  OUTB ((physaddr >> 10) & 0xff, OBOE_RING_BASE0);
+  OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1);
+  OUTB ((physaddr >> 26) & 0x3f, OBOE_RING_BASE2);
+
+  /*Enable DMA controler in byte mode and RX */
+  OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H);
+
+  /* Start up the clocks */
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  /*set to sensible speed */
+  self->speed = 9600;
+  toshoboe_setbaud (self);
+  toshoboe_initptrs (self);
+}
+
+STATIC void
+toshoboe_isntstuck (struct toshoboe_cb *self)
+{
+}
+
+STATIC void
+toshoboe_checkstuck (struct toshoboe_cb *self)
+{
+  unsigned long flags;
+
+  if (0)
+    {
+      spin_lock_irqsave(&self->spinlock, flags);
+
+      /* This will reset the chip completely */
+      printk (KERN_ERR DRIVER_NAME ": Resetting chip\n");
+
+      toshoboe_stopchip (self);
+      toshoboe_startchip (self);
+      spin_unlock_irqrestore(&self->spinlock, flags);
+    }
+}
+
+/*Generate packet of about mtt us long */
+STATIC int
+toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt)
+{
+  int xbofs;
+
+  xbofs = ((int) (mtt/100)) * (int) (self->speed);
+  xbofs=xbofs/80000; /*Eight bits per byte, and mtt is in us*/
+  xbofs++;
+
+  IRDA_DEBUG (2, DRIVER_NAME 
+      ": generated mtt of %d bytes for %d us at %d baud\n"
+	  , xbofs,mtt,self->speed);
+
+  if (xbofs > TX_LEN)
+    {
+      printk (KERN_ERR DRIVER_NAME ": wanted %d bytes MTT but TX_LEN is %d\n",
+              xbofs, TX_LEN);
+      xbofs = TX_LEN;
+    }
+
+  /*xbofs will do for SIR, MIR and FIR,SIR mode doesn't generate a checksum anyway */
+  memset (buf, XBOF, xbofs);
+
+  return xbofs;
+}
+
+/***********************************************************************/
+/* Probe code */
+
+STATIC void
+toshoboe_dumptx (struct toshoboe_cb *self)
+{
+  int i;
+  PROBE_DEBUG(KERN_WARNING "TX:");
+  for (i = 0; i < RX_SLOTS; ++i)
+    PROBE_DEBUG(" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control);
+  PROBE_DEBUG(" [%d]\n",self->speed);
+}
+
+STATIC void
+toshoboe_dumprx (struct toshoboe_cb *self, int score)
+{
+  int i;
+  PROBE_DEBUG(" %d\nRX:",score);
+  for (i = 0; i < RX_SLOTS; ++i)
+    PROBE_DEBUG(" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control);
+  PROBE_DEBUG("\n");
+}
+
+static inline int
+stuff_byte (__u8 byte, __u8 * buf)
+{
+  switch (byte)
+    {
+    case BOF:                  /* FALLTHROUGH */
+    case EOF:                  /* FALLTHROUGH */
+    case CE:
+      /* Insert transparently coded */
+      buf[0] = CE;              /* Send link escape */
+      buf[1] = byte ^ IRDA_TRANS; /* Complement bit 5 */
+      return 2;
+      /* break; */
+    default:
+      /* Non-special value, no transparency required */
+      buf[0] = byte;
+      return 1;
+      /* break; */
+    }
+}
+
+STATIC int toshoboe_invalid_dev(int irq) 
+{
+  printk (KERN_WARNING DRIVER_NAME ": irq %d for unknown device.\n", irq);
+  return 1;
+}
+
+STATIC void
+toshoboe_probeinterrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
+  __u8 irqstat;
+
+  if (self == NULL && toshoboe_invalid_dev(irq)) 
+    return;
+
+  irqstat = INB (OBOE_ISR);
+
+/* was it us */
+  if (!(irqstat & OBOE_INT_MASK))
+    return;
+
+/* Ack all the interrupts */
+  OUTB (irqstat, OBOE_ISR);
+
+  if (irqstat & OBOE_INT_TXDONE)
+    {
+      int txp;
+
+      self->int_tx++;
+      PROBE_DEBUG("T");
+
+      txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK;
+      if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS)
+        {
+          self->int_tx+=100;
+          PROBE_DEBUG("S");
+          toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+        }
+    }
+
+  if (irqstat & OBOE_INT_RXDONE) {
+    self->int_rx++;
+    PROBE_DEBUG("R"); }
+  if (irqstat & OBOE_INT_TXUNDER) {
+    self->int_txunder++;
+    PROBE_DEBUG("U"); }
+  if (irqstat & OBOE_INT_RXOVER) {
+    self->int_rxover++;
+    PROBE_DEBUG("O"); }
+  if (irqstat & OBOE_INT_SIP) {
+    self->int_sip++;
+    PROBE_DEBUG("I"); }
+}
+
+STATIC int
+toshoboe_maketestpacket (unsigned char *buf, int badcrc, int fir)
+{
+  int i;
+  int len = 0;
+  union
+  {
+    __u16 value;
+    __u8 bytes[2];
+  }
+  fcs;
+
+  if (fir)
+    {
+      memset (buf, 0, TT_LEN);
+      return (TT_LEN);
+    }
+
+  fcs.value = INIT_FCS;
+
+  memset (buf, XBOF, 10);
+  len += 10;
+  buf[len++] = BOF;
+
+  for (i = 0; i < TT_LEN; ++i)
+    {
+      len += stuff_byte (i, buf + len);
+      fcs.value = irda_fcs (fcs.value, i);
+    }
+
+  len += stuff_byte (fcs.bytes[0] ^ badcrc, buf + len);
+  len += stuff_byte (fcs.bytes[1] ^ badcrc, buf + len);
+  buf[len++] = EOF;
+  len++;
+  return len;
+}
+
+STATIC int
+toshoboe_probefail (struct toshoboe_cb *self, char *msg)
+{
+  printk (KERN_ERR DRIVER_NAME "probe(%d) failed %s\n",self-> speed, msg);
+  toshoboe_dumpregs (self);
+  toshoboe_stopchip (self);
+  free_irq (self->io.irq, (void *) self);
+  return 0;
+}
+
+STATIC int
+toshoboe_numvalidrcvs (struct toshoboe_cb *self)
+{
+  int i, ret = 0;
+  for (i = 0; i < RX_SLOTS; ++i)
+    if ((self->ring->rx[i].control & 0xe0) == 0)
+      ret++;
+
+  return ret;
+}
+
+STATIC int
+toshoboe_numrcvs (struct toshoboe_cb *self)
+{
+  int i, ret = 0;
+  for (i = 0; i < RX_SLOTS; ++i)
+    if (!(self->ring->rx[i].control & OBOE_CTL_RX_HW_OWNS))
+      ret++;
+
+  return ret;
+}
+
+STATIC int
+toshoboe_probe (struct toshoboe_cb *self)
+{
+  int i, j, n;
+#ifdef USE_MIR
+  int bauds[] = { 9600, 115200, 4000000, 1152000 };
+#else
+  int bauds[] = { 9600, 115200, 4000000 };
+#endif
+  unsigned long flags;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if (request_irq (self->io.irq, toshoboe_probeinterrupt,
+                   self->io.irqflags, "toshoboe", (void *) self))
+    {
+      printk (KERN_ERR DRIVER_NAME ": probe failed to allocate irq %d\n",
+              self->io.irq);
+      return 0;
+    }
+
+  /* test 1: SIR filter and back to back */
+
+  for (j = 0; j < (sizeof (bauds) / sizeof (int)); ++j)
+    {
+      int fir = (j > 1);
+      toshoboe_stopchip (self);
+
+
+      spin_lock_irqsave(&self->spinlock, flags);
+      /*Address is already setup */
+      toshoboe_startchip (self);
+      self->int_rx = self->int_tx = 0;
+      self->speed = bauds[j];
+      toshoboe_setbaud (self);
+      toshoboe_initptrs (self);
+      spin_unlock_irqrestore(&self->spinlock, flags); 
+
+      self->ring->tx[self->txs].control =
+/*   (FIR only) OBOE_CTL_TX_SIP needed for switching to next slot */
+/*    MIR: all received data is stored in one slot */
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
+              : OBOE_CTL_TX_HW_OWNS ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      self->ring->tx[self->txs].control =
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_SIP
+              : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      self->ring->tx[self->txs].control = 
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
+              : OBOE_CTL_TX_HW_OWNS ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      self->ring->tx[self->txs].control =
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
+              | OBOE_CTL_TX_SIP     | OBOE_CTL_TX_BAD_CRC
+              : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      toshoboe_dumptx (self);
+      /* Turn on TX and RX and loopback */
+      toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+
+      i = 0;
+      n = fir ? 1 : 4;
+      while (toshoboe_numvalidrcvs (self) != n)
+        {
+          if (i > 4800)
+              return toshoboe_probefail (self, "filter test");
+          udelay ((9600*(TT_LEN+16))/self->speed);
+          i++;
+        }
+
+      n = fir ? 203 : 102;
+      while ((toshoboe_numrcvs(self) != self->int_rx) || (self->int_tx != n))
+        {
+          if (i > 4800)
+              return toshoboe_probefail (self, "interrupt test");
+          udelay ((9600*(TT_LEN+16))/self->speed);
+          i++;
+        }
+     toshoboe_dumprx (self,i);
+
+     }
+
+  /* test 2: SIR in char at a time */
+
+  toshoboe_stopchip (self);
+  self->int_rx = self->int_tx = 0;
+
+  spin_lock_irqsave(&self->spinlock, flags);
+  toshoboe_startchip (self);
+  spin_unlock_irqrestore(&self->spinlock, flags);
+
+  self->async = 1;
+  self->speed = 115200;
+  toshoboe_setbaud (self);
+  self->ring->tx[self->txs].control =
+    OBOE_CTL_TX_RTCENTX | OBOE_CTL_TX_HW_OWNS;
+  self->ring->tx[self->txs].len = 4;
+
+  ((unsigned char *) self->tx_bufs[self->txs])[0] = 'f';
+  ((unsigned char *) self->tx_bufs[self->txs])[1] = 'i';
+  ((unsigned char *) self->tx_bufs[self->txs])[2] = 's';
+  ((unsigned char *) self->tx_bufs[self->txs])[3] = 'h';
+  toshoboe_dumptx (self);
+  toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+
+  i = 0;
+  while (toshoboe_numvalidrcvs (self) != 4)
+    {
+      if (i > 100)
+          return toshoboe_probefail (self, "Async test");
+      udelay (100);
+      i++;
+    }
+
+  while ((toshoboe_numrcvs (self) != self->int_rx) || (self->int_tx != 1))
+    {
+      if (i > 100)
+          return toshoboe_probefail (self, "Async interrupt test");
+      udelay (100);
+      i++;
+    }
+  toshoboe_dumprx (self,i);
+
+  self->async = 0;
+  self->speed = 9600;
+  toshoboe_setbaud (self);
+  toshoboe_stopchip (self);
+
+  free_irq (self->io.irq, (void *) self);
+
+  printk (KERN_WARNING DRIVER_NAME ": Self test passed ok\n");
+
+  return 1;
+}
+
+/******************************************************************/
+/* Netdev style code */
+
+/* Transmit something */
+STATIC int
+toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+  struct toshoboe_cb *self;
+  __s32 speed;
+  int mtt, len, ctl;
+  unsigned long flags;
+  struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
+
+  self = (struct toshoboe_cb *) dev->priv;
+
+  ASSERT (self != NULL, return 0; );
+
+  IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __FUNCTION__ 
+      ,skb->len,self->txpending,INB (OBOE_ENABLEH));
+  if (!cb->magic) {
+      IRDA_DEBUG (2, "%s.Not IrLAP:%x\n", __FUNCTION__, cb->magic);
+#ifdef DUMP_PACKETS
+      _dumpbufs(skb->data,skb->len,'>'); 
+#endif
+    }
+
+  /* change speed pending, wait for its execution */
+  if (self->new_speed)
+      return -EBUSY;
+
+  /* device stopped (apm) wait for restart */
+  if (self->stopped)
+      return -EBUSY;
+
+  toshoboe_checkstuck (self);
+
+  /* Check if we need to change the speed */
+  /* But not now. Wait after transmission if mtt not required */
+  speed=irda_get_next_speed(skb);
+  if ((speed != self->io.speed) && (speed != -1))
+    {
+      spin_lock_irqsave(&self->spinlock, flags);
+
+      if (self->txpending || skb->len)
+        {
+          self->new_speed = speed;
+          IRDA_DEBUG (1, "%s: Queued TxDone scheduled speed change %d\n" ,
+		      __FUNCTION__, speed);
+          /* if no data, that's all! */
+          if (!skb->len) 
+            {
+	      spin_unlock_irqrestore(&self->spinlock, flags);
+              dev_kfree_skb (skb);
+              return 0;
+            }
+          /* True packet, go on, but */
+          /* do not accept anything before change speed execution */
+          netif_stop_queue(dev); 
+          /* ready to process TxDone interrupt */
+	  spin_unlock_irqrestore(&self->spinlock, flags);
+        }
+      else
+        { 
+          /* idle and no data, change speed now */
+          self->speed = speed;
+          toshoboe_setbaud (self);
+	  spin_unlock_irqrestore(&self->spinlock, flags);
+          dev_kfree_skb (skb);
+          return 0;
+        }
+
+    }
+
+  if ((mtt = irda_get_mtt(skb)))
+    {
+      /* This is fair since the queue should be empty anyway */
+      spin_lock_irqsave(&self->spinlock, flags);
+
+      if (self->txpending)
+        {
+	  spin_unlock_irqrestore(&self->spinlock, flags);
+          return -EBUSY;
+        }
+
+      /* If in SIR mode we need to generate a string of XBOFs */
+      /* In MIR and FIR we need to generate a string of data */
+      /* which we will add a wrong checksum to */
+
+      mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt);
+      IRDA_DEBUG (1, "%s.mtt:%x(%x)%d\n", __FUNCTION__ 
+          ,skb->len,mtt,self->txpending);
+      if (mtt)
+        {
+          self->ring->tx[self->txs].len = mtt & 0xfff;
+
+          ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX;
+          if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON)
+            {
+              ctl |= OBOE_CTL_TX_BAD_CRC | OBOE_CTL_TX_SIP ;
+            }
+#ifdef USE_MIR
+          else if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_MIRON)
+            {
+              ctl |= OBOE_CTL_TX_BAD_CRC;
+            }
+#endif
+          self->ring->tx[self->txs].control = ctl;
+
+          OUTB (0x0, OBOE_ENABLEH);
+          /* It is only a timer. Do not send mtt packet outside! */
+          toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+
+          self->txpending++;
+
+          self->txs++;
+          self->txs %= TX_SLOTS;
+
+        }
+      else
+        {
+          printk(KERN_ERR DRIVER_NAME ": problem with mtt packet - ignored\n");
+        }
+      spin_unlock_irqrestore(&self->spinlock, flags);
+    }
+
+#ifdef DUMP_PACKETS
+dumpbufs(skb->data,skb->len,'>'); 
+#endif
+
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS)
+    {
+      IRDA_DEBUG (0, "%s.ful:%x(%x)%x\n", __FUNCTION__
+          ,skb->len, self->ring->tx[self->txs].control, self->txpending);
+      toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
+      spin_unlock_irqrestore(&self->spinlock, flags);
+      return -EBUSY;
+    }
+
+  if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON)
+    {
+      len = async_wrap_skb (skb, self->tx_bufs[self->txs], TX_BUF_SZ);
+    }
+  else
+    {
+      len = skb->len;
+      memcpy (self->tx_bufs[self->txs], skb->data, len);
+    }
+  self->ring->tx[self->txs].len = len & 0x0fff;
+
+  /*Sometimes the HW doesn't see us assert RTCENTX in the interrupt code */
+  /*later this plays safe, we garuntee the last packet to be transmitted */
+  /*has RTCENTX set */
+
+  ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX;
+  if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON)
+    {
+      ctl |= OBOE_CTL_TX_SIP ;
+    }
+  self->ring->tx[self->txs].control = ctl;
+
+  /* If transmitter is idle start in one-shot mode */
+
+  if (!self->txpending)
+      toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
+
+  self->txpending++;
+
+  self->txs++;
+  self->txs %= TX_SLOTS;
+
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  dev_kfree_skb (skb);
+
+  return 0;
+}
+
+/*interrupt handler */
+STATIC void
+toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
+  __u8 irqstat;
+  struct sk_buff *skb = NULL;
+
+  if (self == NULL && toshoboe_invalid_dev(irq)) 
+    return;
+
+  irqstat = INB (OBOE_ISR);
+
+/* was it us */
+  if (!(irqstat & OBOE_INT_MASK))
+      return;
+
+/* Ack all the interrupts */
+  OUTB (irqstat, OBOE_ISR);
+
+  toshoboe_isntstuck (self);
+
+/* Txdone */
+  if (irqstat & OBOE_INT_TXDONE)
+    {
+      int txp, txpc;
+      int i;
+
+      txp = self->txpending;
+      self->txpending = 0;
+
+      for (i = 0; i < TX_SLOTS; ++i)
+        {
+          if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS)
+              self->txpending++;
+        }
+      IRDA_DEBUG (1, "%s.txd(%x)%x/%x\n", __FUNCTION__
+          ,irqstat,txp,self->txpending);
+
+      txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK;
+
+      /* Got anything queued ? start it together */
+      if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS)
+        {
+          txpc = txp;
+#ifdef OPTIMIZE_TX
+          while (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS)
+            {
+              txp = txpc;
+              txpc++;
+              txpc %= TX_SLOTS;
+              self->stats.tx_packets++;
+              if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS)
+                  self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX;
+            }
+          self->stats.tx_packets--;
+#else
+          self->stats.tx_packets++;
+#endif
+          toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
+        }
+
+      if ((!self->txpending) && (self->new_speed))
+        {
+          self->speed = self->new_speed;
+          IRDA_DEBUG (1, "%s: Executed TxDone scheduled speed change %d\n",
+		      __FUNCTION__, self->speed);
+          toshoboe_setbaud (self);
+        }
+
+      /* Tell network layer that we want more frames */
+      if (!self->new_speed)
+          netif_wake_queue(self->netdev);
+    }
+
+  if (irqstat & OBOE_INT_RXDONE)
+    {
+      while (!(self->ring->rx[self->rxs].control & OBOE_CTL_RX_HW_OWNS))
+        {
+          int len = self->ring->rx[self->rxs].len;
+          skb = NULL;
+          IRDA_DEBUG (3, "%s.rcv:%x(%x)\n", __FUNCTION__ 
+		      ,len,self->ring->rx[self->rxs].control);
+
+#ifdef DUMP_PACKETS
+dumpbufs(self->rx_bufs[self->rxs],len,'<');
+#endif
+
+          if (self->ring->rx[self->rxs].control == 0)
+            {
+              __u8 enable = INB (OBOE_ENABLEH);
+
+              /* In SIR mode we need to check the CRC as this */
+              /* hasn't been done by the hardware */
+              if (enable & OBOE_ENABLEH_SIRON)
+                {
+                  if (!toshoboe_checkfcs (self->rx_bufs[self->rxs], len))
+                      len = 0;
+                  /*Trim off the CRC */
+                  if (len > 1)
+                      len -= 2;
+                  else
+                      len = 0;
+                  IRDA_DEBUG (1, "%s.SIR:%x(%x)\n", __FUNCTION__, len,enable);
+                }
+
+#ifdef USE_MIR
+              else if (enable & OBOE_ENABLEH_MIRON)
+                {
+                  if (len > 1)
+                      len -= 2;
+                  else
+                      len = 0;
+                  IRDA_DEBUG (2, "%s.MIR:%x(%x)\n", __FUNCTION__, len,enable);
+                }
+#endif
+              else if (enable & OBOE_ENABLEH_FIRON)
+                {
+                  if (len > 3)
+                      len -= 4;   /*FIXME: check this */
+                  else
+                      len = 0;
+                  IRDA_DEBUG (1, "%s.FIR:%x(%x)\n", __FUNCTION__, len,enable);
+                }
+              else 
+                  IRDA_DEBUG (0, "%s.?IR:%x(%x)\n", __FUNCTION__, len,enable);
+
+              if (len)
+                {
+                  skb = dev_alloc_skb (len + 1);
+                  if (skb)
+                    {
+                      skb_reserve (skb, 1);
+
+                      skb_put (skb, len);
+                      memcpy (skb->data, self->rx_bufs[self->rxs], len);
+
+                      self->stats.rx_packets++;
+                      skb->dev = self->netdev;
+                      skb->mac.raw = skb->data;
+                      skb->protocol = htons (ETH_P_IRDA);
+                    }
+                  else
+                    {
+                      printk (KERN_INFO 
+                              "%s(), memory squeeze, dropping frame.\n",
+			      __FUNCTION__);
+                    }
+                }
+            }
+          else 
+            {
+            /* TODO: =========================================== */
+            /*  if OBOE_CTL_RX_LENGTH, our buffers are too small */
+            /* (MIR or FIR) data is lost. */
+            /* (SIR) data is splitted in several slots. */
+            /* we have to join all the received buffers received */
+            /*in a large buffer before checking CRC. */
+            IRDA_DEBUG (0, "%s.err:%x(%x)\n", __FUNCTION__
+                ,len,self->ring->rx[self->rxs].control);
+            }
+
+          self->ring->rx[self->rxs].len = 0x0;
+          self->ring->rx[self->rxs].control = OBOE_CTL_RX_HW_OWNS;
+
+          self->rxs++;
+          self->rxs %= RX_SLOTS;
+
+          if (skb)
+              netif_rx (skb);
+
+        }
+    }
+
+  if (irqstat & OBOE_INT_TXUNDER)
+    {
+      printk (KERN_WARNING DRIVER_NAME ": tx fifo underflow\n");
+    }
+  if (irqstat & OBOE_INT_RXOVER)
+    {
+      printk (KERN_WARNING DRIVER_NAME ": rx fifo overflow\n");
+    }
+/* This must be useful for something... */
+  if (irqstat & OBOE_INT_SIP)
+    {
+      self->int_sip++;
+      IRDA_DEBUG (1, "%s.sip:%x(%x)%x\n", __FUNCTION__
+	      ,self->int_sip,irqstat,self->txpending);
+    }
+}
+
+STATIC int
+toshoboe_net_init (struct net_device *dev)
+{
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  /* Setup to be a normal IrDA network device driver */
+  irda_device_setup (dev);
+
+  /* Insert overrides below this line! */
+  return 0;
+}
+
+STATIC int
+toshoboe_net_open (struct net_device *dev)
+{
+  struct toshoboe_cb *self;
+  unsigned long flags;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ASSERT (dev != NULL, return -1; );
+  self = (struct toshoboe_cb *) dev->priv;
+
+  ASSERT (self != NULL, return 0; );
+
+  if (self->async)
+    return -EBUSY;
+
+  if (self->stopped)
+    return 0;
+
+  if (request_irq (self->io.irq, toshoboe_interrupt,
+                   SA_SHIRQ | SA_INTERRUPT, dev->name, (void *) self))
+    {
+      return -EAGAIN;
+    }
+
+  spin_lock_irqsave(&self->spinlock, flags);
+  toshoboe_startchip (self);
+  spin_unlock_irqrestore(&self->spinlock, flags);
+
+  /* Ready to play! */
+  netif_start_queue(dev);
+
+  /*
+   * Open new IrLAP layer instance, now that everything should be
+   * initialized properly
+   */
+  self->irlap = irlap_open (dev, &self->qos, driver_name);
+
+  self->irdad = 1;
+
+  MOD_INC_USE_COUNT;
+
+  return 0;
+}
+
+STATIC int
+toshoboe_net_close (struct net_device *dev)
+{
+  struct toshoboe_cb *self;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ASSERT (dev != NULL, return -1; );
+  self = (struct toshoboe_cb *) dev->priv;
+
+  /* Stop device */
+  netif_stop_queue(dev);
+
+  /* Stop and remove instance of IrLAP */
+  if (self->irlap)
+    irlap_close (self->irlap);
+  self->irlap = NULL;
+
+  self->irdad = 0;
+
+  free_irq (self->io.irq, (void *) self);
+
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+    }
+
+  MOD_DEC_USE_COUNT;
+
+  return 0;
+}
+
+/*
+ * Function toshoboe_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+STATIC int
+toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+  struct if_irda_req *irq = (struct if_irda_req *) rq;
+  struct toshoboe_cb *self;
+  unsigned long flags;
+  int ret = 0;
+
+  ASSERT (dev != NULL, return -1; );
+
+  self = dev->priv;
+
+  ASSERT (self != NULL, return -1; );
+
+  IRDA_DEBUG (5, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
+
+  /* Disable interrupts & save flags */
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  switch (cmd)
+    {
+    case SIOCSBANDWIDTH:       /* Set bandwidth */
+      /* This function will also be used by IrLAP to change the
+       * speed, so we still must allow for speed change within
+       * interrupt context.
+       */
+      IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __FUNCTION__
+          ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate );
+      if (!in_interrupt () && !capable (CAP_NET_ADMIN))
+        return -EPERM;
+
+      /* self->speed=irq->ifr_baudrate; */
+      /* toshoboe_setbaud(self); */
+      /* Just change speed once - inserted by Paul Bristow */
+      self->new_speed = irq->ifr_baudrate;
+      break;
+    case SIOCSMEDIABUSY:       /* Set media busy */
+      IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __FUNCTION__
+          ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) );
+      if (!capable (CAP_NET_ADMIN))
+        return -EPERM;
+      irda_device_set_media_busy (self->netdev, TRUE);
+      break;
+    case SIOCGRECEIVING:       /* Check if we are receiving right now */
+      irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0;
+      IRDA_DEBUG (3, "%s(RECEIVING), %s, (%X/%x)\n", __FUNCTION__
+          ,dev->name, INB (OBOE_STATUS), irq->ifr_receiving );
+      break;
+    default:
+      IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
+      ret = -EOPNOTSUPP;
+    }
+
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  return ret;
+
+}
+
+MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver");
+MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM (max_baud, "i");
+MODULE_PARM_DESC(max_baud, "Maximum baud rate");
+
+MODULE_PARM (do_probe, "i");
+MODULE_PARM_DESC(do_probe, "Enable/disable chip probing and self-test");
+
+STATIC void
+toshoboe_close (struct pci_dev *pci_dev)
+{
+  int i;
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ASSERT (self != NULL, return; );
+
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+    }
+
+  release_region (self->io.fir_base, self->io.fir_ext);
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      kfree (self->tx_bufs[i]);
+      self->tx_bufs[i] = NULL;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      kfree (self->rx_bufs[i]);
+      self->rx_bufs[i] = NULL;
+    }
+
+  if (self->netdev)
+    {
+      /* Remove netdevice */
+      rtnl_lock ();
+      unregister_netdevice (self->netdev);
+      rtnl_unlock ();
+    }
+
+  kfree (self->ringbuf);
+  self->ringbuf = NULL;
+  self->ring = NULL;
+
+  return;
+}
+
+STATIC int
+toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
+{
+  struct toshoboe_cb *self;
+  struct net_device *dev;
+  int i = 0;
+  int ok = 0;
+  int err;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if ((err=pci_enable_device(pci_dev)))
+    return err;
+
+  self = kmalloc (sizeof (struct toshoboe_cb), GFP_KERNEL);
+
+  if (self == NULL)
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't allocate memory for "
+              "IrDA control block\n");
+      return -ENOMEM;
+    }
+
+  memset (self, 0, sizeof (struct toshoboe_cb));
+
+  self->pdev = pci_dev;
+  self->base = pci_resource_start(pci_dev,0);
+
+  self->io.fir_base = self->base;
+  self->io.fir_ext = OBOE_IO_EXTENT;
+  self->io.irq = pci_dev->irq;
+  self->io.irqflags = SA_SHIRQ | SA_INTERRUPT;
+
+  self->speed = self->io.speed = 9600;
+  self->async = 0;
+
+  /* Lock the port that we need */
+  if (NULL==request_region (self->io.fir_base, self->io.fir_ext, driver_name))
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't get iobase of 0x%03x\n"
+	      ,self->io.fir_base);
+      err = -EBUSY;
+      goto freeself;
+    }
+
+  spin_lock_init(&self->spinlock);
+  
+  irda_init_max_qos_capabilies (&self->qos);
+  self->qos.baud_rate.bits = 0;
+
+  if (max_baud >= 2400)
+    self->qos.baud_rate.bits |= IR_2400;
+  /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */
+  if (max_baud >= 9600)
+    self->qos.baud_rate.bits |= IR_9600;
+  if (max_baud >= 19200)
+    self->qos.baud_rate.bits |= IR_19200;
+  if (max_baud >= 115200)
+    self->qos.baud_rate.bits |= IR_115200;
+#ifdef USE_MIR
+  if (max_baud >= 1152000)
+    {
+      self->qos.baud_rate.bits |= IR_1152000;
+      self->flags |= IFF_MIR;
+    }
+#endif
+  if (max_baud >= 4000000)
+    {
+      self->qos.baud_rate.bits |= (IR_4000000 << 8);
+      self->flags |= IFF_FIR;
+    }
+
+  /*FIXME: work this out... */
+  self->qos.min_turn_time.bits = 0xff;
+
+  irda_qos_bits_to_value (&self->qos);
+
+  self->flags = IFF_SIR | IFF_DMA | IFF_PIO;
+
+  /* Allocate twice the size to guarantee alignment */
+  self->ringbuf = (void *) kmalloc (OBOE_RING_LEN << 1, GFP_KERNEL);
+  if (!self->ringbuf)
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't allocate DMA buffers\n");
+      err = -ENOMEM;
+      goto freeregion;
+    }
+
+  /*We need to align the taskfile on a taskfile size boundary */
+  {
+    __u32 addr;
+
+    addr = (__u32) self->ringbuf;
+    addr &= ~(OBOE_RING_LEN - 1);
+    addr += OBOE_RING_LEN;
+    self->ring = (struct OboeRing *) addr;
+  }
+
+  memset (self->ring, 0, OBOE_RING_LEN);
+  self->io.mem_base = (__u32) self->ring;
+
+  ok = 1;
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->tx_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL);
+      if (!self->tx_bufs[i])
+        ok = 0;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->rx_bufs[i] = kmalloc (RX_BUF_SZ, GFP_KERNEL);
+      if (!self->rx_bufs[i])
+        ok = 0;
+    }
+
+  if (!ok)
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't allocate rx/tx buffers\n");
+      err = -ENOMEM;
+      goto freebufs;
+    }
+
+  if (do_probe)
+    if (!toshoboe_probe (self))
+      {
+        err = -ENODEV;
+        goto freebufs;
+      }
+
+  if (!(dev = dev_alloc ("irda%d", &err)))
+    {
+      printk (KERN_ERR DRIVER_NAME ": dev_alloc() failed\n");
+      err = -ENOMEM;
+      goto freebufs;
+    }
+
+  dev->priv = (void *) self;
+  self->netdev = dev;
+
+  printk (KERN_INFO "IrDA: Registered device %s\n", dev->name);
+
+  dev->init = toshoboe_net_init;
+  dev->hard_start_xmit = toshoboe_hard_xmit;
+  dev->open = toshoboe_net_open;
+  dev->stop = toshoboe_net_close;
+  dev->do_ioctl = toshoboe_net_ioctl;
+
+  rtnl_lock ();
+  err = register_netdevice (dev);
+  rtnl_unlock ();
+  if (err)
+    {
+      printk (KERN_ERR DRIVER_NAME ": register_netdev() failed\n");
+      err = -ENOMEM;
+      goto freebufs;
+    }
+
+  pci_set_drvdata(pci_dev,self);
+
+  printk (KERN_INFO DRIVER_NAME ": Using multiple tasks, version %s\n", rcsid);
+
+  return 0;
+
+freebufs:
+  for (i = 0; i < TX_SLOTS; ++i)
+    if (self->tx_bufs[i])
+      kfree (self->tx_bufs[i]);
+  for (i = 0; i < RX_SLOTS; ++i)
+    if (self->rx_bufs[i])
+      kfree (self->rx_bufs[i]);
+  kfree(self->ringbuf);
+
+freeregion:
+  release_region (self->io.fir_base, self->io.fir_ext);
+
+freeself:
+  kfree (self);
+
+  return err;
+}
+
+STATIC int
+toshoboe_gotosleep (struct pci_dev *pci_dev, u32 crap)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+  unsigned long flags;
+  int i = 10;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if (!self || self->stopped)
+    return 0;
+
+  if ((!self->irdad) && (!self->async))
+    return 0;
+
+/* Flush all packets */
+  while ((i--) && (self->txpending))
+    udelay (10000);
+
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  toshoboe_stopchip (self);
+  self->stopped = 1;
+  self->txpending = 0;
+
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  return 0;
+}
+
+STATIC int
+toshoboe_wakeup (struct pci_dev *pci_dev)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+  unsigned long flags;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if (!self || !self->stopped)
+    return 0;
+
+  if ((!self->irdad) && (!self->async))
+    return 0;
+
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  toshoboe_startchip (self);
+  self->stopped = 0;
+
+  netif_wake_queue(self->netdev);
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  return 0;
+}
+
+static struct pci_driver toshoboe_pci_driver = {
+  name		: "toshoboe",
+  id_table	: toshoboe_pci_tbl,
+  probe		: toshoboe_open,
+  remove	: toshoboe_close,
+  suspend	: toshoboe_gotosleep,
+  resume	: toshoboe_wakeup 
+};
+
+int __init
+toshoboe_init (void)
+{
+  return pci_module_init(&toshoboe_pci_driver);
+}
+
+STATIC void __exit
+toshoboe_cleanup (void)
+{
+  pci_unregister_driver(&toshoboe_pci_driver);
+}
+
+module_init(toshoboe_init);
+module_exit(toshoboe_cleanup);
diff -Nru a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/donauboe.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,363 @@
+/*********************************************************************
+ *                
+ * Filename:      toshoboe.h
+ * Version:       2.16
+ * Description:   Driver for the Toshiba OBOE (or type-O or 701)
+ *                FIR Chipset, also supports the DONAUOBOE (type-DO
+ *                or d01) FIR chipset which as far as I know is
+ *                register compatible.
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * Modified: 2.16 Martin Lucina <mato@kotelna.sk>
+ * Modified: 2.16 Sat Jun 22 18:54:29 2002 (sync headers)
+ * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.17 jeu sep 12 08:50:20 2002 (add lock to be used by spinlocks)
+ * 
+ *     Copyright (c) 1999 James McKenzie, All Rights Reserved.
+ *      
+ *     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.
+ *  
+ *     Neither James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ * 
+ *     Applicable Models : Libretto 100/110CT and many more.
+ *     Toshiba refers to this chip as the type-O IR port,
+ *     or the type-DO IR port.
+ *
+ * IrDA chip set list from Toshiba Computer Engineering Corp.
+ * model			method	maker	controler		Version 
+ * Portege 320CT	FIR,SIR Toshiba Oboe(Triangle) 
+ * Portege 3010CT	FIR,SIR Toshiba Oboe(Sydney) 
+ * Portege 3015CT	FIR,SIR Toshiba Oboe(Sydney) 
+ * Portege 3020CT	FIR,SIR Toshiba Oboe(Sydney) 
+ * Portege 7020CT	FIR,SIR ?		?
+ * 
+ * Satell. 4090XCDT	FIR,SIR ?		?
+ * 
+ * Libretto 100CT	FIR,SIR Toshiba Oboe 
+ * Libretto 1000CT	FIR,SIR Toshiba Oboe 
+ * 
+ * TECRA750DVD		FIR,SIR Toshiba Oboe(Triangle)	REV ID=14h 
+ * TECRA780			FIR,SIR Toshiba Oboe(Sandlot)	REV ID=32h,33h 
+ * TECRA750CDT		FIR,SIR Toshiba Oboe(Triangle)	REV ID=13h,14h 
+ * TECRA8000		FIR,SIR Toshiba Oboe(ISKUR)		REV ID=23h 
+ * 
+ ********************************************************************/
+
+/* The documentation for this chip is allegedly released         */
+/* However I have not seen it, not have I managed to contact     */
+/* anyone who has. HOWEVER the chip bears a striking resemblence */
+/* to the IrDA controller in the Toshiba RISC TMPR3922 chip      */
+/* the documentation for this is freely available at             */
+/* http://www.toshiba.com/taec/components/Generic/TMPR3922.shtml */
+/* The mapping between the registers in that document and the    */
+/* Registers in the 701 oboe chip are as follows    */
+
+
+/* 3922 reg     701 regs, by bit numbers                        */
+/*               7- 0  15- 8  24-16  31-25                      */
+/* $28            0x0    0x1                                    */
+/* $2c                                     SEE NOTE 1           */
+/* $30            0x6    0x7                                    */
+/* $34            0x8    0x9               SEE NOTE 2           */
+/* $38           0x10   0x11                                    */
+/* $3C                   0xe               SEE NOTE 3           */
+/* $40           0x12   0x13                                    */
+/* $44           0x14   0x15                                    */
+/* $48           0x16   0x17                                    */
+/* $4c           0x18   0x19                                    */
+/* $50           0x1a   0x1b                                    */
+
+/* FIXME: could be 0x1b 0x1a here */
+
+/* $54           0x1d   0x1c                                    */
+/* $5C           0xf                       SEE NOTE 4           */
+/* $130                                    SEE NOTE 5           */
+/* $134                                    SEE NOTE 6           */
+/*                                                              */
+/* NOTES:                                                       */
+/* 1. The pointer to ring is packed in most unceremoniusly      */
+/*    701 Register      Address bits    (A9-A0 must be zero)    */
+/*            0x4:      A17 A16 A15 A14 A13 A12 A11 A10         */
+/*            0x5:      A25 A24 A23 A22 A21 A20 A19 A18         */
+/*            0x2:        0   0 A31 A30 A29 A28 A27 A26         */
+/*                                                              */
+/* 2. The M$ drivers do a write 0x1 to 0x9, however the 3922    */
+/*    documentation would suggest that a write of 0x1 to 0x8    */
+/*    would be more appropriate.                                */
+/*                                                              */
+/* 3. This assignment is tenuous at best, register 0xe seems to */
+/*    have bits arranged 0 0 0 R/W R/W R/W R/W R/W              */
+/*    if either of the lower two bits are set the chip seems to */
+/*    switch off                                                */
+/*                                                              */
+/* 4. Bits 7-4 seem to be different 4 seems just to be generic  */
+/*    receiver busy flag                                        */
+/*                                                              */
+/* 5. and 6. The IER and ISR have a different bit assignment    */
+/*    The lower three bits of both read back as ones            */
+/* ISR is register 0xc, IER is register 0xd                     */
+/*           7      6      5      4      3      2      1      0 */
+/* 0xc: TxDone RxDone TxUndr RxOver SipRcv      1      1      1 */
+/* 0xd: TxDone RxDone TxUndr RxOver SipRcv      1      1      1 */
+/* TxDone xmitt done (generated only if generate interrupt bit  */
+/*   is set in the ring)                                        */
+/* RxDone recv completed (or other recv condition if you set it */
+/*   up                                                         */
+/* TxUnder underflow in Transmit FIFO                           */
+/* RxOver  overflow in Recv FIFO                                */
+/* SipRcv  received serial gap  (or other condition you set)    */
+/* Interrupts are enabled by writing a one to the IER register  */
+/* Interrupts are cleared by writting a one to the ISR register */
+/*                                                              */
+/* 6. The remaining registers: 0x6 and 0x3 appear to be         */
+/*    reserved parts of 16 or 32 bit registersthe remainder     */
+/*    0xa 0xb 0x1e 0x1f could possibly be (by their behaviour)  */
+/*    the Unicast Filter register at $58.                       */
+/*                                                              */
+/* 7. While the core obviously expects 32 bit accesses all the  */
+/*    M$ drivers do 8 bit accesses, infact the Miniport ones    */
+/*    write and read back the byte serveral times (why?)        */
+
+
+#ifndef TOSHOBOE_H
+#define TOSHOBOE_H
+
+/* Registers */
+
+#define OBOE_IO_EXTENT	0x1f
+
+/*Receive and transmit slot pointers */
+#define OBOE_REG(i)	(i+(self->base))
+#define OBOE_RXSLOT	OBOE_REG(0x0)
+#define OBOE_TXSLOT	OBOE_REG(0x1)
+#define OBOE_SLOT_MASK	0x3f
+
+#define OBOE_TXRING_OFFSET		0x200
+#define OBOE_TXRING_OFFSET_IN_SLOTS	0x40
+
+/*pointer to the ring */
+#define OBOE_RING_BASE0	OBOE_REG(0x4)
+#define OBOE_RING_BASE1	OBOE_REG(0x5)
+#define OBOE_RING_BASE2	OBOE_REG(0x2)
+#define OBOE_RING_BASE3	OBOE_REG(0x3)
+
+/*Number of slots in the ring */
+#define OBOE_RING_SIZE  OBOE_REG(0x7)
+#define OBOE_RING_SIZE_RX4	0x00
+#define OBOE_RING_SIZE_RX8	0x01
+#define OBOE_RING_SIZE_RX16	0x03
+#define OBOE_RING_SIZE_RX32	0x07
+#define OBOE_RING_SIZE_RX64	0x0f
+#define OBOE_RING_SIZE_TX4	0x00
+#define OBOE_RING_SIZE_TX8	0x10
+#define OBOE_RING_SIZE_TX16	0x30
+#define OBOE_RING_SIZE_TX32	0x70
+#define OBOE_RING_SIZE_TX64	0xf0
+
+#define OBOE_RING_MAX_SIZE	64
+
+/*Causes the gubbins to re-examine the ring */
+#define OBOE_PROMPT	OBOE_REG(0x9)
+#define OBOE_PROMPT_BIT		0x1
+
+/* Interrupt Status Register */
+#define OBOE_ISR	OBOE_REG(0xc)
+/* Interrupt Enable Register */
+#define OBOE_IER	OBOE_REG(0xd)
+/* Interrupt bits for IER and ISR */
+#define OBOE_INT_TXDONE		0x80
+#define OBOE_INT_RXDONE		0x40
+#define OBOE_INT_TXUNDER	0x20
+#define OBOE_INT_RXOVER		0x10
+#define OBOE_INT_SIP		0x08
+#define OBOE_INT_MASK		0xf8
+
+/*Reset Register */
+#define OBOE_CONFIG1	OBOE_REG(0xe)
+#define OBOE_CONFIG1_RST	0x01
+#define OBOE_CONFIG1_DISABLE	0x02
+#define OBOE_CONFIG1_4		0x08
+#define OBOE_CONFIG1_8		0x08
+
+#define OBOE_CONFIG1_ON		0x8
+#define OBOE_CONFIG1_RESET	0xf
+#define OBOE_CONFIG1_OFF	0xe
+
+#define OBOE_STATUS	OBOE_REG(0xf)
+#define OBOE_STATUS_RXBUSY	0x10
+#define OBOE_STATUS_FIRRX	0x04
+#define OBOE_STATUS_MIRRX	0x02
+#define OBOE_STATUS_SIRRX	0x01
+
+
+/*Speed control registers */
+#define OBOE_CONFIG0L	OBOE_REG(0x10)
+#define OBOE_CONFIG0H	OBOE_REG(0x11)
+
+#define OBOE_CONFIG0H_TXONLOOP  0x80 /*Transmit when looping (dangerous) */
+#define OBOE_CONFIG0H_LOOP	0x40 /*Loopback Tx->Rx */
+#define OBOE_CONFIG0H_ENTX	0x10 /*Enable Tx */
+#define OBOE_CONFIG0H_ENRX	0x08 /*Enable Rx */
+#define OBOE_CONFIG0H_ENDMAC	0x04 /*Enable/reset* the DMA controller */
+#define OBOE_CONFIG0H_RCVANY	0x02 /*DMA mode 1=bytes, 0=dwords */
+
+#define OBOE_CONFIG0L_CRC16	0x80 /*CRC 1=16 bit 0=32 bit */
+#define OBOE_CONFIG0L_ENFIR	0x40 /*Enable FIR */
+#define OBOE_CONFIG0L_ENMIR	0x20 /*Enable MIR */
+#define OBOE_CONFIG0L_ENSIR	0x10 /*Enable SIR */
+#define OBOE_CONFIG0L_ENSIRF	0x08 /*Enable SIR framer */
+#define OBOE_CONFIG0L_SIRTEST	0x04 /*Enable SIR framer in MIR and FIR */
+#define OBOE_CONFIG0L_INVERTTX  0x02 /*Invert Tx Line */
+#define OBOE_CONFIG0L_INVERTRX  0x01 /*Invert Rx Line */
+
+#define OBOE_BOF	OBOE_REG(0x12)
+#define OBOE_EOF	OBOE_REG(0x13)
+
+#define OBOE_ENABLEL	OBOE_REG(0x14)
+#define OBOE_ENABLEH	OBOE_REG(0x15)
+
+#define OBOE_ENABLEH_PHYANDCLOCK	0x80 /*Toggle low to copy config in */
+#define OBOE_ENABLEH_CONFIGERR		0x40
+#define OBOE_ENABLEH_FIRON		0x20
+#define OBOE_ENABLEH_MIRON		0x10
+#define OBOE_ENABLEH_SIRON		0x08
+#define OBOE_ENABLEH_ENTX		0x04
+#define OBOE_ENABLEH_ENRX		0x02
+#define OBOE_ENABLEH_CRC16		0x01
+
+#define OBOE_ENABLEL_BROADCAST		0x01
+
+#define OBOE_CURR_PCONFIGL		OBOE_REG(0x16) /*Current config */
+#define OBOE_CURR_PCONFIGH		OBOE_REG(0x17)
+
+#define OBOE_NEW_PCONFIGL		OBOE_REG(0x18)
+#define OBOE_NEW_PCONFIGH		OBOE_REG(0x19)
+
+#define OBOE_PCONFIGH_BAUDMASK		0xfc
+#define OBOE_PCONFIGH_WIDTHMASK		0x04
+#define OBOE_PCONFIGL_WIDTHMASK		0xe0
+#define OBOE_PCONFIGL_PREAMBLEMASK	0x1f
+
+#define OBOE_PCONFIG_BAUDMASK		0xfc00
+#define OBOE_PCONFIG_BAUDSHIFT		10
+#define OBOE_PCONFIG_WIDTHMASK		0x04e0
+#define OBOE_PCONFIG_WIDTHSHIFT		5
+#define OBOE_PCONFIG_PREAMBLEMASK	0x001f
+#define OBOE_PCONFIG_PREAMBLESHIFT	0
+
+#define OBOE_MAXLENL			OBOE_REG(0x1a)
+#define OBOE_MAXLENH			OBOE_REG(0x1b)
+
+#define OBOE_RXCOUNTH			OBOE_REG(0x1c) /*Reset on recipt */
+#define OBOE_RXCOUNTL			OBOE_REG(0x1d) /*of whole packet */
+
+/* The PCI ID of the OBOE chip */
+#ifndef PCI_DEVICE_ID_FIR701
+#define PCI_DEVICE_ID_FIR701 	0x0701
+#endif
+
+#ifndef PCI_DEVICE_ID_FIRD01
+#define PCI_DEVICE_ID_FIRD01 	0x0d01
+#endif
+
+struct OboeSlot
+{
+  __u16 len;                    /*Tweleve bits of packet length */
+  __u8 unused;
+  __u8 control;                 /*Slot control/status see below */
+  __u32 address;                /*Slot buffer address */
+}
+__attribute__ ((packed));
+
+#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS
+
+struct OboeRing
+{
+  struct OboeSlot rx[OBOE_NTASKS];
+  struct OboeSlot tx[OBOE_NTASKS];
+};
+
+#define OBOE_RING_LEN (sizeof(struct OboeRing))
+
+
+#define OBOE_CTL_TX_HW_OWNS	0x80 /*W/R This slot owned by the hardware */
+#define OBOE_CTL_TX_DISTX_CRC	0x40 /*W Disable CRC generation for [FM]IR */
+#define OBOE_CTL_TX_BAD_CRC     0x20 /*W Generate bad CRC */
+#define OBOE_CTL_TX_SIP		0x10   /*W Generate an SIP after xmittion */
+#define OBOE_CTL_TX_MKUNDER	0x08 /*W Generate an underrun error */
+#define OBOE_CTL_TX_RTCENTX	0x04 /*W Enable receiver and generate TXdone */
+     /*  After this slot is processed        */
+#define OBOE_CTL_TX_UNDER	0x01  /*R Set by hardware to indicate underrun */
+
+
+#define OBOE_CTL_RX_HW_OWNS	0x80 /*W/R This slot owned by hardware */
+#define OBOE_CTL_RX_PHYERR	0x40 /*R Decoder error on receiption */
+#define OBOE_CTL_RX_CRCERR	0x20 /*R CRC error only set for [FM]IR */
+#define OBOE_CTL_RX_LENGTH	0x10 /*R Packet > max Rx length  */
+#define OBOE_CTL_RX_OVER	0x08   /*R set to indicate an overflow */
+#define OBOE_CTL_RX_SIRBAD	0x04 /*R SIR had BOF in packet or ABORT sequence */
+#define OBOE_CTL_RX_RXEOF	0x02  /*R Finished receiving on this slot */
+
+
+struct toshoboe_cb
+{
+  struct net_device *netdev;    /* Yes! we are some kind of netdevice */
+  struct net_device_stats stats;
+  struct tty_driver ttydev;
+
+  struct irlap_cb *irlap;       /* The link layer we are binded to */
+
+  chipio_t io;                  /* IrDA controller information */
+  struct qos_info qos;          /* QoS capabilities for this device */
+
+  __u32 flags;                  /* Interface flags */
+
+  struct pci_dev *pdev;         /*PCI device */
+  int base;                     /*IO base */
+
+
+  int txpending;                /*how many tx's are pending */
+  int txs, rxs;                 /*Which slots are we at  */
+
+  int irdad;                    /*Driver under control of netdev end  */
+  int async;                    /*Driver under control of async end   */
+
+
+  int stopped;                  /*Stopped by some or other APM stuff */
+
+  int filter;                   /*In SIR mode do we want to receive
+                                   frames or byte ranges */
+
+  void *ringbuf;                /*The ring buffer */
+  struct OboeRing *ring;        /*The ring */
+
+  void *tx_bufs[OBOE_RING_MAX_SIZE]; /*The buffers   */
+  void *rx_bufs[OBOE_RING_MAX_SIZE];
+
+
+  int speed;                    /*Current setting of the speed */
+  int new_speed;                /*Set to request a speed change */
+
+/* The spinlock protect critical parts of the driver.
+ *	Locking is done like this :
+ *		spin_lock_irqsave(&self->spinlock, flags);
+ *	Releasing the lock :
+ *		spin_unlock_irqrestore(&self->spinlock, flags);
+ */
+  spinlock_t spinlock;		
+  /* Used for the probe and diagnostics code */
+  int int_rx;
+  int int_tx;
+  int int_txunder;
+  int int_rxover;
+  int int_sip;
+};
+
+
+#endif
diff -Nru a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
--- a/drivers/net/irda/vlsi_ir.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/net/irda/vlsi_ir.c	Fri Oct 11 21:22:51 2002
@@ -2,9 +2,7 @@
  *
  *	vlsi_ir.c:	VLSI82C147 PCI IrDA controller driver for Linux
  *
- *	Version:	0.3a, Nov 10, 2001
- *
- *	Copyright (c) 2001 Martin Diehl
+ *	Copyright (c) 2001-2002 Martin Diehl
  *
  *	This program is free software; you can redistribute it and/or 
  *	modify it under the terms of the GNU General Public License as 
@@ -25,6 +23,17 @@
 
 #include <linux/module.h>
  
+MODULE_DESCRIPTION("IrDA SIR/MIR/FIR driver for VLSI 82C147");
+MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
+
+#define DRIVER_NAME "vlsi_ir"
+#define DRIVER_VERSION "v0.4"
+
+/********************************************************/
+
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -33,6 +42,9 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/time.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>
@@ -40,17 +52,9 @@
 
 #include <net/irda/vlsi_ir.h>
 
-
 /********************************************************/
 
-
-MODULE_DESCRIPTION("IrDA SIR/MIR/FIR driver for VLSI 82C147");
-MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
-MODULE_LICENSE("GPL");
-
-
-static /* const */ char drivername[] = "vlsi_ir";
-
+static /* const */ char drivername[] = DRIVER_NAME;
 
 #define PCI_CLASS_WIRELESS_IRDA 0x0d00
 
@@ -64,13 +68,8 @@
 
 MODULE_DEVICE_TABLE(pci, vlsi_irda_table);
 
-
 /********************************************************/
 
-
-MODULE_PARM(clksrc, "i");
-MODULE_PARM_DESC(clksrc, "clock input source selection");
-
 /*	clksrc: which clock source to be used
  *		0: auto - try PLL, fallback to 40MHz XCLK
  *		1: on-chip 48MHz PLL
@@ -78,12 +77,10 @@
  *		3: external 40MHz XCLK (HP OB-800)
  */
 
+MODULE_PARM(clksrc, "i");
+MODULE_PARM_DESC(clksrc, "clock input source selection");
 static int clksrc = 0;			/* default is 0(auto) */
 
-
-MODULE_PARM(ringsize, "1-2i");
-MODULE_PARM_DESC(ringsize, "TX, RX ring descriptor size");
-
 /*	ringsize: size of the tx and rx descriptor rings
  *		independent for tx and rx
  *		specify as ringsize=tx[,rx]
@@ -92,11 +89,9 @@
  *		there should be no gain when using rings larger than 8
  */
 
-static int ringsize[] = {8,8};		/* default is tx=rx=8 */
-
-
-MODULE_PARM(sirpulse, "i");
-MODULE_PARM_DESC(sirpulse, "SIR pulse width tuning");
+MODULE_PARM(ringsize, "1-2i");
+MODULE_PARM_DESC(ringsize, "TX, RX ring descriptor size");
+static int ringsize[] = {8,8};		/* default is tx=8 / rx=8 */
 
 /*	sirpulse: tuning of the SIR pulse width within IrPHY 1.3 limits
  *		0: very short, 1.5us (exception: 6us at 2.4 kbaud)
@@ -107,323 +102,750 @@
  *		pulse width saves more than 90% of the transmitted IR power.
  */
 
+MODULE_PARM(sirpulse, "i");
+MODULE_PARM_DESC(sirpulse, "SIR pulse width tuning");
 static int sirpulse = 1;		/* default is 3/16 bittime */
 
-
-MODULE_PARM(qos_mtt_bits, "i");
-MODULE_PARM_DESC(qos_mtt_bits, "IrLAP bitfield representing min-turn-time");
-
 /*	qos_mtt_bits: encoded min-turn-time value we require the peer device
  *		 to use before transmitting to us. "Type 1" (per-station)
  *		 bitfield according to IrLAP definition (section 6.6.8)
- *		 The HP HDLS-1100 requires 1 msec - don't even know
- *		 if this is the one which is used by my OB800
+ *		 Don't know which transceiver is used by my OB800 - the
+ *		 pretty common HP HDLS-1100 requires 1 msec - so lets use this.
  */
 
+MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM_DESC(qos_mtt_bits, "IrLAP bitfield representing min-turn-time");
 static int qos_mtt_bits = 0x04;		/* default is 1 ms */
 
-
 /********************************************************/
 
+static void vlsi_reg_debug(unsigned iobase, const char *s)
+{
+	int	i;
 
-/* some helpers for operations on ring descriptors */
-
+	printk(KERN_DEBUG "%s: ", s);
+	for (i = 0; i < 0x20; i++)
+		printk("%02x", (unsigned)inb((iobase+i)));
+	printk("\n");
+}
 
-static inline int rd_is_active(struct vlsi_ring *r, unsigned i)
+static void vlsi_ring_debug(struct vlsi_ring *r)
 {
-	return ((r->hw[i].rd_status & RD_STAT_ACTIVE) != 0);
+	struct ring_descr *rd;
+	unsigned i;
+
+	printk(KERN_DEBUG "%s - ring %p / size %u / mask 0x%04x / len %u / dir %d / hw %p\n",
+		__FUNCTION__, r, r->size, r->mask, r->len, r->dir, r->rd[0].hw);
+	printk(KERN_DEBUG "%s - head = %d / tail = %d\n", __FUNCTION__,
+		atomic_read(&r->head) & r->mask, atomic_read(&r->tail) & r->mask);
+	for (i = 0; i < r->size; i++) {
+		rd = &r->rd[i];
+		printk(KERN_DEBUG "%s - ring descr %u: ", __FUNCTION__, i);
+		printk("skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw);
+		printk(KERN_DEBUG "%s - hw: status=%02x count=%u addr=0x%08x\n",
+			__FUNCTION__, (unsigned) rd_get_status(rd),
+			(unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd));
+	}
 }
 
-static inline void rd_activate(struct vlsi_ring *r, unsigned i)
+/********************************************************/
+
+#ifdef CONFIG_PROC_FS
+
+static int vlsi_proc_pdev(struct pci_dev *pdev, char *buf, int len)
 {
-	r->hw[i].rd_status |= RD_STAT_ACTIVE;
-}
+	unsigned iobase = pci_resource_start(pdev, 0);
+	unsigned i;
+	char *out = buf;
+
+	if (len < 500)
+		return 0;
 
-static inline void rd_set_addr_status(struct vlsi_ring *r, unsigned i, dma_addr_t a, u8 s)
+	out += sprintf(out, "\n%s (vid/did: %04x/%04x)\n",
+			pdev->name, (int)pdev->vendor, (int)pdev->device);
+	out += sprintf(out, "pci-power-state: %u\n", (unsigned) pdev->current_state);
+	out += sprintf(out, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n",
+			pdev->irq, (unsigned)pci_resource_start(pdev, 0), (u64)pdev->dma_mask);
+	out += sprintf(out, "hw registers: ");
+	for (i = 0; i < 0x20; i++)
+		out += sprintf(out, "%02x", (unsigned)inb((iobase+i)));
+	out += sprintf(out, "\n");
+	return out - buf;
+}
+		
+static int vlsi_proc_ndev(struct net_device *ndev, char *buf, int len)
 {
-	struct ring_descr *rd = r->hw +i;
+	vlsi_irda_dev_t *idev = ndev->priv;
+	char *out = buf;
+	u8 byte;
+	u16 word;
+	unsigned delta1, delta2;
+	struct timeval now;
+	unsigned iobase = ndev->base_addr;
 
-	/* ordering is important for two reasons:
-	 *  - overlayed: writing addr overwrites status
-	 *  - we want to write status last so we have valid address in
-	 *    case status has RD_STAT_ACTIVE set
-	 */
+	if (len < 1000)
+		return 0;
 
-	if ((a & ~DMA_MASK_MSTRPAGE) != MSTRPAGE_VALUE)
-		BUG();
+	out += sprintf(out, "\n%s link state: %s / %s / %s / %s\n", ndev->name,
+		netif_device_present(ndev) ? "attached" : "detached", 
+		netif_running(ndev) ? "running" : "not running",
+		netif_carrier_ok(ndev) ? "carrier ok" : "no carrier",
+		netif_queue_stopped(ndev) ? "queue stopped" : "queue running");
+	if (!netif_running(ndev))
+		return out - buf;
+
+	out += sprintf(out, "\nhw-state:\n");
+	pci_read_config_byte(idev->pdev, VLSI_PCI_IRMISC, &byte);
+	out += sprintf(out, "IRMISC:%s%s%s UART%s",
+		(byte&IRMISC_IRRAIL) ? " irrail" : "",
+		(byte&IRMISC_IRPD) ? " irpd" : "",
+		(byte&IRMISC_UARTTST) ? " uarttest" : "",
+		(byte&IRMISC_UARTEN) ? "" : " disabled\n");
+	if (byte&IRMISC_UARTEN) {
+		out += sprintf(out, "@0x%s\n",
+			(byte&2) ? ((byte&1) ? "3e8" : "2e8")
+				 : ((byte&1) ? "3f8" : "2f8"));
+	}
+	pci_read_config_byte(idev->pdev, VLSI_PCI_CLKCTL, &byte);
+	out += sprintf(out, "CLKCTL: PLL %s%s%s / clock %s / wakeup %s\n",
+		(byte&CLKCTL_PD_INV) ? "powered" : "down",
+		(byte&CLKCTL_LOCK) ? " locked" : "",
+		(byte&CLKCTL_EXTCLK) ? ((byte&CLKCTL_XCKSEL)?" / 40 MHz XCLK":" / 48 MHz XCLK") : "",
+		(byte&CLKCTL_CLKSTP) ? "stopped" : "running",
+		(byte&CLKCTL_WAKE) ? "enabled" : "disabled");
+	pci_read_config_byte(idev->pdev, VLSI_PCI_MSTRPAGE, &byte);
+	out += sprintf(out, "MSTRPAGE: 0x%02x\n", (unsigned)byte);
+
+	byte = inb(iobase+VLSI_PIO_IRINTR);
+	out += sprintf(out, "IRINTR:%s%s%s%s%s%s%s%s\n",
+		(byte&IRINTR_ACTEN) ? " ACTEN" : "",
+		(byte&IRINTR_RPKTEN) ? " RPKTEN" : "",
+		(byte&IRINTR_TPKTEN) ? " TPKTEN" : "",
+		(byte&IRINTR_OE_EN) ? " OE_EN" : "",
+		(byte&IRINTR_ACTIVITY) ? " ACTIVITY" : "",
+		(byte&IRINTR_RPKTINT) ? " RPKTINT" : "",
+		(byte&IRINTR_TPKTINT) ? " TPKTINT" : "",
+		(byte&IRINTR_OE_INT) ? " OE_INT" : "");
+	word = inw(iobase+VLSI_PIO_RINGPTR);
+	out += sprintf(out, "RINGPTR: rx=%u / tx=%u\n", RINGPTR_GET_RX(word), RINGPTR_GET_TX(word));
+	word = inw(iobase+VLSI_PIO_RINGBASE);
+	out += sprintf(out, "RINGBASE: busmap=0x%08x\n",
+		((unsigned)word << 10)|(MSTRPAGE_VALUE<<24));
+	word = inw(iobase+VLSI_PIO_RINGSIZE);
+	out += sprintf(out, "RINGSIZE: rx=%u / tx=%u\n", RINGSIZE_TO_RXSIZE(word),
+		RINGSIZE_TO_TXSIZE(word));
+
+	word = inw(iobase+VLSI_PIO_IRCFG);
+	out += sprintf(out, "IRCFG:%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+		(word&IRCFG_LOOP) ? " LOOP" : "",
+		(word&IRCFG_ENTX) ? " ENTX" : "",
+		(word&IRCFG_ENRX) ? " ENRX" : "",
+		(word&IRCFG_MSTR) ? " MSTR" : "",
+		(word&IRCFG_RXANY) ? " RXANY" : "",
+		(word&IRCFG_CRC16) ? " CRC16" : "",
+		(word&IRCFG_FIR) ? " FIR" : "",
+		(word&IRCFG_MIR) ? " MIR" : "",
+		(word&IRCFG_SIR) ? " SIR" : "",
+		(word&IRCFG_SIRFILT) ? " SIRFILT" : "",
+		(word&IRCFG_SIRTEST) ? " SIRTEST" : "",
+		(word&IRCFG_TXPOL) ? " TXPOL" : "",
+		(word&IRCFG_RXPOL) ? " RXPOL" : "");
+	word = inw(iobase+VLSI_PIO_IRENABLE);
+	out += sprintf(out, "IRENABLE:%s%s%s%s%s%s%s%s\n",
+		(word&IRENABLE_IREN) ? " IRENABLE" : "",
+		(word&IRENABLE_CFGER) ? " CFGERR" : "",
+		(word&IRENABLE_FIR_ON) ? " FIR_ON" : "",
+		(word&IRENABLE_MIR_ON) ? " MIR_ON" : "",
+		(word&IRENABLE_SIR_ON) ? " SIR_ON" : "",
+		(word&IRENABLE_ENTXST) ? " ENTXST" : "",
+		(word&IRENABLE_ENRXST) ? " ENRXST" : "",
+		(word&IRENABLE_CRC16_ON) ? " CRC16_ON" : "");
+	word = inw(iobase+VLSI_PIO_PHYCTL);
+	out += sprintf(out, "PHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n",
+		(unsigned)PHYCTL_TO_BAUD(word),
+		(unsigned)PHYCTL_TO_PLSWID(word),
+		(unsigned)PHYCTL_TO_PREAMB(word));
+	word = inw(iobase+VLSI_PIO_NPHYCTL);
+	out += sprintf(out, "NPHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n",
+		(unsigned)PHYCTL_TO_BAUD(word),
+		(unsigned)PHYCTL_TO_PLSWID(word),
+		(unsigned)PHYCTL_TO_PREAMB(word));
+	word = inw(iobase+VLSI_PIO_MAXPKT);
+	out += sprintf(out, "MAXPKT: max. rx packet size = %u\n", word);
+	word = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
+	out += sprintf(out, "RCVBCNT: rx-fifo filling level = %u\n", word);
+
+	out += sprintf(out, "\nsw-state:\n");
+	out += sprintf(out, "IrPHY setup: %d baud - %s encoding\n", idev->baud, 
+		(idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR"));
+	do_gettimeofday(&now);
+	if (now.tv_usec >= idev->last_rx.tv_usec) {
+		delta2 = now.tv_usec - idev->last_rx.tv_usec;
+		delta1 = 0;
+	}
+	else {
+		delta2 = 1000000 + now.tv_usec - idev->last_rx.tv_usec;
+		delta1 = 1;
+	}
+	out += sprintf(out, "last rx: %lu.%06u sec\n",
+		now.tv_sec - idev->last_rx.tv_sec - delta1, delta2);	
 
-	a &= DMA_MASK_MSTRPAGE;  /* clear highbyte to make sure we won't write
-				  * to status - just in case MSTRPAGE_VALUE!=0
-				  */
-	rd->rd_addr = a;
-	wmb();
-	rd->rd_status = s;	 /* potentially passes ownership to the hardware */
-}
+	out += sprintf(out, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu",
+		idev->stats.rx_packets, idev->stats.rx_bytes, idev->stats.rx_errors,
+		idev->stats.rx_dropped);
+	out += sprintf(out, " / overrun=%lu / length=%lu / frame=%lu / crc=%lu\n",
+		idev->stats.rx_over_errors, idev->stats.rx_length_errors,
+		idev->stats.rx_frame_errors, idev->stats.rx_crc_errors);
+	out += sprintf(out, "TX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu / fifo=%lu\n",
+		idev->stats.tx_packets, idev->stats.tx_bytes, idev->stats.tx_errors,
+		idev->stats.tx_dropped, idev->stats.tx_fifo_errors);
+
+	return out - buf;
+}
+		
+static int vlsi_proc_ring(struct vlsi_ring *r, char *buf, int len)
+{
+	struct ring_descr *rd;
+	unsigned i, j;
+	int h, t;
+	char *out = buf;
 
-static inline void rd_set_status(struct vlsi_ring *r, unsigned i, u8 s)
-{
-	r->hw[i].rd_status = s;
-}
+	if (len < 3000)
+		return 0;
 
-static inline void rd_set_count(struct vlsi_ring *r, unsigned i, u16 c)
-{
-	r->hw[i].rd_count = c;
+	out += sprintf(out, "size %u / mask 0x%04x / len %u / dir %d / hw %p\n",
+		r->size, r->mask, r->len, r->dir, r->rd[0].hw);
+	h = atomic_read(&r->head) & r->mask;
+	t = atomic_read(&r->tail) & r->mask;
+	out += sprintf(out, "head = %d / tail = %d ", h, t);
+	if (h == t)
+		out += sprintf(out, "(empty)\n");
+	else {
+		if (((t+1)&r->mask) == h)
+			out += sprintf(out, "(full)\n");
+		else
+			out += sprintf(out, "(level = %d)\n", ((unsigned)(t-h) & r->mask)); 
+		rd = &r->rd[h];
+		j = (unsigned) rd_get_count(rd);
+		out += sprintf(out, "current: rd = %d / status = %02x / len = %u\n",
+				h, (unsigned)rd_get_status(rd), j);
+		if (j > 0) {
+			out += sprintf(out, "   data:");
+			if (j > 20)
+				j = 20;
+			for (i = 0; i < j; i++)
+				out += sprintf(out, " %02x", (unsigned)((unsigned char *)rd->buf)[i]);
+			out += sprintf(out, "\n");
+		}
+	}
+	for (i = 0; i < r->size; i++) {
+		rd = &r->rd[i];
+		out += sprintf(out, "> ring descr %u: ", i);
+		out += sprintf(out, "skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw);
+		out += sprintf(out, "  hw: status=%02x count=%u busaddr=0x%08x\n",
+			(unsigned) rd_get_status(rd),
+			(unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd));
+	}
+	return out - buf;
 }
 
-static inline u8 rd_get_status(struct vlsi_ring *r, unsigned i)
+static int vlsi_proc_print(struct net_device *ndev, char *buf, int len)
 {
-	return r->hw[i].rd_status;
-}
+	vlsi_irda_dev_t *idev;
+	unsigned long flags;
+	char *out = buf;
 
-static inline dma_addr_t rd_get_addr(struct vlsi_ring *r, unsigned i)
-{
-	dma_addr_t	a;
+	if (!ndev || !ndev->priv) {
+		printk(KERN_ERR "%s: invalid ptr!\n", __FUNCTION__);
+		return 0;
+	}
 
-	a = (r->hw[i].rd_addr & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24);
-	return a;
-}
+	idev = ndev->priv;
 
-static inline u16 rd_get_count(struct vlsi_ring *r, unsigned i)
-{
-	return r->hw[i].rd_count;
-}
+	if (len < 8000)
+		return 0;
 
-/* producer advances r->head when descriptor was added for processing by hw */
+	out += sprintf(out, "\n%s %s\n\n", DRIVER_NAME, DRIVER_VERSION);
+	out += sprintf(out, "clksrc: %s\n", 
+		(clksrc>=2) ? ((clksrc==3)?"40MHz XCLK":"48MHz XCLK")
+			    : ((clksrc==1)?"48MHz PLL":"autodetect"));
+	out += sprintf(out, "ringsize: tx=%d / rx=%d\n",
+		ringsize[0], ringsize[1]);
+	out += sprintf(out, "sirpulse: %s\n", (sirpulse)?"3/16 bittime":"short");
+	out += sprintf(out, "qos_mtt_bits: 0x%02x\n", (unsigned)qos_mtt_bits);
 
-static inline void ring_put(struct vlsi_ring *r)
-{
-	r->head = (r->head + 1) & r->mask;
+	spin_lock_irqsave(&idev->lock, flags);
+	if (idev->pdev != NULL) {
+		out += vlsi_proc_pdev(idev->pdev, out, len - (out-buf));
+		if (idev->pdev->current_state == 0)
+			out += vlsi_proc_ndev(ndev, out, len - (out-buf));
+		else
+			out += sprintf(out, "\nPCI controller down - resume_ok = %d\n",
+				idev->resume_ok);
+		if (netif_running(ndev) && idev->rx_ring && idev->tx_ring) {
+			out += sprintf(out, "\n--------- RX ring -----------\n\n");
+			out += vlsi_proc_ring(idev->rx_ring, out, len - (out-buf));
+			out += sprintf(out, "\n--------- TX ring -----------\n\n");
+			out += vlsi_proc_ring(idev->tx_ring, out, len - (out-buf));
+		}
+	}
+	out += sprintf(out, "\n");
+	spin_unlock_irqrestore(&idev->lock, flags);
+
+	return out - buf;
 }
 
-/* consumer advances r->tail when descriptor was removed after getting processed by hw */
+static struct proc_dir_entry *vlsi_proc_root = NULL;
+
+struct vlsi_proc_data {
+	int size;
+	char *data;
+};
+
+/* most of the proc-fops code borrowed from usb/uhci */
 
-static inline void ring_get(struct vlsi_ring *r)
+static int vlsi_proc_open(struct inode *inode, struct file *file)
 {
-	r->tail = (r->tail + 1) & r->mask;
+	const struct proc_dir_entry *pde = PDE(inode);
+	struct net_device *ndev = pde->data;
+	vlsi_irda_dev_t *idev = ndev->priv;
+	struct vlsi_proc_data *procdata;
+	const int maxdata = 8000;
+
+	lock_kernel();
+	procdata = kmalloc(sizeof(*procdata), GFP_KERNEL);
+	if (!procdata) {
+		unlock_kernel();
+		return -ENOMEM;
+	}
+	procdata->data = kmalloc(maxdata, GFP_KERNEL);
+	if (!procdata->data) {
+		kfree(procdata);
+		unlock_kernel();
+		return -ENOMEM;
+	}
+
+	down(&idev->sem);
+	procdata->size = vlsi_proc_print(ndev, procdata->data, maxdata);
+	up(&idev->sem);
+
+	file->private_data = procdata;
+
+	return 0;
 }
 
+static loff_t vlsi_proc_lseek(struct file *file, loff_t off, int whence)
+{
+	struct vlsi_proc_data *procdata;
+	loff_t new = -1;
 
-/********************************************************/
+	lock_kernel();
+	procdata = file->private_data;
+
+	switch (whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	}
+	if (new < 0 || new > procdata->size) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	unlock_kernel();
+	return (file->f_pos = new);
+}
 
-/* the memory required to hold the 2 descriptor rings */
+static ssize_t vlsi_proc_read(struct file *file, char *buf, size_t nbytes,
+			loff_t *ppos)
+{
+	struct vlsi_proc_data *procdata = file->private_data;
+	unsigned int pos;
+	unsigned int size;
 
-#define RING_AREA_SIZE		(2 * MAX_RING_DESCR * sizeof(struct ring_descr))
+	pos = *ppos;
+	size = procdata->size;
+	if (pos >= size)
+		return 0;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
 
-/* the memory required to hold the rings' buffer entries */
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EINVAL;
 
-#define RING_ENTRY_SIZE		(2 * MAX_RING_DESCR * sizeof(struct ring_entry))
+	copy_to_user(buf, procdata->data + pos, nbytes);
 
-/********************************************************/
+	*ppos += nbytes;
 
-/* just dump all registers */
+	return nbytes;
+}
 
-static void vlsi_reg_debug(unsigned iobase, const char *s)
+static int vlsi_proc_release(struct inode *inode, struct file *file)
 {
-	int	i;
+	struct vlsi_proc_data *procdata = file->private_data;
 
-	mb();
-	printk(KERN_DEBUG "%s: ", s);
-	for (i = 0; i < 0x20; i++)
-		printk("%02x", (unsigned)inb((iobase+i)));
-	printk("\n");
+	kfree(procdata->data);
+	kfree(procdata);
+
+	return 0;
 }
 
-/********************************************************/
+static struct file_operations vlsi_proc_fops = {
+	open:		vlsi_proc_open,
+	llseek:		vlsi_proc_lseek,
+	read:		vlsi_proc_read,
+	release:	vlsi_proc_release,
+};
+#endif
 
+/********************************************************/
 
-static int vlsi_set_clock(struct pci_dev *pdev)
+static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr_hw *hwmap,
+						unsigned size, unsigned len, int dir)
 {
-	u8	clkctl, lock;
-	int	i, count;
+	struct vlsi_ring *r;
+	struct ring_descr *rd;
+	unsigned	i, j;
+	dma_addr_t	busaddr;
 
-	if (clksrc < 2) { /* auto or PLL: try PLL */
-		clkctl = CLKCTL_NO_PD | CLKCTL_CLKSTP;
-		pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
+	if (!size  ||  ((size-1)&size)!=0)	/* must be >0 and power of 2 */
+		return NULL;
 
-		/* procedure to detect PLL lock synchronisation:
-		 * after 0.5 msec initial delay we expect to find 3 PLL lock
-		 * indications within 10 msec for successful PLL detection.
-		 */
-		udelay(500);
-		count = 0;
-		for (i = 500; i <= 10000; i += 50) { /* max 10 msec */
-			pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &lock);
-			if (lock&CLKCTL_LOCK) {
-				if (++count >= 3)
-					break;
-			}
-			udelay(50);
-		}
-		if (count < 3) {
-			if (clksrc == 1) { /* explicitly asked for PLL hence bail out */
-				printk(KERN_ERR "%s: no PLL or failed to lock!\n",
-					__FUNCTION__);
-				clkctl = CLKCTL_CLKSTP;
-				pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-				return -1;
+	r = kmalloc(sizeof(*r) + size * sizeof(struct ring_descr), GFP_KERNEL);
+	if (!r)
+		return NULL;
+	memset(r, 0, sizeof(*r));
+
+	r->pdev = pdev;
+	r->dir = dir;
+	r->len = len;
+	r->rd = (struct ring_descr *)(r+1);
+	r->mask = size - 1;
+	r->size = size;
+	atomic_set(&r->head, 0);
+	atomic_set(&r->tail, 0);
+
+	for (i = 0; i < size; i++) {
+		rd = r->rd + i;
+		memset(rd, 0, sizeof(*rd));
+		rd->hw = hwmap + i;
+		rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA);
+		if (rd->buf == NULL) {
+			for (j = 0; j < i; j++) {
+				rd = r->rd + j;
+				busaddr = rd_get_addr(rd);
+				rd_set_addr_status(rd, 0, 0);
+				if (busaddr)
+					pci_unmap_single(pdev, busaddr, len, dir);
+				kfree(rd->buf);
+				rd->buf = NULL;
 			}
-			else			/* was: clksrc=0(auto) */
-				clksrc = 3;	/* fallback to 40MHz XCLK (OB800) */
-
-			printk(KERN_INFO "%s: PLL not locked, fallback to clksrc=%d\n",
-				__FUNCTION__, clksrc);
+			kfree(r);
+			return NULL;
 		}
-		else { /* got successful PLL lock */
-			clksrc = 1;
-			return 0;
+		busaddr = pci_map_single(pdev, rd->buf, len, dir);
+		if (!busaddr) {
+			printk(KERN_ERR "%s: failed to create PCI-MAP for %p",
+				__FUNCTION__, rd->buf);
+			BUG();
 		}
+		rd_set_addr_status(rd, busaddr, 0);
+		pci_dma_sync_single(pdev, busaddr, len, dir);
+		/* initially, the dma buffer is owned by the CPU */
+		rd->skb = NULL;
 	}
+	return r;
+}
 
-	/* we get here if either no PLL detected in auto-mode or
-	   the external clock source was explicitly specified */
-
-	clkctl = CLKCTL_EXTCLK | CLKCTL_CLKSTP;
-	if (clksrc == 3)
-		clkctl |= CLKCTL_XCKSEL;	
-	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-
-	/* no way to test for working XCLK */
+static int vlsi_free_ring(struct vlsi_ring *r)
+{
+	struct ring_descr *rd;
+	unsigned	i;
+	dma_addr_t	busaddr;
 
+	for (i = 0; i < r->size; i++) {
+		rd = r->rd + i;
+		if (rd->skb)
+			dev_kfree_skb_any(rd->skb);
+		busaddr = rd_get_addr(rd);
+		rd_set_addr_status(rd, 0, 0);
+		if (busaddr)
+			pci_unmap_single(r->pdev, busaddr, r->len, r->dir);
+		if (rd->buf)
+			kfree(rd->buf);
+	}
+	kfree(r);
 	return 0;
 }
 
-
-static void vlsi_start_clock(struct pci_dev *pdev)
+static int vlsi_create_hwif(vlsi_irda_dev_t *idev)
 {
-	u8	clkctl;
+	char 			*ringarea;
+	struct ring_descr_hw	*hwmap;
 
-	printk(KERN_INFO "%s: start clock using %s as input\n", __FUNCTION__,
-		(clksrc&2)?((clksrc&1)?"40MHz XCLK":"48MHz XCLK"):"48MHz PLL");
-	pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);
-	clkctl &= ~CLKCTL_CLKSTP;
-	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
-}
-			
+	idev->virtaddr = NULL;
+	idev->busaddr = 0;
 
-static void vlsi_stop_clock(struct pci_dev *pdev)
-{
-	u8	clkctl;
+	ringarea = pci_alloc_consistent(idev->pdev, HW_RING_AREA_SIZE, &idev->busaddr);
+	if (!ringarea) {
+		printk(KERN_ERR "%s: insufficient memory for descriptor rings\n",
+			__FUNCTION__);
+		goto out;
+	}
+	memset(ringarea, 0, HW_RING_AREA_SIZE);
 
-	pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);
-	clkctl |= CLKCTL_CLKSTP;
-	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
+	hwmap = (struct ring_descr_hw *)ringarea;
+	idev->rx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[1],
+					XFER_BUF_SIZE, PCI_DMA_FROMDEVICE);
+	if (idev->rx_ring == NULL)
+		goto out_unmap;
+
+	hwmap += MAX_RING_DESCR;
+	idev->tx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[0],
+					XFER_BUF_SIZE, PCI_DMA_TODEVICE);
+	if (idev->tx_ring == NULL)
+		goto out_free_rx;
+
+	idev->virtaddr = ringarea;
+	return 0;
+
+out_free_rx:
+	vlsi_free_ring(idev->rx_ring);
+out_unmap:
+	idev->rx_ring = idev->tx_ring = NULL;
+	pci_free_consistent(idev->pdev, HW_RING_AREA_SIZE, ringarea, idev->busaddr);
+	idev->busaddr = 0;
+out:
+	return -ENOMEM;
 }
-			
 
-static void vlsi_unset_clock(struct pci_dev *pdev)
+static int vlsi_destroy_hwif(vlsi_irda_dev_t *idev)
 {
-	u8	clkctl;
+	vlsi_free_ring(idev->rx_ring);
+	vlsi_free_ring(idev->tx_ring);
+	idev->rx_ring = idev->tx_ring = NULL;
 
-	pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);
-	if (!(clkctl&CLKCTL_CLKSTP))
-		/* make sure clock is already stopped */
-		vlsi_stop_clock(pdev);
+	if (idev->busaddr)
+		pci_free_consistent(idev->pdev,HW_RING_AREA_SIZE,idev->virtaddr,idev->busaddr);
 
-	clkctl &= ~(CLKCTL_EXTCLK | CLKCTL_NO_PD);
-	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
+	idev->virtaddr = NULL;
+	idev->busaddr = 0;
+
+	return 0;
 }
 
 /********************************************************/
 
-
-/* ### FIXME: don't use old virt_to_bus() anymore! */
-
-
-static void vlsi_arm_rx(struct vlsi_ring *r)
+static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd)
 {
-	unsigned	i;
-	dma_addr_t	ba;
+	u16		status;
+	int		crclen, len = 0;
+	struct sk_buff	*skb;
+	int		ret = 0;
+	struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev);
+	vlsi_irda_dev_t *idev = ndev->priv;
 
-	for (i = 0; i < r->size; i++) {
-		if (r->buf[i].data == NULL)
-			BUG();
-		ba = virt_to_bus(r->buf[i].data);
-		rd_set_addr_status(r, i, ba, RD_STAT_ACTIVE);
+	pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+	/* dma buffer now owned by the CPU */
+	status = rd_get_status(rd);
+	if (status & RD_RX_ERROR) {
+		if (status & RD_RX_OVER)  
+			ret |= VLSI_RX_OVER;
+		if (status & RD_RX_LENGTH)  
+			ret |= VLSI_RX_LENGTH;
+		if (status & RD_RX_PHYERR)  
+			ret |= VLSI_RX_FRAME;
+		if (status & RD_RX_CRCERR)  
+			ret |= VLSI_RX_CRC;
+	}
+	else {
+		len = rd_get_count(rd);
+		crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16);
+		len -= crclen;		/* remove trailing CRC */
+		if (len <= 0) {
+			printk(KERN_ERR "%s: strange frame (len=%d)\n",
+				__FUNCTION__, len);
+			ret |= VLSI_RX_DROP;
+		}
+		else if (!rd->skb) {
+			printk(KERN_ERR "%s: rx packet dropped\n", __FUNCTION__);
+			ret |= VLSI_RX_DROP;
+		}
+		else {
+			skb = rd->skb;
+			rd->skb = NULL;
+			skb->dev = ndev;
+			memcpy(skb_put(skb,len), rd->buf, len);
+			skb->mac.raw = skb->data;
+			if (in_interrupt())
+				netif_rx(skb);
+			else
+				netif_rx_ni(skb);
+			ndev->last_rx = jiffies;
+		}
 	}
+	rd_set_status(rd, 0);
+	rd_set_count(rd, 0);
+	/* buffer still owned by CPU */
+
+	return (ret) ? -ret : len;
 }
 
-static int vlsi_alloc_ringbuf(struct vlsi_ring *r)
+static void vlsi_fill_rx(struct vlsi_ring *r)
 {
-	unsigned	i, j;
+	struct ring_descr *rd;
 
-	r->head = r->tail = 0;
-	r->mask = r->size - 1;
-	for (i = 0; i < r->size; i++) {
-		r->buf[i].skb = NULL;
-		r->buf[i].data = kmalloc(XFER_BUF_SIZE, GFP_KERNEL|GFP_DMA);
-		if (r->buf[i].data == NULL) {
-			for (j = 0; j < i; j++) {
-				kfree(r->buf[j].data);
-				r->buf[j].data = NULL;
+	for (rd = ring_last(r); rd != NULL; rd = ring_put(r)) {
+		if (rd_is_active(rd)) {
+			BUG();
+			break;
+		}
+		if (!rd->skb) {
+			rd->skb = dev_alloc_skb(IRLAP_SKB_ALLOCSIZE);
+			if (rd->skb) {
+				skb_reserve(rd->skb,1);
+				rd->skb->protocol = htons(ETH_P_IRDA);
 			}
-			return -ENOMEM;
+			else
+				break;	/* probably not worth logging? */
 		}
+		/* give dma buffer back to busmaster */
+		pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+		rd_activate(rd);
 	}
-	return 0;
 }
 
-static void vlsi_free_ringbuf(struct vlsi_ring *r)
+static void vlsi_rx_interrupt(struct net_device *ndev)
 {
-	unsigned	i;
+	vlsi_irda_dev_t *idev = ndev->priv;
+	struct vlsi_ring *r = idev->rx_ring;
+	struct ring_descr *rd;
+	int ret;
 
-	for (i = 0; i < r->size; i++) {
-		if (r->buf[i].data == NULL)
-			continue;
-		if (r->buf[i].skb) {
-			dev_kfree_skb(r->buf[i].skb);
-			r->buf[i].skb = NULL;
+	for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
+
+		if (rd_is_active(rd))
+			break;
+
+		ret = vlsi_process_rx(r, rd);
+
+		if (ret < 0) {
+			ret = -ret;
+			idev->stats.rx_errors++;
+			if (ret & VLSI_RX_DROP)  
+				idev->stats.rx_dropped++;
+			if (ret & VLSI_RX_OVER)  
+				idev->stats.rx_over_errors++;
+			if (ret & VLSI_RX_LENGTH)  
+				idev->stats.rx_length_errors++;
+			if (ret & VLSI_RX_FRAME)  
+				idev->stats.rx_frame_errors++;
+			if (ret & VLSI_RX_CRC)  
+				idev->stats.rx_crc_errors++;
 		}
-		else
-			kfree(r->buf[i].data);
-		r->buf[i].data = NULL;
+		else if (ret > 0) {
+			idev->stats.rx_packets++;
+			idev->stats.rx_bytes += ret;
+		}
+	}
+
+	do_gettimeofday(&idev->last_rx); /* remember "now" for later mtt delay */
+
+	vlsi_fill_rx(r);
+
+	if (ring_first(r) == NULL) {
+		/* we are in big trouble, if this should ever happen */
+		printk(KERN_ERR "%s: rx ring exhausted!\n", __FUNCTION__);
+		vlsi_ring_debug(r);
 	}
+	else
+		outw(0, ndev->base_addr+VLSI_PIO_PROMPT);
 }
 
+/* caller must have stopped the controller from busmastering */
 
-static int vlsi_init_ring(vlsi_irda_dev_t *idev)
+static void vlsi_unarm_rx(vlsi_irda_dev_t *idev)
 {
-	char 		 *ringarea;
+	struct vlsi_ring *r = idev->rx_ring;
+	struct ring_descr *rd;
+	int ret;
 
-	ringarea = pci_alloc_consistent(idev->pdev, RING_AREA_SIZE, &idev->busaddr);
-	if (!ringarea) {
-		printk(KERN_ERR "%s: insufficient memory for descriptor rings\n",
-			__FUNCTION__);
-		return -ENOMEM;
-	}
-	memset(ringarea, 0, RING_AREA_SIZE);
+	for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
 
-#if 0
-	printk(KERN_DEBUG "%s: (%d,%d)-ring %p / %p\n", __FUNCTION__,
-		ringsize[0], ringsize[1], ringarea, 
-		(void *)(unsigned)idev->busaddr);
-#endif
+		ret = 0;
+		if (rd_is_active(rd)) {
+			rd_set_status(rd, 0);
+			if (rd_get_count(rd)) {
+				printk(KERN_INFO "%s - dropping rx packet\n", __FUNCTION__);
+				ret = -VLSI_RX_DROP;
+			}
+			rd_set_count(rd, 0);
+			pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+			if (rd->skb) {
+				dev_kfree_skb_any(rd->skb);
+				rd->skb = NULL;
+			}
+		}
+		else
+			ret = vlsi_process_rx(r, rd);
 
-	idev->rx_ring.size = ringsize[1];
-	idev->rx_ring.hw = (struct ring_descr *)ringarea;
-	if (!vlsi_alloc_ringbuf(&idev->rx_ring)) {
-		idev->tx_ring.size = ringsize[0];
-		idev->tx_ring.hw = idev->rx_ring.hw + MAX_RING_DESCR;
-		if (!vlsi_alloc_ringbuf(&idev->tx_ring)) {
-			idev->virtaddr = ringarea;
-			return 0;
+		if (ret < 0) {
+			ret = -ret;
+			idev->stats.rx_errors++;
+			if (ret & VLSI_RX_DROP)  
+				idev->stats.rx_dropped++;
+			if (ret & VLSI_RX_OVER)  
+				idev->stats.rx_over_errors++;
+			if (ret & VLSI_RX_LENGTH)  
+				idev->stats.rx_length_errors++;
+			if (ret & VLSI_RX_FRAME)  
+				idev->stats.rx_frame_errors++;
+			if (ret & VLSI_RX_CRC)  
+				idev->stats.rx_crc_errors++;
+		}
+		else if (ret > 0) {
+			idev->stats.rx_packets++;
+			idev->stats.rx_bytes += ret;
 		}
-		vlsi_free_ringbuf(&idev->rx_ring);
 	}
-
-	pci_free_consistent(idev->pdev, RING_AREA_SIZE,
-		ringarea, idev->busaddr);
-	printk(KERN_ERR "%s: insufficient memory for ring buffers\n",
-		__FUNCTION__);
-	return -1;
 }
 
+/********************************************************/
 
+static int vlsi_process_tx(struct vlsi_ring *r, struct ring_descr *rd)
+{
+	u16		status;
+	int		len;
+	int		ret;
+
+	pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+	/* dma buffer now owned by the CPU */
+	status = rd_get_status(rd);
+	if (status & RD_TX_UNDRN)
+		ret = VLSI_TX_FIFO;
+	else
+		ret = 0;
+	rd_set_status(rd, 0);
 
-/********************************************************/
+	if (rd->skb) {
+		len = rd->skb->len;
+		dev_kfree_skb_any(rd->skb);
+		rd->skb = NULL;
+	}
+	else	/* tx-skb already freed? - should never happen */
+		len = rd_get_count(rd);		/* incorrect for SIR! (due to wrapping) */
 
+	rd_set_count(rd, 0);
+	/* dma buffer still owned by the CPU */
 
+	return (ret) ? -ret : len;
+}
 
-static int vlsi_set_baud(struct net_device *ndev)
+static int vlsi_set_baud(struct net_device *ndev, int dolock)
 {
 	vlsi_irda_dev_t *idev = ndev->priv;
 	unsigned long flags;
@@ -431,18 +853,16 @@
 	unsigned iobase; 
 	u16 config;
 	unsigned mode;
+	unsigned idle_retry;
 	int	ret;
 	int	baudrate;
+	int	fifocnt = 0;	/* Keep compiler happy */
 
 	baudrate = idev->new_baud;
 	iobase = ndev->base_addr;
-
+#if 0
 	printk(KERN_DEBUG "%s: %d -> %d\n", __FUNCTION__, idev->baud, idev->new_baud);
-
-	spin_lock_irqsave(&idev->lock, flags);
-
-	outw(0, iobase+VLSI_PIO_IRENABLE);
-
+#endif
 	if (baudrate == 4000000) {
 		mode = IFF_FIR;
 		config = IRCFG_FIR;
@@ -455,7 +875,7 @@
 	}
 	else {
 		mode = IFF_SIR;
-		config = IRCFG_SIR | IRCFG_SIRFILT | IRCFG_RXANY;
+		config = IRCFG_SIR | IRCFG_SIRFILT  | IRCFG_RXANY;
 		switch(baudrate) {
 			default:
 				printk(KERN_ERR "%s: undefined baudrate %d - fallback to 9600!\n",
@@ -473,6 +893,32 @@
 		}
 	}
 
+	if (dolock)
+		spin_lock_irqsave(&idev->lock, flags);
+	else
+		flags = 0xdead;	/* prevent bogus warning about possible uninitialized use */
+
+	for (idle_retry=0; idle_retry < 100; idle_retry++) {
+		fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
+		if (fifocnt == 0)
+			break;
+		if (!idle_retry)
+			printk(KERN_WARNING "%s: waiting for rx fifo to become empty(%d)\n",
+				__FUNCTION__, fifocnt);
+		if (dolock) {
+			spin_unlock_irqrestore(&idev->lock, flags);
+			udelay(100);
+			spin_lock_irqsave(&idev->lock, flags);
+		}
+		else
+			udelay(100);
+	}
+	if (fifocnt != 0)
+		printk(KERN_ERR "%s: rx fifo not empty(%d)\n", __FUNCTION__, fifocnt);
+
+	outw(0, iobase+VLSI_PIO_IRENABLE);
+	wmb();
+
 	config |= IRCFG_MSTR | IRCFG_ENRX;
 
 	outw(config, iobase+VLSI_PIO_IRCFG);
@@ -480,10 +926,12 @@
 	outw(nphyctl, iobase+VLSI_PIO_NPHYCTL);
 	wmb();
 	outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE);
+	mb();
 
-	/* chip fetches IRCFG on next rising edge of its 8MHz clock */
+	udelay(1);	/* chip applies IRCFG on next rising edge of its 8MHz clock */
+
+	/* read back settings for validation */
 
-	mb();
 	config = inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_MASK;
 
 	if (mode == IFF_FIR)
@@ -493,7 +941,6 @@
 	else
 		config ^= IRENABLE_SIR_ON;
 
-
 	if (config != (IRENABLE_IREN|IRENABLE_ENRXST)) {
 		printk(KERN_ERR "%s: failed to set %s mode!\n", __FUNCTION__,
 			(mode==IFF_SIR)?"SIR":((mode==IFF_MIR)?"MIR":"FIR"));
@@ -512,7 +959,8 @@
 			ret = 0;
 		}
 	}
-	spin_unlock_irqrestore(&idev->lock, flags);
+	if (dolock)
+		spin_unlock_irqrestore(&idev->lock, flags);
 
 	if (ret)
 		vlsi_reg_debug(iobase,__FUNCTION__);
@@ -520,278 +968,396 @@
 	return ret;
 }
 
+static inline int vlsi_set_baud_lock(struct net_device *ndev)
+{
+	return vlsi_set_baud(ndev, 1);
+}
 
+static inline int vlsi_set_baud_nolock(struct net_device *ndev)
+{
+	return vlsi_set_baud(ndev, 0);
+}
 
-static int vlsi_init_chip(struct net_device *ndev)
+static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
 	vlsi_irda_dev_t *idev = ndev->priv;
-	unsigned	iobase;
-	u16 ptr;
-
-	iobase = ndev->base_addr;
-
-	outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* w/c pending IRQ, disable all INT */
-
-	outw(0, iobase+VLSI_PIO_IRENABLE);	/* disable IrPHY-interface */
+	struct vlsi_ring	*r = idev->tx_ring;
+	struct ring_descr *rd;
+	unsigned long flags;
+	unsigned iobase = ndev->base_addr;
+	u8 status;
+	u16 config;
+	int mtt;
+	int len, speed;
+	struct timeval  now, ready;
 
-	/* disable everything, particularly IRCFG_MSTR - which resets the RING_PTR */
+	speed = irda_get_next_speed(skb);
+	if (speed != -1  &&  speed != idev->baud) {
+		netif_stop_queue(ndev);
+		idev->new_baud = speed;
+		if (!skb->len) {
+			dev_kfree_skb_any(skb);
 
-	outw(0, iobase+VLSI_PIO_IRCFG);
-	wmb();
-	outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE);
+			/* due to the completely asynch tx operation we might have
+			 * IrLAP racing with the hardware here, f.e. if the controller
+			 * is just sending the last packet with current speed while
+			 * the LAP is already switching the speed using synchronous
+			 * len=0 packet. Immediate execution would lead to hw lockup
+			 * requiring a powercycle to reset. Good candidate to trigger
+			 * this is the final UA:RSP packet after receiving a DISC:CMD
+			 * when getting the LAP down.
+			 * Note that we are not protected by the queue_stop approach
+			 * because the final UA:RSP arrives _without_ request to apply
+			 * new-speed-after-this-packet - hence the driver doesn't know
+			 * this was the last packet and doesn't stop the queue. So the
+			 * forced switch to default speed from LAP gets through as fast
+			 * as only some 10 usec later while the UA:RSP is still processed
+			 * by the hardware and we would get screwed.
+			 * Note: no locking required since we (netdev->xmit) are the only
+			 * supplier for tx and the network layer provides serialization
+			 */
+			spin_lock_irqsave(&idev->lock, flags);
+			if (ring_first(idev->tx_ring) == NULL) {
+				/* no race - tx-ring already empty */
+				vlsi_set_baud_nolock(ndev);
+				netif_wake_queue(ndev);
+			}
+			else
+				; /* keep the speed change pending like it would
+				   * for any len>0 packet. tx completion interrupt
+				   * will apply it when the tx ring becomes empty.
+				   */
+			spin_unlock_irqrestore(&idev->lock, flags);
+			return 0;
+		}
+		status = RD_TX_CLRENTX;  /* stop tx-ring after this frame */
+	}
+	else
+		status = 0;
 
-	mb();
+	if (skb->len == 0) {
+		printk(KERN_ERR "%s: dropping len=0 packet\n", __FUNCTION__);
+		goto drop;
+	}
 
-	outw(0, iobase+VLSI_PIO_IRENABLE);
+	/* sanity checks - should never happen!
+	 * simply BUGging the violation and dropping the packet
+	 */
 
-	outw(MAX_PACKET_LENGTH, iobase+VLSI_PIO_MAXPKT);  /* max possible value=0x0fff */
+	rd = ring_last(r);
+	if (!rd) {				/* ring full - queue should have been stopped! */
+		BUG();
+		goto drop;
+	}
 
-	outw(BUS_TO_RINGBASE(idev->busaddr), iobase+VLSI_PIO_RINGBASE);
+	if (rd_is_active(rd)) {			/* entry still owned by hw! */
+		BUG();
+		goto drop;
+	}
 
-	outw(TX_RX_TO_RINGSIZE(idev->tx_ring.size, idev->rx_ring.size),
-		iobase+VLSI_PIO_RINGSIZE);	
+	if (!rd->buf) {				/* no memory for this tx entry - weird! */
+		BUG();
+		goto drop;
+	}
 
-	ptr = inw(iobase+VLSI_PIO_RINGPTR);
-	idev->rx_ring.head = idev->rx_ring.tail = RINGPTR_GET_RX(ptr);
-	idev->tx_ring.head = idev->tx_ring.tail = RINGPTR_GET_TX(ptr);
+	if (rd->skb) {				/* hm, associated old skb still there */
+		BUG();
+		goto drop;
+	}
 
-	outw(IRCFG_MSTR, iobase+VLSI_PIO_IRCFG);		/* ready for memory access */
-	wmb();
-	outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE);
+	/* tx buffer already owned by CPU due to pci_dma_sync_single() either
+	 * after initial pci_map_single or after subsequent tx-completion
+	 */
 
-	mb();
+	if (idev->mode == IFF_SIR) {
+		status |= RD_TX_DISCRC;		/* no hw-crc creation */
+		len = async_wrap_skb(skb, rd->buf, r->len);
 
-	idev->new_baud = 9600;		/* start with IrPHY using 9600(SIR) mode */
-	vlsi_set_baud(ndev);
+		/* Some rare worst case situation in SIR mode might lead to
+		 * potential buffer overflow. The wrapper detects this, returns
+		 * with a shortened frame (without FCS/EOF) but doesn't provide
+		 * any error indication about the invalid packet which we are
+		 * going to transmit.
+		 * Therefore we log if the buffer got filled to the point, where the
+		 * wrapper would abort, i.e. when there are less than 5 bytes left to
+		 * allow appending the FCS/EOF.
+		 */
 
-	outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR);	/* just in case - w/c pending IRQ's */
-	wmb();
+		if (len >= r->len-5)
+			 printk(KERN_WARNING "%s: possible buffer overflow with SIR wrapping!\n",
+			 	__FUNCTION__);
+	}
+	else {
+		/* hw deals with MIR/FIR mode wrapping */
+		status |= RD_TX_PULSE;		/* send 2 us highspeed indication pulse */
+		len = skb->len;
+		if (len > r->len) {
+			printk(KERN_ERR "%s: no space - skb too big (%d)\n",
+				__FUNCTION__, skb->len);
+			goto drop;
+		}
+		else
+			memcpy(rd->buf, skb->data, len);
+	}
 
-	/* DO NOT BLINDLY ENABLE IRINTR_ACTEN!
-	 * basically every received pulse fires an ACTIVITY-INT
-	 * leading to >>1000 INT's per second instead of few 10
-	 */
+	/* do mtt delay before we need to disable interrupts! */
 
-	outb(IRINTR_RPKTEN|IRINTR_TPKTEN, iobase+VLSI_PIO_IRINTR);
-	wmb();
+	if ((mtt = irda_get_mtt(skb)) > 0) {
+	
+		ready.tv_usec = idev->last_rx.tv_usec + mtt;
+		ready.tv_sec = idev->last_rx.tv_sec;
+		if (ready.tv_usec >= 1000000) {
+			ready.tv_usec -= 1000000;
+			ready.tv_sec++;		/* IrLAP 1.1: mtt always < 1 sec */
+		}
+		for(;;) {
+			do_gettimeofday(&now);
+			if (now.tv_sec > ready.tv_sec
+			    ||  (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec))
+			    	break;
+			udelay(100);
+			/* must not sleep here - we are called under xmit_lock! */
+		}
+	}
 
-	return 0;
-}
+	rd->skb = skb;			/* remember skb for tx-complete stats */
 
+	rd_set_count(rd, len);
+	rd_set_status(rd, status);	/* not yet active! */
 
-/**************************************************************/
+	/* give dma buffer back to busmaster-hw (flush caches to make
+	 * CPU-driven changes visible from the pci bus).
+	 */
 
+	pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
 
-static void vlsi_refill_rx(struct vlsi_ring *r)
-{
-	do {
-		if (rd_is_active(r, r->head))
-			BUG();
-		rd_activate(r, r->head);
-		ring_put(r);
-	} while (r->head != r->tail);
-}
+/*
+ *	We need to disable IR output in order to switch to TX mode.
+ *	Better not do this blindly anytime we want to transmit something
+ *	because TX may already run. However we are racing with the controller
+ *	which may stop TX at any time when fetching an inactive descriptor
+ *	or one with CLR_ENTX set. So we switch on TX only, if TX was not running
+ *	_after_ the new descriptor was activated on the ring. This ensures
+ *	we will either find TX already stopped or we can be sure, there
+ *	will be a TX-complete interrupt even if the chip stopped doing
+ *	TX just after we found it still running. The ISR will then find
+ *	the non-empty ring and restart TX processing. The enclosing
+ *	spinlock provides the correct serialization to prevent race with isr.
+ */
 
+	spin_lock_irqsave(&idev->lock,flags);
 
-static int vlsi_rx_interrupt(struct net_device *ndev)
-{
-	vlsi_irda_dev_t *idev = ndev->priv;
-	struct vlsi_ring *r;
-	int	len;
-	u8	status;
-	struct sk_buff	*skb;
-	int	crclen;
+	rd_activate(rd);
 
-	r = &idev->rx_ring;
-	while (!rd_is_active(r, r->tail)) {
+	if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) {
+		int fifocnt;
 
-		status = rd_get_status(r, r->tail);
-		if (status & RX_STAT_ERROR) {
-			idev->stats.rx_errors++;
-			if (status & RX_STAT_OVER)  
-				idev->stats.rx_over_errors++;
-			if (status & RX_STAT_LENGTH)  
-				idev->stats.rx_length_errors++;
-			if (status & RX_STAT_PHYERR)  
-				idev->stats.rx_frame_errors++;
-			if (status & RX_STAT_CRCERR)  
-				idev->stats.rx_crc_errors++;
-		}
-		else {
-			len = rd_get_count(r, r->tail);
-			crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16);
-			if (len < crclen)
-				printk(KERN_ERR "%s: strange frame (len=%d)\n",
-					__FUNCTION__, len);
-			else
-				len -= crclen;		/* remove trailing CRC */
+		fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
+		if (fifocnt != 0)
+			printk(KERN_WARNING "%s: rx fifo not empty(%d)\n",
+				__FUNCTION__, fifocnt);
 
-			skb = dev_alloc_skb(len+1);
-			if (skb) {
-				skb->dev = ndev;
-				skb_reserve(skb,1);
-				memcpy(skb_put(skb,len), r->buf[r->tail].data, len);
-				idev->stats.rx_packets++;
-				idev->stats.rx_bytes += len;
-				skb->mac.raw = skb->data;
-				skb->protocol = htons(ETH_P_IRDA);
-				netif_rx(skb);				
-				ndev->last_rx = jiffies;
-			}
-			else {
-				idev->stats.rx_dropped++;
-				printk(KERN_ERR "%s: rx packet dropped\n", __FUNCTION__);
-			}
-		}
-		rd_set_count(r, r->tail, 0);
-		rd_set_status(r, r->tail, 0);
-		ring_get(r);
-		if (r->tail == r->head) {
-			printk(KERN_WARNING "%s: rx ring exhausted\n", __FUNCTION__);
-			break;
-		}
+		config = inw(iobase+VLSI_PIO_IRCFG);
+		rmb();
+		outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG);
+		mb();
+		outw(0, iobase+VLSI_PIO_PROMPT);
 	}
+	ndev->trans_start = jiffies;
 
-	do_gettimeofday(&idev->last_rx); /* remember "now" for later mtt delay */
-
-	vlsi_refill_rx(r);
-
-	mb();
-	outw(0, ndev->base_addr+VLSI_PIO_PROMPT);
+	if (ring_put(r) == NULL) {
+		netif_stop_queue(ndev);
+		printk(KERN_DEBUG "%s: tx ring full - queue stopped\n", __FUNCTION__);
+	}
+	spin_unlock_irqrestore(&idev->lock, flags);
 
 	return 0;
-}
 
+drop:
+	dev_kfree_skb_any(skb);
+	idev->stats.tx_errors++;
+	idev->stats.tx_dropped++;
+	return 1;
+}
 
-static int vlsi_tx_interrupt(struct net_device *ndev)
+static void vlsi_tx_interrupt(struct net_device *ndev)
 {
 	vlsi_irda_dev_t *idev = ndev->priv;
-	struct vlsi_ring	*r;
+	struct vlsi_ring	*r = idev->tx_ring;
+	struct ring_descr	*rd;
 	unsigned	iobase;
 	int	ret;
 	u16	config;
-	u16	status;
 
-	r = &idev->tx_ring;
-	while (!rd_is_active(r, r->tail)) {
-		if (r->tail == r->head)
-			break;	/* tx ring empty - nothing to send anymore */
+	for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
+
+		if (rd_is_active(rd))
+			break;
+
+		ret = vlsi_process_tx(r, rd);
 
-		status = rd_get_status(r, r->tail);
-		if (status & TX_STAT_UNDRN) {
+		if (ret < 0) {
+			ret = -ret;
 			idev->stats.tx_errors++;
-			idev->stats.tx_fifo_errors++;
+			if (ret & VLSI_TX_DROP)
+				idev->stats.tx_dropped++;
+			if (ret & VLSI_TX_FIFO)
+				idev->stats.tx_fifo_errors++;
 		}
-		else {
+		else if (ret > 0){
 			idev->stats.tx_packets++;
-			idev->stats.tx_bytes += rd_get_count(r, r->tail); /* not correct for SIR */
-		}
-		rd_set_count(r, r->tail, 0);
-		rd_set_status(r, r->tail, 0);
-		if (r->buf[r->tail].skb) {
-			rd_set_addr_status(r, r->tail, 0, 0);
-			dev_kfree_skb(r->buf[r->tail].skb);
-			r->buf[r->tail].skb = NULL;
-			r->buf[r->tail].data = NULL;
+			idev->stats.tx_bytes += ret;
 		}
-		ring_get(r);
 	}
 
-	ret = 0;
-	iobase = ndev->base_addr;
+	if (idev->new_baud  &&  rd == NULL)	/* tx ring empty and speed change pending */
+		vlsi_set_baud_lock(ndev);
 
-	if (r->head == r->tail) {	/* tx ring empty: re-enable rx */
+	iobase = ndev->base_addr;
+	config = inw(iobase+VLSI_PIO_IRCFG);
 
-		outw(0, iobase+VLSI_PIO_IRENABLE);
-		config = inw(iobase+VLSI_PIO_IRCFG);
-		mb();
+	if (rd == NULL)			/* tx ring empty: re-enable rx */
 		outw((config & ~IRCFG_ENTX) | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG);
-		wmb();
-		outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE);
+
+	else if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) {
+		int fifocnt;
+
+		fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
+		if (fifocnt != 0)
+			printk(KERN_WARNING "%s: rx fifo not empty(%d)\n",
+				__FUNCTION__, fifocnt);
+		outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG);
 	}
-	else
-		ret = 1;			/* no speed-change-check */
 
-	mb();
 	outw(0, iobase+VLSI_PIO_PROMPT);
 
-	if (netif_queue_stopped(ndev)) {
+	if (netif_queue_stopped(ndev)  &&  !idev->new_baud) {
 		netif_wake_queue(ndev);
 		printk(KERN_DEBUG "%s: queue awoken\n", __FUNCTION__);
 	}
-	return ret;
 }
 
+/* caller must have stopped the controller from busmastering */
 
-#if 0	/* disable ACTIVITY handling for now */
-
-static int vlsi_act_interrupt(struct net_device *ndev)
+static void vlsi_unarm_tx(vlsi_irda_dev_t *idev)
 {
-	printk(KERN_DEBUG "%s\n", __FUNCTION__);
-	return 0;
+	struct vlsi_ring *r = idev->tx_ring;
+	struct ring_descr *rd;
+	int ret;
+
+	for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) {
+
+		ret = 0;
+		if (rd_is_active(rd)) {
+			rd_set_status(rd, 0);
+			rd_set_count(rd, 0);
+			pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir);
+			if (rd->skb) {
+				dev_kfree_skb_any(rd->skb);
+				rd->skb = NULL;
+			}
+			printk(KERN_INFO "%s - dropping tx packet\n", __FUNCTION__);
+			ret = -VLSI_TX_DROP;
+		}
+		else
+			ret = vlsi_process_tx(r, rd);
+
+		if (ret < 0) {
+			ret = -ret;
+			idev->stats.tx_errors++;
+			if (ret & VLSI_TX_DROP)
+				idev->stats.tx_dropped++;
+			if (ret & VLSI_TX_FIFO)
+				idev->stats.tx_fifo_errors++;
+		}
+		else if (ret > 0){
+			idev->stats.tx_packets++;
+			idev->stats.tx_bytes += ret;
+		}
+	}
+
 }
-#endif
 
-static void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
-	struct net_device *ndev = dev_instance;
-	vlsi_irda_dev_t *idev = ndev->priv;
-	unsigned	iobase;
-	u8		irintr;
-	int 		boguscount = 32;
-	int		no_speed_check = 0;
-	unsigned	got_act;
-	unsigned long	flags;
+/********************************************************/
 
-	got_act = 0;
-	iobase = ndev->base_addr;
-	spin_lock_irqsave(&idev->lock,flags);
-	do {
-		irintr = inb(iobase+VLSI_PIO_IRINTR);
-		rmb();
-		outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */
-		wmb();
+static int vlsi_start_clock(struct pci_dev *pdev)
+{
+	u8	clkctl, lock;
+	int	i, count;
 
-		if (!(irintr&=IRINTR_INT_MASK))		/* not our INT - probably shared */
-			break;
+	if (clksrc < 2) { /* auto or PLL: try PLL */
+		clkctl = CLKCTL_PD_INV | CLKCTL_CLKSTP;
+		pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
 
-//		vlsi_reg_debug(iobase,__FUNCTION__);
+		/* procedure to detect PLL lock synchronisation:
+		 * after 0.5 msec initial delay we expect to find 3 PLL lock
+		 * indications within 10 msec for successful PLL detection.
+		 */
+		udelay(500);
+		count = 0;
+		for (i = 500; i <= 10000; i += 50) { /* max 10 msec */
+			pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &lock);
+			if (lock&CLKCTL_LOCK) {
+				if (++count >= 3)
+					break;
+			}
+			udelay(50);
+		}
+		if (count < 3) {
+			if (clksrc == 1) { /* explicitly asked for PLL hence bail out */
+				printk(KERN_ERR "%s: no PLL or failed to lock!\n",
+					__FUNCTION__);
+				clkctl = CLKCTL_CLKSTP;
+				pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
+				return -1;
+			}
+			else			/* was: clksrc=0(auto) */
+				clksrc = 3;	/* fallback to 40MHz XCLK (OB800) */
 
-		if (irintr&IRINTR_RPKTINT)
-			no_speed_check |= vlsi_rx_interrupt(ndev);
+			printk(KERN_INFO "%s: PLL not locked, fallback to clksrc=%d\n",
+				__FUNCTION__, clksrc);
+		}
+		else
+			clksrc = 1;	/* got successful PLL lock */
+	}
 
-		if (irintr&IRINTR_TPKTINT)
-			no_speed_check |= vlsi_tx_interrupt(ndev);
+	if (clksrc != 1) {
+		/* we get here if either no PLL detected in auto-mode or
+		   an external clock source was explicitly specified */
 
-#if 0	/* disable ACTIVITY handling for now */
+		clkctl = CLKCTL_EXTCLK | CLKCTL_CLKSTP;
+		if (clksrc == 3)
+			clkctl |= CLKCTL_XCKSEL;	
+		pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
 
-		if (got_act  &&  irintr==IRINTR_ACTIVITY) /* nothing new */
-			break;
+		/* no way to test for working XCLK */
+	}
+	else
+		pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);
 
-		if ((irintr&IRINTR_ACTIVITY) && !(irintr^IRINTR_ACTIVITY) ) {
-			no_speed_check |= vlsi_act_interrupt(ndev);
-			got_act = 1;
-		}
-#endif
-		if (irintr & ~(IRINTR_RPKTINT|IRINTR_TPKTINT|IRINTR_ACTIVITY))
-			printk(KERN_DEBUG "%s: IRINTR = %02x\n",
-				__FUNCTION__, (unsigned)irintr);
-			
-	} while (--boguscount > 0);
-	spin_unlock_irqrestore(&idev->lock,flags);
+	/* ok, now going to connect the chip with the clock source */
 
-	if (boguscount <= 0)
-		printk(KERN_ERR "%s: too much work in interrupt!\n", __FUNCTION__);
+	clkctl &= ~CLKCTL_CLKSTP;
+	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
 
-	else if (!no_speed_check) {
-		if (idev->new_baud)
-			vlsi_set_baud(ndev);
-	}
+	return 0;
 }
 
+static void vlsi_stop_clock(struct pci_dev *pdev)
+{
+	u8	clkctl;
+
+	/* disconnect chip from clock source */
+	pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl);
+	clkctl |= CLKCTL_CLKSTP;
+	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
 
-/**************************************************************/
+	/* disable all clock sources */
+	clkctl &= ~(CLKCTL_EXTCLK | CLKCTL_PD_INV);
+	pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl);
+}
 
+/********************************************************/
 
 /* writing all-zero to the VLSI PCI IO register area seems to prevent
  * some occasional situations where the hardware fails (symptoms are 
@@ -811,135 +1377,119 @@
 		outw(0, iobase + i);
 }
 
-
-static int vlsi_open(struct net_device *ndev)
+static int vlsi_init_chip(struct pci_dev *pdev)
 {
+	struct net_device *ndev = pci_get_drvdata(pdev);
 	vlsi_irda_dev_t *idev = ndev->priv;
-	struct pci_dev *pdev = idev->pdev;
-	int	err;
-	char	hwname[32];
-
-	if (pci_request_regions(pdev,drivername)) {
-		printk(KERN_ERR "%s: io resource busy\n", __FUNCTION__);
-		return -EAGAIN;
-	}
-
-	/* under some rare occasions the chip apparently comes up
-	 * with IRQ's pending. So we get interrupts invoked much too early
-	 * which will immediately kill us again :-(
-	 * so we better w/c pending IRQ and disable them all
-	 */
-
-	outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR);
+	unsigned	iobase;
+	u16 ptr;
 
-	if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ,
-			drivername, ndev)) {
-		printk(KERN_ERR "%s: couldn't get IRQ: %d\n",
-			__FUNCTION__, ndev->irq);
-		pci_release_regions(pdev);
-		return -EAGAIN;
-	}
-	printk(KERN_INFO "%s: got resources for %s - irq=%d / io=%04lx\n",
-		__FUNCTION__, ndev->name, ndev->irq, ndev->base_addr );
+	/* start the clock and clean the registers */
 
-	if (vlsi_set_clock(pdev)) {
+	if (vlsi_start_clock(pdev)) {
 		printk(KERN_ERR "%s: no valid clock source\n",
 			__FUNCTION__);
-		free_irq(ndev->irq,ndev);
-		pci_release_regions(pdev);
-		return -EIO;
+		pci_disable_device(pdev);
+		return -1;
 	}
+	iobase = ndev->base_addr;
+	vlsi_clear_regs(iobase);
 
-	vlsi_start_clock(pdev);
+	outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* w/c pending IRQ, disable all INT */
 
-	vlsi_clear_regs(ndev->base_addr);
+	outw(0, iobase+VLSI_PIO_IRENABLE);	/* disable IrPHY-interface */
 
-	err = vlsi_init_ring(idev);
-	if (err) {
-		vlsi_unset_clock(pdev);
-		free_irq(ndev->irq,ndev);
-		pci_release_regions(pdev);
-		return err;
-	}
+	/* disable everything, particularly IRCFG_MSTR - (also resetting the RING_PTR) */
+
+	outw(0, iobase+VLSI_PIO_IRCFG);
+	wmb();
 
-	vlsi_init_chip(ndev);
+	outw(MAX_PACKET_LENGTH, iobase+VLSI_PIO_MAXPKT);  /* max possible value=0x0fff */
 
-	printk(KERN_INFO "%s: IrPHY setup: %d baud (%s), %s SIR-pulses\n",
-		__FUNCTION__, idev->baud, 
-		(idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR"),
-		(sirpulse)?"3/16 bittime":"short");
+	outw(BUS_TO_RINGBASE(idev->busaddr), iobase+VLSI_PIO_RINGBASE);
 
-	vlsi_arm_rx(&idev->rx_ring);
+	outw(TX_RX_TO_RINGSIZE(idev->tx_ring->size, idev->rx_ring->size),
+		iobase+VLSI_PIO_RINGSIZE);	
 
-	do_gettimeofday(&idev->last_rx);  /* first mtt may start from now on */
+	ptr = inw(iobase+VLSI_PIO_RINGPTR);
+	atomic_set(&idev->rx_ring->head, RINGPTR_GET_RX(ptr));
+	atomic_set(&idev->rx_ring->tail, RINGPTR_GET_RX(ptr));
+	atomic_set(&idev->tx_ring->head, RINGPTR_GET_TX(ptr));
+	atomic_set(&idev->tx_ring->tail, RINGPTR_GET_TX(ptr));
 
-	sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr);
-	idev->irlap = irlap_open(ndev,&idev->qos,hwname);
+	vlsi_set_baud_lock(ndev);	/* idev->new_baud used as provided by caller */
 
-	netif_start_queue(ndev);
-	outw(0, ndev->base_addr+VLSI_PIO_PROMPT);	/* kick hw state machine */
+	outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR);	/* just in case - w/c pending IRQ's */
+	wmb();
+
+	/* DO NOT BLINDLY ENABLE IRINTR_ACTEN!
+	 * basically every received pulse fires an ACTIVITY-INT
+	 * leading to >>1000 INT's per second instead of few 10
+	 */
 
-	printk(KERN_INFO "%s: device %s operational using (%d,%d) tx,rx-ring\n",
-		__FUNCTION__, ndev->name, ringsize[0], ringsize[1]);
+	outb(IRINTR_RPKTEN|IRINTR_TPKTEN, iobase+VLSI_PIO_IRINTR);
 
 	return 0;
 }
 
-
-static int vlsi_close(struct net_device *ndev)
+static int vlsi_start_hw(vlsi_irda_dev_t *idev)
 {
-	vlsi_irda_dev_t *idev = ndev->priv;
 	struct pci_dev *pdev = idev->pdev;
-	u8	cmd;
-	unsigned iobase;
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	unsigned iobase = ndev->base_addr;
+	u8 byte;
 
+	/* we don't use the legacy UART, disable its address decoding */
 
-	iobase = ndev->base_addr;
-	netif_stop_queue(ndev);
+	pci_read_config_byte(pdev, VLSI_PCI_IRMISC, &byte);
+	byte &= ~(IRMISC_UARTEN | IRMISC_UARTTST);
+	pci_write_config_byte(pdev, VLSI_PCI_IRMISC, byte);
 
-	if (idev->irlap)
-		irlap_close(idev->irlap);
-	idev->irlap = NULL;
+	/* enable PCI busmaster access to our 16MB page */
 
-	outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR);	/* w/c pending + disable further IRQ */
-	wmb();
-	outw(0, iobase+VLSI_PIO_IRENABLE);
-	outw(0, iobase+VLSI_PIO_IRCFG);			/* disable everything */
-	wmb();
-	outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE);
-	mb();						/* ... from now on */
+	pci_write_config_byte(pdev, VLSI_PCI_MSTRPAGE, MSTRPAGE_VALUE);
+	pci_set_master(pdev);
 
-	outw(0, iobase+VLSI_PIO_IRENABLE);
-	wmb();
+	vlsi_init_chip(pdev);
 
-	vlsi_clear_regs(ndev->base_addr);
+	vlsi_fill_rx(idev->rx_ring);
 
-	vlsi_stop_clock(pdev);
+	do_gettimeofday(&idev->last_rx);	/* first mtt may start from now on */
 
-	vlsi_unset_clock(pdev);
+	outw(0, iobase+VLSI_PIO_PROMPT);	/* kick hw state machine */
 
-	free_irq(ndev->irq,ndev);
+	return 0;
+}
 
-	vlsi_free_ringbuf(&idev->rx_ring);
-	vlsi_free_ringbuf(&idev->tx_ring);
+static int vlsi_stop_hw(vlsi_irda_dev_t *idev)
+{
+	struct pci_dev *pdev = idev->pdev;
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	unsigned iobase = ndev->base_addr;
+	unsigned long flags;
 
-	if (idev->busaddr)
-		pci_free_consistent(idev->pdev,RING_AREA_SIZE,idev->virtaddr,idev->busaddr);
+	spin_lock_irqsave(&idev->lock,flags);
+	outw(0, iobase+VLSI_PIO_IRENABLE);
+	outw(0, iobase+VLSI_PIO_IRCFG);			/* disable everything */
+	wmb();
 
-	idev->virtaddr = NULL;
-	idev->busaddr = 0;
+	outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR);	/* w/c pending + disable further IRQ */
+	mb();
+	spin_unlock_irqrestore(&idev->lock,flags);
 
-	pci_read_config_byte(pdev, PCI_COMMAND, &cmd);
-	cmd &= ~PCI_COMMAND_MASTER;
-	pci_write_config_byte(pdev, PCI_COMMAND, cmd);
+	vlsi_unarm_tx(idev);
+	vlsi_unarm_rx(idev);
 
-	pci_release_regions(pdev);
+	vlsi_clear_regs(iobase);
+	vlsi_stop_clock(pdev);
 
-	printk(KERN_INFO "%s: device %s stopped\n", __FUNCTION__, ndev->name);
+	pci_disable_device(pdev);
 
 	return 0;
 }
 
+/**************************************************************/
+
 static struct net_device_stats * vlsi_get_stats(struct net_device *ndev)
 {
 	vlsi_irda_dev_t *idev = ndev->priv;
@@ -947,147 +1497,30 @@
 	return &idev->stats;
 }
 
-static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static void vlsi_tx_timeout(struct net_device *ndev)
 {
 	vlsi_irda_dev_t *idev = ndev->priv;
-	struct vlsi_ring	*r;
-	unsigned long flags;
-	unsigned iobase;
-	u8 status;
-	u16 config;
-	int mtt;
-	int len, speed;
-	struct timeval  now, ready;
-
-
-	status = 0;
-
-	speed = irda_get_next_speed(skb);
-
-	if (speed != -1  &&  speed != idev->baud) {
-		idev->new_baud = speed;
-		if (!skb->len) {
-			dev_kfree_skb(skb);
-			vlsi_set_baud(ndev);
-			return 0;
-		}
-		status = TX_STAT_CLRENTX;  /* stop tx-ring after this frame */
-	}
-
-	if (skb->len == 0) {
-		printk(KERN_ERR "%s: blocking 0-size packet???\n",
-			__FUNCTION__);
-		dev_kfree_skb(skb);
-		return 0;
-	}
-
-	r = &idev->tx_ring;
-
-	if (rd_is_active(r, r->head))
-		BUG();
-
-	if (idev->mode == IFF_SIR) {
-		status |= TX_STAT_DISCRC;
-		len = async_wrap_skb(skb, r->buf[r->head].data, XFER_BUF_SIZE);
-	}
-	else {				/* hw deals with MIR/FIR mode */
-		len = skb->len;
-		memcpy(r->buf[r->head].data, skb->data, len);
-	}
-
-	rd_set_count(r, r->head, len);
-	rd_set_addr_status(r, r->head, virt_to_bus(r->buf[r->head].data), status);
-
-	/* new entry not yet activated! */
-
-#if 0
-	printk(KERN_DEBUG "%s: dump entry %d: %u %02x %08x\n",
-		__FUNCTION__, r->head,
-		idev->ring_hw[r->head].rd_count,
-		(unsigned)idev->ring_hw[r->head].rd_status,
-		idev->ring_hw[r->head].rd_addr & 0xffffffff);
-	vlsi_reg_debug(iobase,__FUNCTION__);
-#endif
-
 
-	/* let mtt delay pass before we need to acquire the spinlock! */
 
-	if ((mtt = irda_get_mtt(skb)) > 0) {
-	
-		ready.tv_usec = idev->last_rx.tv_usec + mtt;
-		ready.tv_sec = idev->last_rx.tv_sec;
-		if (ready.tv_usec >= 1000000) {
-			ready.tv_usec -= 1000000;
-			ready.tv_sec++;		/* IrLAP 1.1: mtt always < 1 sec */
-		}
-		for(;;) {
-			do_gettimeofday(&now);
-			if (now.tv_sec > ready.tv_sec
-			    ||  (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec))
-			    	break;
-			udelay(100);
-		}
-	}
-
-/*
- *	race window ahead, due to concurrent controller processing!
- *
- *	We need to disable IR output in order to switch to TX mode.
- *	Better not do this blindly anytime we want to transmit something
- *	because TX may already run. However the controller may stop TX
- *	at any time when fetching an inactive descriptor or one with
- *	CLR_ENTX set. So we switch on TX only, if TX was not running
- *	_after_ the new descriptor was activated on the ring. This ensures
- *	we will either find TX already stopped or we can be sure, there
- *	will be a TX-complete interrupt even if the chip stopped doing
- *	TX just after we found it still running. The ISR will then find
- *	the non-empty ring and restart TX processing. The enclosing
- *	spinlock is required to get serialization with the ISR right.
- */
+	vlsi_reg_debug(ndev->base_addr, __FUNCTION__);
+	vlsi_ring_debug(idev->tx_ring);
 
-
-	iobase = ndev->base_addr;
-
-	spin_lock_irqsave(&idev->lock,flags);
-
-	rd_activate(r, r->head);
-	ring_put(r);
-
-	if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) {
-	
-		outw(0, iobase+VLSI_PIO_IRENABLE);
-
-		config = inw(iobase+VLSI_PIO_IRCFG);
-		rmb();
-		outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG);
-		wmb();
-		outw(IRENABLE_IREN, iobase+VLSI_PIO_IRENABLE);
-		mb();
-		outw(0, iobase+VLSI_PIO_PROMPT);
-		wmb();
-	}
-
-	if (r->head == r->tail) {
+	if (netif_running(ndev))
 		netif_stop_queue(ndev);
-		printk(KERN_DEBUG "%s: tx ring full - queue stopped: %d/%d\n",
-			__FUNCTION__, r->head, r->tail);
-#if 0
-		printk(KERN_INFO "%s: dump stalled entry %d: %u %02x %08x\n",
-			__FUNCTION__, r->tail,
-			r->hw[r->tail].rd_count,
-			(unsigned)r->hw[r->tail].rd_status,
-			r->hw[r->tail].rd_addr & 0xffffffff);
-#endif
-		vlsi_reg_debug(iobase,__FUNCTION__);
-	}
 
-	spin_unlock_irqrestore(&idev->lock, flags);
+	vlsi_stop_hw(idev);
 
-	dev_kfree_skb(skb);	
+	/* now simply restart the whole thing */
 
-	return 0;
-}
+	if (!idev->new_baud)
+		idev->new_baud = idev->baud;		/* keep current baudrate */
 
+	if (vlsi_start_hw(idev))
+		printk(KERN_CRIT "%s: failed to restart hw - %s(%s) unusable!\n",
+			__FUNCTION__, idev->pdev->name, ndev->name);
+	else
+		netif_start_queue(ndev);
+}
 
 static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 {
@@ -1097,14 +1530,20 @@
 	u16 fifocnt;
 	int ret = 0;
 
-	spin_lock_irqsave(&idev->lock,flags);
 	switch (cmd) {
 		case SIOCSBANDWIDTH:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret = -EPERM;
 				break;
 			}
+			spin_lock_irqsave(&idev->lock, flags);
 			idev->new_baud = irq->ifr_baudrate;
+			/* when called from userland there might be a minor race window here
+			 * if the stack tries to change speed concurrently - which would be
+			 * pretty strange anyway with the userland having full control...
+			 */
+			vlsi_set_baud_nolock(ndev);
+			spin_unlock_irqrestore(&idev->lock, flags);
 			break;
 		case SIOCSMEDIABUSY:
 			if (!capable(CAP_NET_ADMIN)) {
@@ -1116,7 +1555,7 @@
 		case SIOCGRECEIVING:
 			/* the best we can do: check whether there are any bytes in rx fifo.
 			 * The trustable window (in case some data arrives just afterwards)
-			 * may be as short as 1usec or so at 4Mbps - no way for future-telling.
+			 * may be as short as 1usec or so at 4Mbps.
 			 */
 			fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK;
 			irq->ifr_receiving = (fifocnt!=0) ? 1 : 0;
@@ -1126,42 +1565,159 @@
 				__FUNCTION__, cmd);
 			ret = -EOPNOTSUPP;
 	}	
-	spin_unlock_irqrestore(&idev->lock,flags);
 	
 	return ret;
 }
 
+/********************************************************/
+
+static void vlsi_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *ndev = dev_instance;
+	vlsi_irda_dev_t *idev = ndev->priv;
+	unsigned	iobase;
+	u8		irintr;
+	int 		boguscount = 32;
+	unsigned	got_act;
+	unsigned long	flags;
+
+	got_act = 0;
+	iobase = ndev->base_addr;
+	do {
+		spin_lock_irqsave(&idev->lock,flags);
+		irintr = inb(iobase+VLSI_PIO_IRINTR);
+		rmb();
+		outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */
+		spin_unlock_irqrestore(&idev->lock,flags);
+
+		if (!(irintr&=IRINTR_INT_MASK))		/* not our INT - probably shared */
+			break;
+
+		if (irintr&IRINTR_RPKTINT)
+			vlsi_rx_interrupt(ndev);
+
+		if (irintr&IRINTR_TPKTINT)
+			vlsi_tx_interrupt(ndev);
+
+		if (!(irintr & ~IRINTR_ACTIVITY))
+			break;		/* done if only activity remaining */
+	
+		if (irintr & ~(IRINTR_RPKTINT|IRINTR_TPKTINT|IRINTR_ACTIVITY)) {
+			printk(KERN_DEBUG "%s: IRINTR = %02x\n",
+				__FUNCTION__, (unsigned)irintr);
+			vlsi_reg_debug(iobase,__FUNCTION__);
+		}			
+	} while (--boguscount > 0);
+
+	if (boguscount <= 0)
+		printk(KERN_WARNING "%s: too much work in interrupt!\n", __FUNCTION__);
 
+}
+
+/********************************************************/
 
-int vlsi_irda_init(struct net_device *ndev)
+static int vlsi_open(struct net_device *ndev)
 {
 	vlsi_irda_dev_t *idev = ndev->priv;
-	struct pci_dev *pdev = idev->pdev;
-	u8	byte;
+	int	err = -EAGAIN;
+	char	hwname[32];
+
+	if (pci_request_regions(idev->pdev, drivername)) {
+		printk(KERN_ERR "%s: io resource busy\n", __FUNCTION__);
+		goto errout;
+	}
+	ndev->base_addr = pci_resource_start(idev->pdev,0);
+	ndev->irq = idev->pdev->irq;
+
+	/* under some rare occasions the chip apparently comes up with
+	 * IRQ's pending. We better w/c pending IRQ and disable them all
+	 */
+
+	outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR);
+
+	if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ,
+			drivername, ndev)) {
+		printk(KERN_ERR "%s: couldn't get IRQ: %d\n",
+			__FUNCTION__, ndev->irq);
+		goto errout_io;
+	}
 
+	if ((err = vlsi_create_hwif(idev)) != 0)
+		goto errout_irq;
+
+	sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr);
+	idev->irlap = irlap_open(ndev,&idev->qos,hwname);
+	if (!idev->irlap)
+		goto errout_free_ring;
+
+	do_gettimeofday(&idev->last_rx);  /* first mtt may start from now on */
+
+	idev->new_baud = 9600;		/* start with IrPHY using 9600(SIR) mode */
+
+	if ((err = vlsi_start_hw(idev)) != 0)
+		goto errout_close_irlap;
+
+	netif_start_queue(ndev);
+
+	printk(KERN_INFO "%s: device %s operational\n", __FUNCTION__, ndev->name);
+
+	return 0;
+
+errout_close_irlap:
+	irlap_close(idev->irlap);
+errout_free_ring:
+	vlsi_destroy_hwif(idev);
+errout_irq:
+	free_irq(ndev->irq,ndev);
+errout_io:
+	pci_release_regions(idev->pdev);
+errout:
+	return err;
+}
+
+static int vlsi_close(struct net_device *ndev)
+{
+	vlsi_irda_dev_t *idev = ndev->priv;
+
+	netif_stop_queue(ndev);
+
+	if (idev->irlap)
+		irlap_close(idev->irlap);
+	idev->irlap = NULL;
+
+	vlsi_stop_hw(idev);
+
+	vlsi_destroy_hwif(idev);
+
+	free_irq(ndev->irq,ndev);
+
+	pci_release_regions(idev->pdev);
+
+	printk(KERN_INFO "%s: device %s stopped\n", __FUNCTION__, ndev->name);
+
+	return 0;
+}
+
+static int vlsi_irda_init(struct net_device *ndev)
+{
+	vlsi_irda_dev_t *idev = ndev->priv;
+	struct pci_dev *pdev = idev->pdev;
 
 	SET_MODULE_OWNER(ndev);
 
 	ndev->irq = pdev->irq;
 	ndev->base_addr = pci_resource_start(pdev,0);
 
-	/* PCI busmastering - see include file for details! */
+	/* PCI busmastering
+	 * see include file for details why we need these 2 masks, in this order!
+	 */
 
-	if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW)) {
+	if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW)
+	    || pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) {
 		printk(KERN_ERR "%s: aborting due to PCI BM-DMA address limitations\n",
 			__FUNCTION__);
 		return -1;
 	}
-	pci_set_master(pdev);
-	pdev->dma_mask = DMA_MASK_MSTRPAGE;
-	pci_write_config_byte(pdev, VLSI_PCI_MSTRPAGE, MSTRPAGE_VALUE);
-
-	/* we don't use the legacy UART, disable its address decoding */
-
-	pci_read_config_byte(pdev, VLSI_PCI_IRMISC, &byte);
-	byte &= ~(IRMISC_UARTEN | IRMISC_UARTTST);
-	pci_write_config_byte(pdev, VLSI_PCI_IRMISC, byte);
-
 
 	irda_init_max_qos_capabilies(&idev->qos);
 
@@ -1187,6 +1743,8 @@
 	ndev->get_stats	      = vlsi_get_stats;
 	ndev->hard_start_xmit = vlsi_hard_start_xmit;
 	ndev->do_ioctl	      = vlsi_ioctl;
+	ndev->tx_timeout      = vlsi_tx_timeout;
+	ndev->watchdog_timeo  = 500*HZ/1000;	/* max. allowed turn time for IrLAP */
 
 	return 0;
 }	
@@ -1203,6 +1761,8 @@
 
 	if (pci_enable_device(pdev))
 		goto out;
+	else
+		pdev->current_state = 0; /* hw must be running now */
 
 	printk(KERN_INFO "%s: IrDA PCI controller %s detected\n",
 		drivername, pdev->name);
@@ -1228,6 +1788,8 @@
 	ndev->priv = (void *) idev;
 
 	spin_lock_init(&idev->lock);
+	init_MUTEX(&idev->sem);
+	down(&idev->sem);
 	idev->pdev = pdev;
 	ndev->init = vlsi_irda_init;
 	strcpy(ndev->name,"irda%d");
@@ -1236,13 +1798,36 @@
 			__FUNCTION__);
 		goto out_freedev;
 	}
+
+#ifdef CONFIG_PROC_FS
+	{
+		struct proc_dir_entry *ent;
+
+		ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root);
+		if (!ent) {
+			printk(KERN_ERR "%s: failed to create proc entry\n", __FUNCTION__);
+			goto out_unregister;
+		}
+		ent->data = ndev;
+		ent->proc_fops = &vlsi_proc_fops;
+		ent->size = 0;
+		idev->proc_entry = ent;
+	}
+#endif
+
 	printk(KERN_INFO "%s: registered device %s\n", drivername, ndev->name);
 
 	pci_set_drvdata(pdev, ndev);
+	up(&idev->sem);
 
 	return 0;
 
+out_unregister:
+	up(&idev->sem);
+	unregister_netdev(ndev);
+	goto out_disable;
 out_freedev:
+	up(&idev->sem);
 	kfree(ndev);
 out_disable:
 	pci_disable_device(pdev);
@@ -1254,37 +1839,145 @@
 static void __devexit vlsi_irda_remove(struct pci_dev *pdev)
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
+	vlsi_irda_dev_t *idev;
 
-	if (ndev) {
-		printk(KERN_INFO "%s: unregister device %s\n",
-			drivername, ndev->name);
-
-		unregister_netdev(ndev);
-		/* do not free - async completed by unregister_netdev()
-		 * ndev->destructor called (if present) when going to free
-		 */
-
-	}
-	else
+	if (!ndev) {
 		printk(KERN_CRIT "%s: lost netdevice?\n", drivername);
-	pci_set_drvdata(pdev, NULL);
+		return;
+	}
 
+	idev = ndev->priv;
+	down(&idev->sem);
+	pci_set_drvdata(pdev, NULL);
 	pci_disable_device(pdev);
-	printk(KERN_INFO "%s: %s disabled\n", drivername, pdev->name);
+#ifdef CONFIG_PROC_FS
+	if (idev->proc_entry) {
+		remove_proc_entry(ndev->name, vlsi_proc_root);
+		idev->proc_entry = NULL;
+	}
+#endif
+	up(&idev->sem);
+
+	unregister_netdev(ndev);
+	/* do not free - async completed by unregister_netdev()
+	 * ndev->destructor called (if present) when going to free
+	 */
+
+	printk(KERN_INFO "%s: %s removed\n", drivername, pdev->name);
+}
+
+#ifdef CONFIG_PM
+
+/* The Controller doesn't provide PCI PM capabilities as defined by PCI specs.
+ * Some of the Linux PCI-PM code however depends on this, for example in
+ * pci_set_power_state(). So we have to take care to perform the required
+ * operations on our own (particularly reflecting the pdev->current_state)
+ * otherwise we might get cheated by pci-pm.
+ */
+
+static int vlsi_irda_save_state(struct pci_dev *pdev, u32 state)
+{
+	if (state < 1 || state > 3 ) {
+		printk( KERN_ERR "%s - %s: invalid pm state request: %u\n",
+			__FUNCTION__, pdev->name, state);
+		return -1;
+	}
+	return 0;
 }
 
 static int vlsi_irda_suspend(struct pci_dev *pdev, u32 state)
 {
-	printk(KERN_ERR "%s - %s\n", __FUNCTION__, pdev->name);
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	vlsi_irda_dev_t *idev;
+
+	if (state < 1 || state > 3 ) {
+		printk( KERN_ERR "%s - %s: invalid pm state request: %u\n",
+			__FUNCTION__, pdev->name, state);
+		return 0;
+	}
+	if (!ndev) {
+		printk(KERN_ERR "%s - %s: no netdevice \n", __FUNCTION__, pdev->name);
+		return 0;
+	}
+	idev = ndev->priv;	
+	down(&idev->sem);
+	if (pdev->current_state != 0) {			/* already suspended */
+		if (state > pdev->current_state) {	/* simply go deeper */
+			pci_set_power_state(pdev,state);
+			pdev->current_state = state;
+		}
+		else
+			printk(KERN_ERR "%s - %s: invalid suspend request %u -> %u\n",
+				__FUNCTION__, pdev->name, pdev->current_state, state);
+		up(&idev->sem);
+		return 0;
+	}
+
+	if (netif_running(ndev)) {
+		netif_device_detach(ndev);
+		vlsi_stop_hw(idev);
+		pci_save_state(pdev, idev->cfg_space);
+		if (!idev->new_baud)
+			/* remember speed settings to restore on resume */
+			idev->new_baud = idev->baud;
+	}
+
+	pci_set_power_state(pdev,state);
+	pdev->current_state = state;
+	idev->resume_ok = 1;
+	up(&idev->sem);
 	return 0;
 }
 
 static int vlsi_irda_resume(struct pci_dev *pdev)
 {
-	printk(KERN_ERR "%s - %s\n", __FUNCTION__, pdev->name);
+	struct net_device *ndev = pci_get_drvdata(pdev);
+	vlsi_irda_dev_t	*idev;
+
+	if (!ndev) {
+		printk(KERN_ERR "%s - %s: no netdevice \n", __FUNCTION__, pdev->name);
+		return 0;
+	}
+	idev = ndev->priv;	
+	down(&idev->sem);
+	if (pdev->current_state == 0) {
+		up(&idev->sem);
+		printk(KERN_ERR "%s - %s: already resumed\n", __FUNCTION__, pdev->name);
+		return 0;
+	}
+	
+	pci_set_power_state(pdev, 0);
+	pdev->current_state = 0;
+
+	if (!idev->resume_ok) {
+		/* should be obsolete now - but used to happen due to:
+		 * - pci layer initially setting pdev->current_state = 4 (unknown)
+		 * - pci layer did not walk the save_state-tree (might be APM problem)
+		 *   so we could not refuse to suspend from undefined state
+		 * - vlsi_irda_suspend detected invalid state and refused to save
+		 *   configuration for resume - but was too late to stop suspending
+		 * - vlsi_irda_resume got screwed when trying to resume from garbage
+		 *
+		 * now we explicitly set pdev->current_state = 0 after enabling the
+		 * device and independently resume_ok should catch any garbage config.
+		 */
+		printk(KERN_ERR "%s - hm, nothing to resume?\n", __FUNCTION__);
+		up(&idev->sem);
+		return 0;
+	}
+
+	if (netif_running(ndev)) {
+		pci_restore_state(pdev, idev->cfg_space);
+		vlsi_start_hw(idev);
+		netif_device_attach(ndev);
+	}
+	idev->resume_ok = 0;
+	up(&idev->sem);
 	return 0;
 }
 
+#endif /* CONFIG_PM */
+
 /*********************************************************/
 
 static struct pci_driver vlsi_irda_driver = {
@@ -1292,13 +1985,20 @@
 	.id_table	= vlsi_irda_table,
 	.probe		= vlsi_irda_probe,
 	.remove		= __devexit_p(vlsi_irda_remove),
+#ifdef CONFIG_PM
+	.save_state	= vlsi_irda_save_state,
 	.suspend	= vlsi_irda_suspend,
 	.resume		= vlsi_irda_resume,
+#endif
 };
 
+#ifdef CONFIG_PROC_FS
+#define PROC_DIR ("driver/" DRIVER_NAME)
+#endif
+
 static int __init vlsi_mod_init(void)
 {
-	int	i;
+	int	i, ret;
 
 	if (clksrc < 0  ||  clksrc > 3) {
 		printk(KERN_ERR "%s: invalid clksrc=%d\n", drivername, clksrc);
@@ -1324,14 +2024,27 @@
 
 	sirpulse = !!sirpulse;
 
-	return pci_module_init(&vlsi_irda_driver);
+#ifdef CONFIG_PROC_FS
+	vlsi_proc_root = create_proc_entry(PROC_DIR, S_IFDIR, 0);
+	if (!vlsi_proc_root)
+		return -ENOMEM;
+#endif
+
+	ret = pci_module_init(&vlsi_irda_driver);
+
+#ifdef CONFIG_PROC_FS
+	if (ret)
+		remove_proc_entry(PROC_DIR, 0);
+#endif
+	return ret;
+
 }
 
 static void __exit vlsi_mod_exit(void)
 {
 	pci_unregister_driver(&vlsi_irda_driver);
+	remove_proc_entry(PROC_DIR, 0);
 }
 
 module_init(vlsi_mod_init);
 module_exit(vlsi_mod_exit);
-
diff -Nru a/drivers/net/mii.c b/drivers/net/mii.c
--- a/drivers/net/mii.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/net/mii.c	Fri Oct 11 21:22:55 2002
@@ -243,7 +243,7 @@
 
 	/* figure out media and duplex from advertise and LPA values */
 	media = mii_nway_result(lpa & advertise);
-	duplex = (media & (ADVERTISE_100FULL | ADVERTISE_10FULL)) ? 1 : 0;
+	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
 
 	if (ok_to_print)
 		printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
diff -Nru a/drivers/net/ns83820.c b/drivers/net/ns83820.c
--- a/drivers/net/ns83820.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/net/ns83820.c	Fri Oct 11 21:23:04 2002
@@ -1,9 +1,9 @@
-#define _VERSION "0.18"
+#define _VERSION "0.20"
 /* ns83820.c by Benjamin LaHaise with contributions.
  *
  * Questions/comments/discussion to linux-ns83820@kvack.org.
  *
- * $Revision: 1.34.2.16 $
+ * $Revision: 1.34.2.23 $
  *
  * Copyright 2001 Benjamin LaHaise.
  * Copyright 2001, 2002 Red Hat.
@@ -57,6 +57,12 @@
  *	20020310	0.17	speedups
  *	20020610	0.18 -	actually use the pci dma api for highmem
  *			     -	remove pci latency register fiddling
+ *			0.19 -	better bist support
+ *			     -	add ihr and reset_phy parameters
+ *			     -	gmii bus probing
+ *			     -	fix missed txok introduced during performance
+ *				tuning
+ *			0.20 -	fix stupid RFEN thinko.  i am such a smurf.
  *
  * Driver Overview
  * ===============
@@ -101,9 +107,16 @@
 #include <linux/compiler.h>
 #include <linux/prefetch.h>
 #include <linux/ethtool.h>
+#include <linux/timer.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/system.h>
+
+/* Global parameters.  See MODULE_PARM near the bottom. */
+static int ihr = 2;
+static int reset_phy = 0;
+static int lnksts = 0;		/* CFG_LNKSTS bit polarity */
 
 /* Dprintk is used for more interesting debug events */
 #undef Dprintk
@@ -126,7 +139,7 @@
 
 /* Must not exceed ~65000. */
 #define NR_RX_DESC	64
-#define NR_TX_DESC	64
+#define NR_TX_DESC	128
 
 /* not tunable */
 #define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14)	/* rx/tx mac addr + type */
@@ -138,6 +151,9 @@
 
 #define CR_TXE		0x00000001
 #define CR_TXD		0x00000002
+/* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE
+ * The Receive engine skips one descriptor and moves
+ * onto the next one!! */
 #define CR_RXE		0x00000004
 #define CR_RXD		0x00000008
 #define CR_TXR		0x00000010
@@ -145,8 +161,21 @@
 #define CR_SWI		0x00000080
 #define CR_RST		0x00000100
 
-#define PTSCR_EEBIST_EN	0x00000002
-#define PTSCR_EELOAD_EN	0x00000004
+#define PTSCR_EEBIST_FAIL       0x00000001
+#define PTSCR_EEBIST_EN         0x00000002
+#define PTSCR_EELOAD_EN         0x00000004
+#define PTSCR_RBIST_FAIL        0x000001b8
+#define PTSCR_RBIST_DONE        0x00000200
+#define PTSCR_RBIST_EN          0x00000400
+#define PTSCR_RBIST_RST         0x00002000
+
+#define MEAR_EEDI		0x00000001
+#define MEAR_EEDO		0x00000002
+#define MEAR_EECLK		0x00000004
+#define MEAR_EESEL		0x00000008
+#define MEAR_MDIO		0x00000010
+#define MEAR_MDDIR		0x00000020
+#define MEAR_MDC		0x00000040
 
 #define ISR_TXDESC3	0x40000000
 #define ISR_TXDESC2	0x20000000
@@ -202,6 +231,8 @@
 #define CFG_DUPSTS	0x10000000
 #define CFG_TBI_EN	0x01000000
 #define CFG_MODE_1000	0x00400000
+/* Ramit : Dont' ever use AUTO_1000, it never works and is buggy.
+ * Read the Phy response and then configure the MAC accordingly */
 #define CFG_AUTO_1000	0x00200000
 #define CFG_PINT_CTL	0x001c0000
 #define CFG_PINT_DUPSTS	0x00100000
@@ -230,22 +261,29 @@
 #define EXTSTS_TCPPKT	0x00080000
 #define EXTSTS_IPPKT	0x00020000
 
-#define SPDSTS_POLARITY	(CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS)
+#define SPDSTS_POLARITY	(CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))
 
 #define MIBC_MIBS	0x00000008
 #define MIBC_ACLR	0x00000004
 #define MIBC_FRZ	0x00000002
 #define MIBC_WRN	0x00000001
 
+#define PCR_PSEN	(1 << 31)
+#define PCR_PS_MCAST	(1 << 30)
+#define PCR_PS_DA	(1 << 29)
+#define PCR_STHI_8	(3 << 23)
+#define PCR_STLO_4	(1 << 23)
+#define PCR_FFHI_8K	(3 << 21)
+#define PCR_FFLO_4K	(1 << 21)
+#define PCR_PAUSE_CNT	0xFFFE
+
 #define RXCFG_AEP	0x80000000
 #define RXCFG_ARP	0x40000000
 #define RXCFG_STRIPCRC	0x20000000
 #define RXCFG_RX_FD	0x10000000
 #define RXCFG_ALP	0x08000000
 #define RXCFG_AIRL	0x04000000
-#define RXCFG_MXDMA	0x00700000
-#define RXCFG_MXDMA0	0x00100000
-#define RXCFG_MXDMA64	0x00600000
+#define RXCFG_MXDMA512	0x00700000
 #define RXCFG_DRTH	0x0000003e
 #define RXCFG_DRTH0	0x00000002
 
@@ -354,23 +392,22 @@
 #define desc_addr_set(desc, addr)				\
 	do {							\
 		u64 __addr = (addr);				\
-		desc[BUFPTR] = cpu_to_le32(__addr);		\
-		desc[BUFPTR+1] = cpu_to_le32(__addr >> 32);	\
+		(desc)[0] = cpu_to_le32(__addr);		\
+		(desc)[1] = cpu_to_le32(__addr >> 32);		\
 	} while(0)
 #define desc_addr_get(desc)					\
-		(((u64)le32_to_cpu(desc[BUFPTR+1]) << 32)	\
-		     | le32_to_cpu(desc[BUFPTR]))
+		(((u64)le32_to_cpu((desc)[1]) << 32)		\
+		     | le32_to_cpu((desc)[0]))
 #else
 #define HW_ADDR_LEN	4
-#define desc_addr_set(desc, addr)	(desc[BUFPTR] = cpu_to_le32(addr))
-#define desc_addr_get(desc)		(le32_to_cpu(desc[BUFPTR]))
+#define desc_addr_set(desc, addr)	((desc)[0] = cpu_to_le32(addr))
+#define desc_addr_get(desc)		(le32_to_cpu((desc)[0]))
 #endif
 
-#define LINK		0
-#define BUFPTR		(LINK + HW_ADDR_LEN/4)
-#define CMDSTS		(BUFPTR + HW_ADDR_LEN/4)
-#define EXTSTS		(CMDSTS + 4/4)
-#define DRV_NEXT	(EXTSTS + 4/4)
+#define DESC_LINK		0
+#define DESC_BUFPTR		(DESC_LINK + HW_ADDR_LEN/4)
+#define DESC_CMDSTS		(DESC_BUFPTR + HW_ADDR_LEN/4)
+#define DESC_EXTSTS		(DESC_CMDSTS + 4/4)
 
 #define CMDSTS_OWN	0x80000000
 #define CMDSTS_MORE	0x40000000
@@ -426,18 +463,19 @@
 
 	spinlock_t	tx_lock;
 
-	long		tx_idle;
-
 	u16		tx_done_idx;
 	u16		tx_idx;
 	volatile u16	tx_free_idx;	/* idx of free desc chain */
 	u16		tx_intr_idx;
 
+	atomic_t	nr_tx_skbs;
 	struct sk_buff	*tx_skbs[NR_TX_DESC];
 
 	char		pad[16] __attribute__((aligned(16)));
 	u32		*tx_descs;
 	dma_addr_t	tx_phy_descs;
+
+	struct timer_list	tx_watchdog;
 };
 
 //free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC
@@ -458,33 +496,15 @@
  * conditions, still route realtime traffic with as low jitter as
  * possible.
  */
-#ifdef USE_64BIT_ADDR
-static inline void build_rx_desc64(struct ns83820 *dev, u32 *desc, u64 link, u64 buf, u32 cmdsts, u32 extsts)
-{
-	desc[0] = link;
-	desc[1] = link >> 32;
-	desc[2] = buf;
-	desc[3] = buf >> 32;
-	desc[5] = extsts;
-	mb();
-	desc[4] = cmdsts;
-}
-
-#define build_rx_desc	build_rx_desc64
-#else
-
-static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts)
+static inline void build_rx_desc(struct ns83820 *dev, u32 *desc, dma_addr_t link, dma_addr_t buf, u32 cmdsts, u32 extsts)
 {
-	desc[0] = cpu_to_le32(link);
-	desc[1] = cpu_to_le32(buf);
-	desc[3] = cpu_to_le32(extsts);
+	desc_addr_set(desc + DESC_LINK, link);
+	desc_addr_set(desc + DESC_BUFPTR, buf);
+	desc[DESC_EXTSTS] = extsts;
 	mb();
-	desc[2] = cpu_to_le32(cmdsts);
+	desc[DESC_CMDSTS] = cmdsts;
 }
 
-#define build_rx_desc	build_rx_desc32
-#endif
-
 #define nr_rx_empty(dev) ((NR_RX_DESC-2 + dev->rx_info.next_rx - dev->rx_info.next_empty) % NR_RX_DESC)
 static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
 {
@@ -717,7 +737,7 @@
 		phy_intr(dev);
 
 		/* Okay, let it rip */
-		spin_lock(&dev->misc_lock);
+		spin_lock_irq(&dev->misc_lock);
 		dev->IMR_cache |= ISR_PHY;
 		dev->IMR_cache |= ISR_RXRCMP;
 		//dev->IMR_cache |= ISR_RXERR;
@@ -731,7 +751,7 @@
 
 		writel(dev->IMR_cache, dev->base + IMR);
 		writel(1, dev->base + IER);
-		spin_unlock(&dev->misc_lock);
+		spin_unlock_irq(&dev->misc_lock);
 
 		kick_rx(dev);
 
@@ -788,7 +808,7 @@
 	else
 		kick_rx(dev);
 	if (dev->rx_info.idle)
-		Dprintk("BAD\n");
+		printk(KERN_DEBUG "%s: BAD\n", dev->net_dev.name);
 }
 
 /* rx_irq
@@ -820,14 +840,14 @@
 	dprintk("walking descs\n");
 	next_rx = info->next_rx;
 	desc = info->next_rx_desc;
-	while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) &&
+	while ((CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[DESC_CMDSTS]))) &&
 	       (cmdsts != CMDSTS_OWN)) {
 		struct sk_buff *skb;
-		u32 extsts = le32_to_cpu(desc[EXTSTS]);
-		dma_addr_t bufptr = desc_addr_get(desc);
+		u32 extsts = le32_to_cpu(desc[DESC_EXTSTS]);
+		dma_addr_t bufptr = desc_addr_get(desc + DESC_BUFPTR);
 
 		dprintk("cmdsts: %08x\n", cmdsts);
-		dprintk("link: %08x\n", cpu_to_le32(desc[LINK]));
+		dprintk("link: %08x\n", cpu_to_le32(desc[DESC_LINK]));
 		dprintk("extsts: %08x\n", extsts);
 
 		skb = info->skbs[next_rx];
@@ -881,8 +901,13 @@
 {
 	struct ns83820 *dev = (void *)_dev;
 	rx_irq(dev);
-	writel(0x002, dev->base + IHR);
-	writel(dev->IMR_cache | ISR_RXDESC, dev->base + IMR);
+	writel(ihr, dev->base + IHR);
+
+	spin_lock_irq(&dev->misc_lock);
+	dev->IMR_cache |= ISR_RXDESC;
+	writel(dev->IMR_cache, dev->base + IMR);
+	spin_unlock_irq(&dev->misc_lock);
+
 	rx_irq(dev);
 	ns83820_rx_kick(dev);
 }
@@ -891,8 +916,8 @@
  */
 static inline void kick_tx(struct ns83820 *dev)
 {
-	dprintk("kick_tx(%p): tx_idle=%ld, tx_idx=%d free_idx=%d\n",
-		dev, dev->tx_idle, dev->tx_idx, dev->tx_free_idx);
+	dprintk("kick_tx(%p): tx_idx=%d free_idx=%d\n",
+		dev, dev->tx_idx, dev->tx_free_idx);
 	writel(CR_TXE, dev->base + CR);
 }
 
@@ -903,14 +928,16 @@
 {
 	u32 cmdsts, tx_done_idx, *desc;
 
+	spin_lock_irq(&dev->tx_lock);
+
 	dprintk("do_tx_done(%p)\n", dev);
 	tx_done_idx = dev->tx_done_idx;
 	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 
 	dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
-		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[CMDSTS]));
+		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
 	while ((tx_done_idx != dev->tx_free_idx) &&
-	       !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[CMDSTS]))) ) {
+	       !(CMDSTS_OWN & (cmdsts = le32_to_cpu(desc[DESC_CMDSTS]))) ) {
 		struct sk_buff *skb;
 		unsigned len;
 		dma_addr_t addr;
@@ -929,13 +956,14 @@
 		dprintk("done(%p)\n", skb);
 
 		len = cmdsts & CMDSTS_LEN_MASK;
-		addr = desc_addr_get(desc);
+		addr = desc_addr_get(desc + DESC_BUFPTR);
 		if (skb) {
 			pci_unmap_single(dev->pci_dev,
 					addr,
 					len,
 					PCI_DMA_TODEVICE);
 			dev_kfree_skb_irq(skb);
+			atomic_dec(&dev->nr_tx_skbs);
 		} else
 			pci_unmap_page(dev->pci_dev, 
 					addr,
@@ -944,7 +972,7 @@
 
 		tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC;
 		dev->tx_done_idx = tx_done_idx;
-		desc[CMDSTS] = cpu_to_le32(0);
+		desc[DESC_CMDSTS] = cpu_to_le32(0);
 		mb();
 		desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
 	}
@@ -957,6 +985,7 @@
 		netif_start_queue(&dev->net_dev);
 		netif_wake_queue(&dev->net_dev);
 	}
+	spin_unlock_irq(&dev->tx_lock);
 }
 
 static void ns83820_cleanup_tx(struct ns83820 *dev)
@@ -966,12 +995,18 @@
 	for (i=0; i<NR_TX_DESC; i++) {
 		struct sk_buff *skb = dev->tx_skbs[i];
 		dev->tx_skbs[i] = NULL;
-		if (skb)
-			dev_kfree_skb(skb);
+		if (skb) {
+			u32 *desc = dev->tx_descs + (i * DESC_SIZE);
+			pci_unmap_single(dev->pci_dev,
+					desc_addr_get(desc + DESC_BUFPTR),
+					le32_to_cpu(desc[DESC_CMDSTS]) & CMDSTS_LEN_MASK,
+					PCI_DMA_TODEVICE);
+			dev_kfree_skb_irq(skb);
+			atomic_dec(&dev->nr_tx_skbs);
+		}
 	}
 
 	memset(dev->tx_descs, 0, NR_TX_DESC * DESC_SIZE * 4);
-	set_bit(0, &dev->tx_idle);
 }
 
 /* transmit routine.  This code relies on the network layer serializing
@@ -985,7 +1020,7 @@
 	struct ns83820 *dev = (struct ns83820 *)_dev;
 	u32 free_idx, cmdsts, extsts;
 	int nr_free, nr_frags;
-	unsigned tx_done_idx;
+	unsigned tx_done_idx, last_idx;
 	dma_addr_t buf;
 	unsigned len;
 	skb_frag_t *frag;
@@ -1004,7 +1039,7 @@
 		netif_start_queue(&dev->net_dev);
 	}
 
-	free_idx = dev->tx_free_idx;
+	last_idx = free_idx = dev->tx_free_idx;
 	tx_done_idx = dev->tx_done_idx;
 	nr_free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC;
 	nr_free -= 1;
@@ -1058,15 +1093,16 @@
 
 		dprintk("frag[%3u]: %4u @ 0x%08Lx\n", free_idx, len,
 			(unsigned long long)buf);
+		last_idx = free_idx;
 		free_idx = (free_idx + 1) % NR_TX_DESC;
-		desc[LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
-		desc_addr_set(desc, buf);
-		desc[EXTSTS] = cpu_to_le32(extsts);
+		desc[DESC_LINK] = cpu_to_le32(dev->tx_phy_descs + (free_idx * DESC_SIZE * 4));
+		desc_addr_set(desc + DESC_BUFPTR, buf);
+		desc[DESC_EXTSTS] = cpu_to_le32(extsts);
 
 		cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
 		cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
 		cmdsts |= len;
-		desc[CMDSTS] = cpu_to_le32(cmdsts);
+		desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);
 
 		if (residue) {
 			buf += len;
@@ -1088,15 +1124,22 @@
 		nr_frags--;
 	}
 	dprintk("done pkt\n");
-	dev->tx_skbs[free_idx] = skb;
-	first_desc[CMDSTS] |= cpu_to_le32(CMDSTS_OWN);
+
+	spin_lock_irq(&dev->tx_lock);
+	dev->tx_skbs[last_idx] = skb;
+	first_desc[DESC_CMDSTS] |= cpu_to_le32(CMDSTS_OWN);
 	dev->tx_free_idx = free_idx;
+	atomic_inc(&dev->nr_tx_skbs);
+	spin_unlock_irq(&dev->tx_lock);
+
 	kick_tx(dev);
 
 	/* Check again: we may have raced with a tx done irq */
 	if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev))
 		netif_start_queue(&dev->net_dev);
 
+	/* set the transmit start time to catch transmit timeouts */
+	dev->net_dev.trans_start = jiffies;
 	return 0;
 }
 
@@ -1190,6 +1233,7 @@
 	spin_unlock(&dev->misc_lock);
 }
 
+static void ns83820_do_isr(struct ns83820 *dev, u32 isr);
 static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
 {
 	struct ns83820 *dev = data;
@@ -1200,7 +1244,11 @@
 
 	isr = readl(dev->base + ISR);
 	dprintk("irq: %08x\n", isr);
+	ns83820_do_isr(dev, isr);
+}
 
+static void ns83820_do_isr(struct ns83820 *dev, u32 isr)
+{
 #ifdef DEBUG
 	if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
 		Dprintk("odd isr? 0x%08x\n", isr);
@@ -1214,7 +1262,12 @@
 
 	if ((ISR_RXDESC | ISR_RXOK) & isr) {
 		prefetch(dev->rx_info.next_rx_desc);
-		writel(dev->IMR_cache & ~(ISR_RXDESC | ISR_RXOK), dev->base + IMR);
+
+		spin_lock_irq(&dev->misc_lock);
+		dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
+		writel(dev->IMR_cache, dev->base + IMR);
+		spin_unlock_irq(&dev->misc_lock);
+
 		tasklet_schedule(&dev->rx_tasklet);
 		//rx_irq(dev);
 		//writel(4, dev->base + IHR);
@@ -1246,12 +1299,11 @@
 			printk(KERN_ALERT "%s: BUG -- txdp out of range\n", dev->net_dev.name);
 			dev->tx_idx = 0;
 		}
-		if (dev->tx_idx != dev->tx_free_idx)
-			writel(CR_TXE, dev->base + CR);
-			//kick_tx(dev);
-		else
-			dev->tx_idle = 1;
-		mb();
+		/* The may have been a race between a pci originated read
+		 * and the descriptor update from the cpu.  Just in case, 
+		 * kick the transmitter if the hardware thinks it is on a 
+		 * different descriptor than we are.
+		 */
 		if (dev->tx_idx != dev->tx_free_idx)
 			kick_tx(dev);
 	}
@@ -1259,12 +1311,38 @@
 	/* Defer tx ring processing until more than a minimum amount of
 	 * work has accumulated
 	 */
-	if ((ISR_TXDESC | ISR_TXIDLE) & isr)
+	if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
 		do_tx_done(dev);
 
+		/* Disable TxOk if there are no outstanding tx packets.
+		 */
+		if ((dev->tx_done_idx == dev->tx_free_idx) &&
+		    (dev->IMR_cache & ISR_TXOK)) {
+			spin_lock_irq(&dev->misc_lock);
+			dev->IMR_cache &= ~ISR_TXOK;
+			writel(dev->IMR_cache, dev->base + IMR);
+			spin_unlock_irq(&dev->misc_lock);
+		}
+	}
+
+	/* The TxIdle interrupt can come in before the transmit has
+	 * completed.  Normally we reap packets off of the combination
+	 * of TxDesc and TxIdle and leave TxOk disabled (since it 
+	 * occurs on every packet), but when no further irqs of this 
+	 * nature are expected, we must enable TxOk.
+	 */
+	if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
+		spin_lock_irq(&dev->misc_lock);
+		dev->IMR_cache |= ISR_TXOK;
+		writel(dev->IMR_cache, dev->base + IMR);
+		spin_unlock_irq(&dev->misc_lock);
+	}
+
+	/* MIB interrupt: one of the statistics counters is about to overflow */
 	if (unlikely(ISR_MIB & isr))
 		ns83820_mib_isr(dev);
 
+	/* PHY: Link up/down/negotiation state change */
 	if (unlikely(ISR_PHY & isr))
 		phy_intr(dev);
 
@@ -1289,6 +1367,7 @@
 	struct ns83820 *dev = (struct ns83820 *)_dev;
 
 	/* FIXME: protect against interrupt handler? */
+	del_timer_sync(&dev->tx_watchdog);
 
 	/* disable interrupts */
 	writel(0, dev->base + IMR);
@@ -1302,13 +1381,75 @@
 
 	synchronize_irq(dev->pci_dev->irq);
 
+	spin_lock_irq(&dev->misc_lock);
 	dev->IMR_cache &= ~(ISR_TXURN | ISR_TXIDLE | ISR_TXERR | ISR_TXDESC | ISR_TXOK);
+	spin_unlock_irq(&dev->misc_lock);
+
 	ns83820_cleanup_rx(dev);
 	ns83820_cleanup_tx(dev);
 
 	return 0;
 }
 
+static void ns83820_do_isr(struct ns83820 *dev, u32 isr);
+static void ns83820_tx_timeout(struct net_device *_dev)
+{
+	struct ns83820 *dev = (struct ns83820 *)_dev;
+        u32 tx_done_idx, *desc;
+	long flags;
+
+	local_irq_save(flags);
+
+	tx_done_idx = dev->tx_done_idx;
+	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
+
+	printk(KERN_INFO "%s: tx_timeout: tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
+		dev->net_dev.name,
+		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
+
+#if defined(DEBUG)
+	{
+		u32 isr;
+		isr = readl(dev->base + ISR);
+		printk("irq: %08x imr: %08x\n", isr, dev->IMR_cache);
+		ns83820_do_isr(dev, isr);
+	}
+#endif
+
+	do_tx_done(dev);
+
+	tx_done_idx = dev->tx_done_idx;
+	desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
+
+	printk(KERN_INFO "%s: after: tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
+		dev->net_dev.name,
+		tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
+
+	local_irq_restore(flags);
+}
+
+static void ns83820_tx_watch(unsigned long data)
+{
+	struct ns83820 *dev = (void *)data;
+
+#if defined(DEBUG)
+	printk("ns83820_tx_watch: %u %u %d\n",
+		dev->tx_done_idx, dev->tx_free_idx, atomic_read(&dev->nr_tx_skbs)
+		);
+#endif
+
+	if (time_after(jiffies, dev->net_dev.trans_start + 1*HZ) &&
+	    dev->tx_done_idx != dev->tx_free_idx) {
+		printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n",
+			dev->net_dev.name,
+			dev->tx_done_idx, dev->tx_free_idx,
+			atomic_read(&dev->nr_tx_skbs));
+		ns83820_tx_timeout(&dev->net_dev);
+	}
+
+	mod_timer(&dev->tx_watchdog, jiffies + 2*HZ);
+}
+
 static int ns83820_open(struct net_device *_dev)
 {
 	struct ns83820 *dev = (struct ns83820 *)_dev;
@@ -1326,7 +1467,7 @@
 
 	memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE);
 	for (i=0; i<NR_TX_DESC; i++) {
-		dev->tx_descs[(i * DESC_SIZE) + LINK]
+		dev->tx_descs[(i * DESC_SIZE) + DESC_LINK]
 				= cpu_to_le32(
 				  dev->tx_phy_descs
 				  + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4);
@@ -1338,9 +1479,11 @@
 	writel(0, dev->base + TXDP_HI);
 	writel(desc, dev->base + TXDP);
 
-//printk("IMR: %08x / %08x\n", readl(dev->base + IMR), dev->IMR_cache);
+	init_timer(&dev->tx_watchdog);
+	dev->tx_watchdog.data = (unsigned long)dev;
+	dev->tx_watchdog.function = ns83820_tx_watch;
+	mod_timer(&dev->tx_watchdog, jiffies + 2*HZ);
 
-	set_bit(0, &dev->tx_idle);
 	netif_start_queue(&dev->net_dev);	/* FIXME: wait for phy to come up */
 
 	return 0;
@@ -1350,15 +1493,6 @@
 	return ret;
 }
 
-#if 0	/* FIXME: implement this! */
-static void ns83820_tx_timeout(struct net_device *_dev)
-{
-	struct ns83820 *dev = (struct ns83820 *)_dev;
-
-	printk("ns83820_tx_timeout\n");
-}
-#endif
-
 static void ns83820_getmac(struct ns83820 *dev, u8 *mac)
 {
 	unsigned i;
@@ -1392,6 +1526,7 @@
 	u8 *rfcr = dev->base + RFCR;
 	u32 and_mask = 0xffffffff;
 	u32 or_mask = 0;
+	u32 val;
 
 	if (dev->net_dev.flags & IFF_PROMISC)
 		or_mask |= RFCR_AAU | RFCR_AAM;
@@ -1404,10 +1539,225 @@
 		and_mask &= ~RFCR_AAM;
 
 	spin_lock_irq(&dev->misc_lock);
-	writel((readl(rfcr) & and_mask) | or_mask, rfcr);
+	val = (readl(rfcr) & and_mask) | or_mask;
+	/* Ramit : RFCR Write Fix doc says RFEN must be 0 modify other bits */
+	writel(val & ~RFCR_RFEN, rfcr);
+	writel(val, rfcr);
 	spin_unlock_irq(&dev->misc_lock);
 }
 
+static void ns83820_run_bist(struct ns83820 *dev, const char *name, u32 enable, u32 done, u32 fail)
+{
+	int timed_out = 0;
+	long start;
+	u32 status;
+	int loops = 0;
+
+	dprintk("%s: start %s\n", dev->net_dev.name, name);
+
+	start = jiffies;
+
+	writel(enable, dev->base + PTSCR);
+	for (;;) {
+		loops++;
+		status = readl(dev->base + PTSCR);
+		if (!(status & enable))
+			break;
+		if (status & done)
+			break;
+		if (status & fail)
+			break;
+		if ((jiffies - start) >= HZ) {
+			timed_out = 1;
+			break;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	if (status & fail)
+		printk(KERN_INFO "%s: %s failed! (0x%08x & 0x%08x)\n",
+			dev->net_dev.name, name, status, fail);
+	else if (timed_out)
+		printk(KERN_INFO "%s: run_bist %s timed out! (%08x)\n",
+			dev->net_dev.name, name, status);
+
+	dprintk("%s: done %s in %d loops\n", dev->net_dev.name, name, loops);
+}
+
+static void ns83820_mii_write_bit(struct ns83820 *dev, int bit)
+{
+	/* drive MDC low */
+	dev->MEAR_cache &= ~MEAR_MDC;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* enable output, set bit */
+	dev->MEAR_cache |= MEAR_MDDIR;
+	if (bit)
+		dev->MEAR_cache |= MEAR_MDIO;
+	else
+		dev->MEAR_cache &= ~MEAR_MDIO;
+
+	/* set the output bit */
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* Wait.  Max clock rate is 2.5MHz, this way we come in under 1MHz */
+	udelay(1);
+
+	/* drive MDC high causing the data bit to be latched */
+	dev->MEAR_cache |= MEAR_MDC;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* Wait again... */
+	udelay(1);
+}
+
+static int ns83820_mii_read_bit(struct ns83820 *dev)
+{
+	int bit;
+
+	/* drive MDC low, disable output */
+	dev->MEAR_cache &= ~MEAR_MDC;
+	dev->MEAR_cache &= ~MEAR_MDDIR;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+	readl(dev->base + MEAR);
+
+	/* Wait.  Max clock rate is 2.5MHz, this way we come in under 1MHz */
+	udelay(1);
+
+	/* drive MDC high causing the data bit to be latched */
+	bit = (readl(dev->base + MEAR) & MEAR_MDIO) ? 1 : 0;
+	dev->MEAR_cache |= MEAR_MDC;
+	writel(dev->MEAR_cache, dev->base + MEAR);
+
+	/* Wait again... */
+	udelay(1);
+
+	return bit;
+}
+
+static unsigned ns83820_mii_read_reg(struct ns83820 *dev, unsigned phy, unsigned reg)
+{
+	unsigned data = 0;
+	int i;
+
+	/* read some garbage so that we eventually sync up */
+	for (i=0; i<64; i++)
+		ns83820_mii_read_bit(dev);
+
+	ns83820_mii_write_bit(dev, 0);	/* start */
+	ns83820_mii_write_bit(dev, 1);
+	ns83820_mii_write_bit(dev, 1);	/* opcode read */
+	ns83820_mii_write_bit(dev, 0);
+
+	/* write out the phy address: 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, phy & (0x10 >> i));
+
+	/* write out the register address, 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, reg & (0x10 >> i));
+
+	ns83820_mii_read_bit(dev);	/* turn around cycles */
+	ns83820_mii_read_bit(dev);
+
+	/* read in the register data, 16 bits msb first */
+	for (i=0; i<16; i++) {
+		data <<= 1;
+		data |= ns83820_mii_read_bit(dev);
+	}
+
+	return data;
+}
+
+static unsigned ns83820_mii_write_reg(struct ns83820 *dev, unsigned phy, unsigned reg, unsigned data)
+{
+	int i;
+
+	/* read some garbage so that we eventually sync up */
+	for (i=0; i<64; i++)
+		ns83820_mii_read_bit(dev);
+
+	ns83820_mii_write_bit(dev, 0);	/* start */
+	ns83820_mii_write_bit(dev, 1);
+	ns83820_mii_write_bit(dev, 0);	/* opcode read */
+	ns83820_mii_write_bit(dev, 1);
+
+	/* write out the phy address: 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, phy & (0x10 >> i));
+
+	/* write out the register address, 5 bits, msb first */
+	for (i=0; i<5; i++)
+		ns83820_mii_write_bit(dev, reg & (0x10 >> i));
+
+	ns83820_mii_read_bit(dev);	/* turn around cycles */
+	ns83820_mii_read_bit(dev);
+
+	/* read in the register data, 16 bits msb first */
+	for (i=0; i<16; i++)
+		ns83820_mii_write_bit(dev, (data >> (15 - i)) & 1);
+
+	return data;
+}
+
+static void ns83820_probe_phy(struct ns83820 *dev)
+{
+	static int first;
+	int i;
+#define MII_PHYIDR1	0x02
+#define MII_PHYIDR2	0x03
+
+#if 0
+	if (!first) {
+		unsigned tmp;
+		ns83820_mii_read_reg(dev, 1, 0x09);
+		ns83820_mii_write_reg(dev, 1, 0x10, 0x0d3e);
+
+		tmp = ns83820_mii_read_reg(dev, 1, 0x00);
+		ns83820_mii_write_reg(dev, 1, 0x00, tmp | 0x8000);
+		udelay(1300);
+		ns83820_mii_read_reg(dev, 1, 0x09);
+	}
+#endif
+	first = 1;
+
+	for (i=1; i<2; i++) {
+		int j;
+		unsigned a, b;
+		a = ns83820_mii_read_reg(dev, i, MII_PHYIDR1);
+		b = ns83820_mii_read_reg(dev, i, MII_PHYIDR2);
+
+		//printk("%s: phy %d: 0x%04x 0x%04x\n",
+		//	dev->net_dev.name, i, a, b);
+
+		for (j=0; j<0x16; j+=4) {
+			dprintk("%s: [0x%02x] %04x %04x %04x %04x\n",
+				dev->net_dev.name, j,
+				ns83820_mii_read_reg(dev, i, 0 + j),
+				ns83820_mii_read_reg(dev, i, 1 + j),
+				ns83820_mii_read_reg(dev, i, 2 + j),
+				ns83820_mii_read_reg(dev, i, 3 + j)
+				);
+		}
+	}
+	{
+		unsigned a, b;
+		/* read firmware version: memory addr is 0x8402 and 0x8403 */
+		ns83820_mii_write_reg(dev, 1, 0x16, 0x000d);
+		ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e);
+		a = ns83820_mii_read_reg(dev, 1, 0x1d);
+
+		ns83820_mii_write_reg(dev, 1, 0x16, 0x000d);
+		ns83820_mii_write_reg(dev, 1, 0x1e, 0x810e);
+		b = ns83820_mii_read_reg(dev, 1, 0x1d);
+		dprintk("version: 0x%04x 0x%04x\n", a, b);
+	}
+}
+
 static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
 	struct ns83820 *dev;
@@ -1415,6 +1765,7 @@
 	int err;
 	int using_dac = 0;
 
+	/* See if we can set the dma mask early on; failure is fatal. */
 	if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffff)) {
 		using_dac = 1;
 	} else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) {
@@ -1443,7 +1794,7 @@
 
 	err = pci_enable_device(pci_dev);
 	if (err) {
-		printk(KERN_INFO "ns83820: pci_enable_dev: %d\n", err);
+		printk(KERN_INFO "ns83820: pci_enable_dev failed: %d\n", err);
 		goto out_free;
 	}
 
@@ -1461,6 +1812,7 @@
 	dprintk("%p: %08lx  %p: %08lx\n",
 		dev->tx_descs, (long)dev->tx_phy_descs,
 		dev->rx_info.descs, (long)dev->rx_info.phy_descs);
+
 	/* disable interrupts */
 	writel(0, dev->base + IMR);
 	writel(0, dev->base + IER);
@@ -1479,45 +1831,47 @@
 		goto out_unmap;
 	}
 
-	if(register_netdev(&dev->net_dev)) goto out_unmap;
+	err = register_netdev(&dev->net_dev);
+	if (err) {
+		printk(KERN_INFO "ns83820: unable to register netdev: %d\n", err);
+		goto out_unmap;
+	}
+
+	printk("%s: ns83820.c: 0x22c: %08x, subsystem: %04x:%04x\n",
+		dev->net_dev.name, le32_to_cpu(readl(dev->base + 0x22c)),
+		pci_dev->subsystem_vendor, pci_dev->subsystem_device);
 
 	dev->net_dev.open = ns83820_open;
 	dev->net_dev.stop = ns83820_stop;
 	dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit;
-	dev->net_dev.change_mtu = ns83820_change_mtu;
 	dev->net_dev.get_stats = ns83820_get_stats;
 	dev->net_dev.change_mtu = ns83820_change_mtu;
 	dev->net_dev.set_multicast_list = ns83820_set_multicast;
 	dev->net_dev.do_ioctl = ns83820_ioctl;
-	//FIXME: dev->net_dev.tx_timeout = ns83820_tx_timeout;
+	dev->net_dev.tx_timeout = ns83820_tx_timeout;
+	dev->net_dev.watchdog_timeo = 5 * HZ;
 
 	pci_set_drvdata(pci_dev, dev);
 
 	ns83820_do_reset(dev, CR_RST);
 
-	dprintk("start bist\n");
-	writel(PTSCR_EEBIST_EN, dev->base + PTSCR);
-	do {
-		schedule();
-	} while (readl(dev->base + PTSCR) & PTSCR_EEBIST_EN);
-	dprintk("done bist\n");
-
-	dprintk("start eeload\n");
-	writel(PTSCR_EELOAD_EN, dev->base + PTSCR);
-	do {
-		schedule();
-	} while (readl(dev->base + PTSCR) & PTSCR_EELOAD_EN);
-	dprintk("done eeload\n");
+	/* Must reset the ram bist before running it */
+	writel(PTSCR_RBIST_RST, dev->base + PTSCR);
+	ns83820_run_bist(dev, "sram bist",   PTSCR_RBIST_EN,
+			 PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL);
+	ns83820_run_bist(dev, "eeprom bist", PTSCR_EEBIST_EN, 0,
+			 PTSCR_EEBIST_FAIL);
+	ns83820_run_bist(dev, "eeprom load", PTSCR_EELOAD_EN, 0, 0);
 
 	/* I love config registers */
 	dev->CFG_cache = readl(dev->base + CFG);
 
 	if ((dev->CFG_cache & CFG_PCI64_DET)) {
-		printk("%s: detected 64 bit PCI data bus.\n",
+		printk(KERN_INFO "%s: detected 64 bit PCI data bus.\n",
 			dev->net_dev.name);
 		/*dev->CFG_cache |= CFG_DATA64_EN;*/
 		if (!(dev->CFG_cache & CFG_DATA64_EN))
-			printk("%s: EEPROM did not enable 64 bit bus.  Disabled.\n",
+			printk(KERN_INFO "%s: EEPROM did not enable 64 bit bus.  Disabled.\n",
 				dev->net_dev.name);
 	} else
 		dev->CFG_cache &= ~(CFG_DATA64_EN);
@@ -1529,6 +1883,11 @@
 			  CFG_EXTSTS_EN   | CFG_EXD         | CFG_PESEL;
 	dev->CFG_cache |= CFG_REQALG;
 	dev->CFG_cache |= CFG_POW;
+	dev->CFG_cache |= CFG_TMRTEST;
+
+	/* When compiled with 64 bit addressing, we must always enable
+	 * the 64 bit descriptor format.
+	 */
 #ifdef USE_64BIT_ADDR
 	dev->CFG_cache |= CFG_M64ADDR;
 #endif
@@ -1540,7 +1899,8 @@
 
 	/* setup optical transceiver if we have one */
 	if (dev->CFG_cache & CFG_TBI_EN) {
-		printk("%s: enabling optical transceiver\n", dev->net_dev.name);
+		printk(KERN_INFO "%s: enabling optical transceiver\n",
+			dev->net_dev.name);
 		writel(readl(dev->base + GPIOR) | 0x3e8, dev->base + GPIOR);
 
 		/* setup auto negotiation feature advertisement */
@@ -1560,6 +1920,14 @@
 	writel(dev->CFG_cache, dev->base + CFG);
 	dprintk("CFG: %08x\n", dev->CFG_cache);
 
+	if (reset_phy) {
+		printk(KERN_INFO "%s: resetting phy\n", dev->net_dev.name);
+		writel(dev->CFG_cache | CFG_PHY_RST, dev->base + CFG);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((HZ+99)/100);
+		writel(dev->CFG_cache, dev->base + CFG);
+	}
+
 #if 0	/* Huh?  This sets the PCI latency register.  Should be done via 
 	 * the PCI layer.  FIXME.
 	 */
@@ -1572,7 +1940,9 @@
 	 * can be transmitted is 8192 - FLTH - burst size.
 	 * If only the transmit fifo was larger...
 	 */
-	writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA1024
+	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
+	 * some DELL and COMPAQ SMP systems */
+	writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512
 		| ((1600 / 32) * 0x100),
 		dev->base + TXCFG);
 
@@ -1582,12 +1952,15 @@
 	writel(0x000, dev->base + IHR);
 
 	/* Set Rx to full duplex, don't accept runt, errored, long or length
-	 * range errored packets.  Set MXDMA to 0 => 1024 word burst
+	 * range errored packets.  Use 512 byte DMA.
 	 */
+	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
+	 * some DELL and COMPAQ SMP systems 
+	 * Turn on ALP, only we are accpeting Jumbo Packets */
 	writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
 		| RXCFG_STRIPCRC
-		| RXCFG_ALP
-		| (RXCFG_MXDMA0 * 0) | 0, dev->base + RXCFG);
+		//| RXCFG_ALP
+		| (RXCFG_MXDMA512) | 0, dev->base + RXCFG);
 
 	/* Disable priority queueing */
 	writel(0, dev->base + PQCR);
@@ -1597,13 +1970,23 @@
 	 * revision of the chip does not properly accept IP fragments
 	 * at least for UDP.
 	 */
+	/* Ramit : Be sure to turn on RXCFG_ARP if VLAN's are enabled, since
+	 * the MAC it calculates the packetsize AFTER stripping the VLAN
+	 * header, and if a VLAN Tagged packet of 64 bytes is received (like
+	 * a ping with a VLAN header) then the card, strips the 4 byte VLAN
+	 * tag and then checks the packet size, so if RXCFG_ARP is not enabled,
+	 * it discrards it!.  These guys......
+	 */
 	writel(VRCR_IPEN | VRCR_VTDEN, dev->base + VRCR);
 
 	/* Enable per-packet TCP/UDP/IP checksumming */
 	writel(VTCR_PPCHK, dev->base + VTCR);
 
-	/* Disable Pause frames */
-	writel(0, dev->base + PCR);
+	/* Ramit : Enable async and sync pause frames */
+	/* writel(0, dev->base + PCR); */
+	writel((PCR_PS_MCAST | PCR_PS_DA | PCR_PSEN | PCR_FFLO_4K |
+		PCR_FFHI_8K | PCR_STLO_4 | PCR_STHI_8 | PCR_PAUSE_CNT),
+		dev->base + PCR);
 
 	/* Disable Wake On Lan */
 	writel(0, dev->base + WCSR);
@@ -1631,6 +2014,10 @@
 		(dev->net_dev.features & NETIF_F_HIGHDMA) ? "h,sg" : "sg"
 		);
 
+#ifdef PHY_CODE_IS_FINISHED
+	ns83820_probe_phy(dev);
+#endif
+
 	return 0;
 
 out_unmap:
@@ -1670,7 +2057,7 @@
 }
 
 static struct pci_device_id ns83820_pci_tbl[] __devinitdata = {
-	{ 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+	{ 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, .driver_data = 0, },
 	{ 0, },
 };
 
@@ -1702,6 +2089,15 @@
 MODULE_LICENSE("GPL");
 
 MODULE_DEVICE_TABLE(pci, ns83820_pci_tbl);
+
+MODULE_PARM(lnksts, "i");
+MODULE_PARM_DESC(lnksts, "Polarity of LNKSTS bit");
+
+MODULE_PARM(ihr, "i");
+MODULE_PARM_DESC(ihr, "Time in 100 us increments to delay interrupts (range 0-127)");
+
+MODULE_PARM(reset_phy, "i");
+MODULE_PARM_DESC(reset_phy, "Set to 1 to reset the PHY on startup");
 
 module_init(ns83820_init);
 module_exit(ns83820_exit);
diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
--- a/drivers/net/pcmcia/smc91c92_cs.c	Fri Oct 11 21:23:01 2002
+++ b/drivers/net/pcmcia/smc91c92_cs.c	Fri Oct 11 21:23:01 2002
@@ -8,7 +8,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    smc91c92_cs.c 1.113 2001/10/13 00:08:53
+    smc91c92_cs.c 1.2 2002/09/28 15:00:00
     
     This driver contains code written by Donald Becker
     (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
@@ -37,12 +37,15 @@
 #include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -88,6 +91,9 @@
 #define DEBUG(n, args...)
 #endif
 
+#define DRV_NAME	"smc91c92_cs"
+#define DRV_VERSION	"1.2"
+
 /*====================================================================*/
 
 /* Operational parameter that usually are not changed. */
@@ -109,6 +115,7 @@
 struct smc_private {
     dev_link_t			link;
     struct net_device		dev;
+    spinlock_t			lock;
     u_short			manfid;
     u_short			cardid;
     struct net_device_stats	stats;
@@ -122,7 +129,7 @@
     u_short			media_status;
     u_short			fast_poll;
     u_short			link_status;
-    int				phy_id;
+    struct mii_if_info		mii_if;
 };
 
 /* Special definitions for Megahertz multifunction cards */
@@ -292,9 +299,11 @@
 static void smc_set_xcvr(struct net_device *dev, int if_port);
 static void smc_reset(struct net_device *dev);
 static void media_check(u_long arg);
-static void mdio_sync(ioaddr_t addr);
-static int mdio_read(ioaddr_t addr, int phy_id, int loc);
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value);
+static void smc_mdio_sync(ioaddr_t addr);
+static int smc_mdio_read(struct net_device *dev, int phy_id, int loc);
+static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value);
+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int smc_link_ok(struct net_device *dev);
 
 /*======================================================================
 
@@ -346,7 +355,7 @@
     if (!smc) return NULL;
     memset(smc, 0, sizeof(struct smc_private));
     link = &smc->link; dev = &smc->dev;
-
+    spin_lock_init(&smc->lock);
     link->release.function = &smc91c92_release;
     link->release.data = (u_long)link;
     link->io.NumPorts1 = 16;
@@ -369,6 +378,7 @@
     dev->get_stats = &smc91c92_get_stats;
     dev->set_config = &s9k_config;
     dev->set_multicast_list = &set_rx_mode;
+    dev->do_ioctl = &smc_ioctl;
     ether_setup(dev);
     dev->open = &smc91c92_open;
     dev->stop = &smc91c92_close;
@@ -377,6 +387,12 @@
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
     dev->priv = link->priv = link->irq.Instance = smc;
+   
+    smc->mii_if.dev = dev;
+    smc->mii_if.mdio_read = smc_mdio_read;
+    smc->mii_if.mdio_write = smc_mdio_write;
+    smc->mii_if.phy_id_mask = 0x1f;
+    smc->mii_if.reg_num_mask = 0x1f;
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -1044,10 +1060,10 @@
 	SMC_SELECT_BANK(3);
 
 	for (i = 0; i < 32; i++) {
-	    j = mdio_read(dev->base_addr + MGMT, i, 1);
+	    j = smc_mdio_read(dev, i, 1);
 	    if ((j != 0) && (j != 0xffff)) break;
 	}
-	smc->phy_id = (i < 32) ? i : -1;
+	smc->mii_if.phy_id = (i < 32) ? i : -1;
 	if (i < 32) {
 	    DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
 	} else {
@@ -1190,7 +1206,7 @@
 #define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
 #define MDIO_DATA_READ		0x02
 
-static void mdio_sync(ioaddr_t addr)
+static void smc_mdio_sync(ioaddr_t addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -1199,12 +1215,13 @@
     }
 }
 
-static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+static int smc_mdio_read(struct net_device *dev, int phy_id, int loc)
 {
+    ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
 
-    mdio_sync(addr);
+    smc_mdio_sync(addr);
     for (i = 13; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1218,12 +1235,13 @@
     return (retval>>1) & 0xffff;
 }
 
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 {
+    ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
 
-    mdio_sync(addr);
+    smc_mdio_sync(addr);
     for (i = 31; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1777,6 +1795,7 @@
 static void set_rx_mode(struct net_device *dev)
 {
     ioaddr_t ioaddr = dev->base_addr;
+    struct smc_private *smc = dev->priv;
     u_int multicast_table[ 2 ] = { 0, };
     unsigned long flags;
     u_short rx_cfg_setting;
@@ -1795,16 +1814,15 @@
     }
     
     /* Load MC table and Rx setting into the chip without interrupts. */
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(3);
     outl(multicast_table[0], ioaddr + MULTICAST0);
     outl(multicast_table[1], ioaddr + MULTICAST4);
     SMC_SELECT_BANK(0);
     outw(rx_cfg_setting, ioaddr + RCR);
     SMC_SELECT_BANK(2);
-    restore_flags(flags);
-    
+    spin_unlock_irqrestore(&smc->lock, flags);
+ 
     return;
 }
 
@@ -1917,11 +1935,11 @@
 	SMC_SELECT_BANK(3);
 
 	/* Reset MII */
-	mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x8000);
+	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
 
 	/* Restart MII autonegotiation */
-	mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x0000);
-	mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x1200);
+	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
+	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
     }
 
     /* Enable interrupts. */
@@ -1942,7 +1960,6 @@
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
-    ioaddr_t mii_addr = dev->base_addr + MGMT;
     u_short link;
 
     saved_bank = inw(ioaddr + BANK_SELECT);
@@ -1974,20 +1991,20 @@
     }
 
     if (smc->cfg & CFG_MII_SELECT) {
-	if (smc->phy_id < 0)
+	if (smc->mii_if.phy_id < 0)
 	    goto reschedule;
 
 	SMC_SELECT_BANK(3);
-	link = mdio_read(mii_addr, smc->phy_id, 1);
+	link = smc_mdio_read(dev, smc->mii_if.phy_id, 1);
 	if (!link || (link == 0xffff)) {
   	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);
-	    smc->phy_id = -1;
+	    smc->mii_if.phy_id = -1;
 	    goto reschedule;
 	}
 
 	link &= 0x0004;
 	if (link != smc->link_status) {
-	    u_short p = mdio_read(mii_addr, smc->phy_id, 5);
+	    u_short p = smc_mdio_read(dev, smc->mii_if.phy_id, 5);
 	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
 		(link) ? "found" : "lost");
 	    if (link) {
@@ -2043,6 +2060,191 @@
     SMC_SELECT_BANK(saved_bank);
 }
 
+static int smc_link_ok(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    struct smc_private *smc = dev->priv;
+
+    if (smc->cfg & CFG_MII_SELECT) {
+	return mii_link_ok(&smc->mii_if);
+    } else {
+        SMC_SELECT_BANK(0);
+	return inw(ioaddr + EPH) & EPH_LINK_OK;
+    }
+}
+
+static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+    u16 tmp;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
+	SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
+		
+    SMC_SELECT_BANK(1);
+    tmp = inw(ioaddr + CONFIG);
+    ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
+    ecmd->transceiver = XCVR_INTERNAL;
+    ecmd->speed = SPEED_10;
+    ecmd->phy_address = ioaddr + MGMT;
+
+    SMC_SELECT_BANK(0);
+    tmp = inw(ioaddr + TCR);
+    ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+
+    return 0;
+}
+
+static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+    u16 tmp;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    if (ecmd->speed != SPEED_10)
+    	return -EINVAL;
+    if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+    	return -EINVAL;
+    if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
+	return -EINVAL;
+    if (ecmd->transceiver != XCVR_INTERNAL)
+    	return -EINVAL;
+
+    if (ecmd->port == PORT_AUI)
+	smc_set_xcvr(dev, 1);
+    else
+	smc_set_xcvr(dev, 0);
+
+    SMC_SELECT_BANK(0);
+    tmp = inw(ioaddr + TCR);
+    if (ecmd->duplex == DUPLEX_FULL)
+	tmp |= TCR_FDUPLX;
+    else
+	tmp &= ~TCR_FDUPLX;
+    outw(ioaddr + TCR, tmp);
+	
+    return 0;
+}
+
+static int smc_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+    u32 ethcmd;
+    struct smc_private *smc = dev->priv;
+
+    if (get_user(ethcmd, (u32 *)useraddr))
+	return -EFAULT;
+
+    switch (ethcmd) {
+
+    case ETHTOOL_GDRVINFO: {
+	struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+	strcpy(info.driver, DRV_NAME);
+	strcpy(info.version, DRV_VERSION);
+	if (copy_to_user(useraddr, &info, sizeof(info)))
+	    return -EFAULT;
+	return 0;
+    }
+
+    /* get settings */
+    case ETHTOOL_GSET: {
+	int ret;
+	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+	spin_lock_irq(&smc->lock);
+	if (smc->cfg & CFG_MII_SELECT)
+	    ret = mii_ethtool_gset(&smc->mii_if, &ecmd);
+	else
+	    ret = smc_netdev_get_ecmd(dev, &ecmd);
+	spin_unlock_irq(&smc->lock);
+	if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+	    return -EFAULT;
+	return ret;
+    }
+
+    /* set settings */
+    case ETHTOOL_SSET: {
+	int ret;
+	struct ethtool_cmd ecmd;
+	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+	    return -EFAULT;
+	spin_lock_irq(&smc->lock);
+	if (smc->cfg & CFG_MII_SELECT)
+	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);    
+	else
+	    ret = smc_netdev_set_ecmd(dev, &ecmd);
+	spin_unlock_irq(&smc->lock);
+	return ret;
+    }
+
+    /* get link status */
+    case ETHTOOL_GLINK: {
+	struct ethtool_value edata = { ETHTOOL_GLINK };
+	spin_lock_irq(&smc->lock);
+	edata.data = smc_link_ok(dev);
+	spin_unlock_irq(&smc->lock);
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+	    return -EFAULT;
+	return 0;
+    }
+
+#ifdef PCMCIA_DEBUG
+    /* get message-level */
+    case ETHTOOL_GMSGLVL: {
+	struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+	edata.data = pc_debug;
+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
+	    return -EFAULT;
+	return 0;
+    }
+    
+    /* set message-level */
+    case ETHTOOL_SMSGLVL: {
+	struct ethtool_value edata;
+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
+	    return -EFAULT;
+	pc_debug = edata.data;
+	return 0;
+    }
+#endif
+    /* restart autonegotiation */
+    case ETHTOOL_NWAY_RST: {
+	if (smc->cfg & CFG_MII_SELECT)
+	    return mii_nway_restart(&smc->mii_if);
+	else
+	    return -EOPNOTSUPP;
+    }
+    
+    default:
+	break;
+    }
+
+    return -EOPNOTSUPP;
+}
+
+static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    struct smc_private *smc = dev->priv;
+    struct mii_ioctl_data *mii;
+    int rc = 0;
+
+    mii = (struct mii_ioctl_data *) &rq->ifr_data;
+    if (!netif_running(dev))
+    	return -EINVAL;
+
+    switch (cmd) {
+    case SIOCETHTOOL:
+	rc = smc_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	break;
+    
+    default:
+	spin_lock_irq(&smc->lock);
+	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
+	spin_unlock_irq(&smc->lock);
+	break;
+    }
+
+    return rc;
+}
+
+
 /*====================================================================*/
 
 static int __init init_smc91c92_cs(void)
@@ -2069,3 +2271,4 @@
 
 module_init(init_smc91c92_cs);
 module_exit(exit_smc91c92_cs);
+
diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c
--- a/drivers/net/pppoe.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/net/pppoe.c	Fri Oct 11 21:23:00 2002
@@ -403,7 +403,7 @@
         bh_lock_sock(sk);
 
 	/* Socket state is unknown, must put skb into backlog. */
-	if (sk->lock.users != 0) {
+	if (sock_owned_by_user(sk) != 0) {
 		sk_add_backlog(sk, skb);
 		ret = NET_RX_SUCCESS;
 	} else {
@@ -444,7 +444,7 @@
 		 * one socket family type, we cannot (easily) distinguish
 		 * what kind of SKB it is during backlog rcv.
 		 */
-		if (sk->lock.users == 0) {
+		if (sock_owned_by_user(sk) == 0) {
 			sk->state = PPPOX_ZOMBIE;
 			pppox_unbind_sock(sk);
 		}
diff -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
--- a/drivers/net/sgiseeq.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/net/sgiseeq.c	Fri Oct 11 21:23:04 2002
@@ -615,7 +615,7 @@
 	int i;
 	struct sgiseeq_private *sp;
 
-	dev->priv = (struct sgiseeq_private *) get_free_page(GFP_KERNEL);
+	dev->priv = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL);
 	if (dev->priv == NULL)
 		return -ENOMEM;
 
diff -Nru a/drivers/net/tc35815.c b/drivers/net/tc35815.c
--- a/drivers/net/tc35815.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/net/tc35815.c	Fri Oct 11 21:22:50 2002
@@ -640,7 +640,7 @@
 		if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
 			return -ENOMEM;
 		for (i = 0; i < RX_BUF_PAGES; i++) {
-			if ((lp->data_buf[i] = (void *)get_free_page(GFP_KERNEL)) == 0) {
+			if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) {
 				while (--i >= 0) {
 					free_page((unsigned long)lp->data_buf[i]);
 					lp->data_buf[i] = 0;
diff -Nru a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
--- a/drivers/net/tokenring/ibmtr.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/net/tokenring/ibmtr.c	Fri Oct 11 21:23:00 2002
@@ -243,7 +243,7 @@
 static void __devinit find_turbo_adapters(int *iolist) {
 	int ram_addr;
 	int index=0;
-	__u32 chanid;
+	void *chanid;
 	int found_turbo=0;
 	unsigned char *tchanid, ctemp;
 	int i,j;
@@ -300,7 +300,7 @@
 		printk("ibmtr::find_turbo_adapters, ibmtr card found at"
 			" %x but not a Turbo model\n",ram_addr);
 #endif
-	iounmap(ram_addr) ; 	
+	iounmap(ram_mapped) ; 	
 	} /* for */
 	for(i=0; i<IBMTR_MAX_ADAPTERS; i++) {
 		if(!turbo_io[i]) break;
diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
--- a/drivers/net/tokenring/olympic.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/net/tokenring/olympic.c	Fri Oct 11 21:23:02 2002
@@ -56,8 +56,15 @@
  * 07/19/01 - Improve bad LAA reporting, strip out freemem
  *	      into a separate function, its called from 3 
  *	      different places now. 
- * 02/09/01 - Replaced sleep_on. 
- *
+ * 02/09/02 - Replaced sleep_on. 
+ * 03/01/02 - Replace access to several registers from 32 bit to 
+ * 	      16 bit. Fixes alignment errors on PPC 64 bit machines.
+ * 	      Thanks to Al Trautman for this one.
+ * 03/10/02 - Fix BUG in arb_cmd. Bug was there all along but was
+ * 	      silently ignored until the error checking code 
+ * 	      went into version 1.0.0 
+ * 06/04/02 - Add correct start up sequence for the cardbus adapters.
+ * 	      Required for strict compliance with pci power mgmt specs.
  *  To Do:
  *
  *	     Wake on lan	
@@ -111,7 +118,7 @@
  */
 
 static char version[] __devinitdata = 
-"Olympic.c v1.0.0 2/9/02  - Peter De Schrijver & Mike Phillips" ; 
+"Olympic.c v1.0.5 6/04/02 - Peter De Schrijver & Mike Phillips" ; 
 
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
 				   "Address Verification", "Neighbor Notification (Ring Poll)",
@@ -296,9 +303,10 @@
 	spin_lock_init(&olympic_priv->olympic_lock) ; 
 
 	/* Needed for cardbus */
-	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR))
+	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) {
 		writel(readl(olympic_priv->olympic_mmio+FERMASK)|FERMASK_INT_BIT, olympic_mmio+FERMASK);
-
+	}
+	
 #if OLYMPIC_DEBUG
 	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
 	printk("GPR: %x\n",readw(olympic_mmio+GPR));
@@ -311,24 +319,42 @@
 	writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL);
 	
 	if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
-		writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
+		writew(readw(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",olympic_priv->olympic_card_name);
 	} else if (olympic_priv->olympic_ring_speed == 16) {
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", olympic_priv->olympic_card_name);
-		writel(GPR_16MBPS, olympic_mmio+GPR);
+		writew(GPR_16MBPS, olympic_mmio+GPR);
 	} else if (olympic_priv->olympic_ring_speed == 4) {
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", olympic_priv->olympic_card_name) ; 
-		writel(0, olympic_mmio+GPR);
+		writew(0, olympic_mmio+GPR);
 	} 
 	
-	writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
+	writew(readw(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
 
 #if OLYMPIC_DEBUG
 	printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; 
 #endif
+	/* Solo has been paused to meet the Cardbus power
+	 * specs if the adapter is cardbus. Check to 
+	 * see its been paused and then restart solo. The
+	 * adapter should set the pause bit within 1 second.
+	 */
+
+	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { 
+		t=jiffies;
+		while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { 
+			schedule() ; 
+			if(jiffies-t > 2*HZ) { 
+				printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; 
+				return -ENODEV;
+			}
+		}
+		writel(readl(olympic_mmio+CLKCTL) & ~CLKCTL_PAUSE, olympic_mmio+CLKCTL) ; 
+	}
+	
 	/* start solo init */
 	writel((1<<15),olympic_mmio+SISR_MASK_SUM);
 
@@ -341,13 +367,13 @@
 		}
 	}
 	
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
 
 #if OLYMPIC_DEBUG
 	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
 #endif
 
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800));
 
 #if OLYMPIC_DEBUG		
 {
@@ -422,11 +448,11 @@
 
 	/* adapter is closed, so SRB is pointed to by LAPWWO */
 
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800));
 	
 #if OLYMPIC_DEBUG
-	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+	printk("LAPWWO: %x, LAPA: %x\n",readw(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
 	printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
 	printk("Before the open command \n");
 #endif	
@@ -486,7 +512,7 @@
             			olympic_priv->srb_queued=0;
             			break;
         		}
-			if ((jiffies-t) > 60*HZ) { 
+			if ((jiffies-t) > 10*HZ) { 
 				printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; 
 				olympic_priv->srb_queued=0;
 				break ; 
@@ -495,7 +521,7 @@
     		}
 		remove_wait_queue(&olympic_priv->srb_wait,&wait) ; 
 		set_current_state(TASK_RUNNING) ; 
-
+		olympic_priv->srb_queued = 0 ; 
 #if OLYMPIC_DEBUG
 		printk("init_srb(%p): ",init_srb);
 		for(i=0;i<20;i++)
@@ -629,7 +655,8 @@
 	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
 
 	printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]);
-	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = %08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
+	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr =
+%08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
 #endif
 
 	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
@@ -790,7 +817,7 @@
 			   	   	   first. Ideally all frames would be in a single buffer, this can be tuned by
                                	   	   altering the buffer size. If the length of the packet is less than
 					   1500 bytes we're going to copy it over anyway to stop packets getting
-					   dropped from sockets with buffers small than our pkt_buf_sz. */
+					   dropped from sockets with buffers smaller than our pkt_buf_sz. */
 				
  					if (buffer_cnt==1) {
 						olympic_priv->rx_ring_last_received++ ; 
@@ -1097,10 +1124,13 @@
 	writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
 
 #if OLYMPIC_DEBUG
+	{
+	int i ; 
 	printk("srb(%p): ",srb);
 	for(i=0;i<4;i++)
 		printk("%x ",readb(srb+i));
 	printk("\n");
+	}
 #endif
 	free_irq(dev->irq,dev);
 
@@ -1369,8 +1399,7 @@
 	arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
 	asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
 	srb = (u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
-	writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
-
+	
 	if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
 
 		header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */	
@@ -1423,7 +1452,7 @@
 		/* Now tell the card we have dealt with the received frame */
 
 		/* Set LISR Bit 1 */
-		writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM);
+		writel(LISR_ARB_FREE,olympic_priv->olympic_mmio + LISR_SUM);
 
 		/* Is the ASB free ? */ 	
 		
diff -Nru a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h
--- a/drivers/net/tokenring/olympic.h	Fri Oct 11 21:23:05 2002
+++ b/drivers/net/tokenring/olympic.h	Fri Oct 11 21:23:05 2002
@@ -91,6 +91,7 @@
 #define TIMER 0x50
 
 #define CLKCTL 0x74
+#define CLKCTL_PAUSE (1<<15) 
 
 #define PM_CON 0x4
 
diff -Nru a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
--- a/drivers/net/wan/cycx_drv.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/net/wan/cycx_drv.c	Fri Oct 11 21:23:00 2002
@@ -423,9 +423,9 @@
 
 	/* Verify firmware module format version */
 	if (cfm->version != CFM_VERSION) {
-		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware format %u rejected! "
+		printk(KERN_ERR "%s:%s: firmware format %u rejected! "
 				"Expecting %u.\n",
-				modname, cfm->version, CFM_VERSION);
+				modname, __FUNCTION__, cfm->version, CFM_VERSION);
 		return -EINVAL;
 	}
 
@@ -437,8 +437,8 @@
 	if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
 */
 	if (cksum != cfm->checksum) {
-		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware corrupted!\n",
-				modname);
+		printk(KERN_ERR "%s:%s: firmware corrupted!\n",
+				modname, __FUNCTION__);
 		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
 				len - sizeof(cfm_t) - 1, cfm->info.codesize);
                 printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
@@ -450,7 +450,7 @@
 
 	img_hdr = (cycx_header_t*)(((u8*)cfm) + sizeof(cfm_t) - 1);
 #ifdef FIRMWARE_DEBUG
-	printk(KERN_INFO "%s:" __FUNCTION__ ": image sizes\n", modname);
+	printk(KERN_INFO "%s:%s: image sizes\n", __FUNCTION__, modname);
 	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
 	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
 	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
diff -Nru a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
--- a/drivers/net/wan/cycx_x25.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/net/wan/cycx_x25.c	Fri Oct 11 21:22:54 2002
@@ -1446,7 +1446,7 @@
         unsigned char *ptr;
 
         if ((skb = dev_alloc_skb(1)) == NULL) {
-                printk(KERN_ERR __FUNCTION__ ": out of memory\n");
+                printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
                 return;
         }
 
diff -Nru a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c
--- a/drivers/net/wan/lmc/lmc_debug.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/net/wan/lmc/lmc_debug.c	Fri Oct 11 21:22:55 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 -Nru a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
--- a/drivers/net/wan/z85230.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/net/wan/z85230.c	Fri Oct 11 21:22:51 2002
@@ -889,12 +889,12 @@
 	if(c->mtu  > PAGE_SIZE/2)
 		return -EMSGSIZE;
 	 
-	c->rx_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
+	c->rx_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
 	if(c->rx_buf[0]==NULL)
 		return -ENOBUFS;
 	c->rx_buf[1]=c->rx_buf[0]+PAGE_SIZE/2;
 	
-	c->tx_dma_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
+	c->tx_dma_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
 	if(c->tx_dma_buf[0]==NULL)
 	{
 		free_page((unsigned long)c->rx_buf[0]);
@@ -1079,7 +1079,7 @@
 	if(c->mtu  > PAGE_SIZE/2)
 		return -EMSGSIZE;
 	 
-	c->tx_dma_buf[0]=(void *)get_free_page(GFP_KERNEL|GFP_DMA);
+	c->tx_dma_buf[0]=(void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
 	if(c->tx_dma_buf[0]==NULL)
 		return -ENOBUFS;
 
diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
--- a/drivers/net/wireless/orinoco_cs.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/net/wireless/orinoco_cs.c	Fri Oct 11 21:23:03 2002
@@ -32,7 +32,6 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/tqueue.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
diff -Nru a/drivers/pci/gen-devlist.c b/drivers/pci/gen-devlist.c
--- a/drivers/pci/gen-devlist.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/pci/gen-devlist.c	Fri Oct 11 21:22:58 2002
@@ -1,7 +1,7 @@
 /*
  *	Generate devlist.h and classlist.h from the PCI ID file.
  *
- *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ *	(c) 1999--2002 Martin Mares <mj@ucw.cz>
  */
 
 #include <stdio.h>
@@ -15,8 +15,13 @@
 	while (*c) {
 		if (*c == '"')
 			fprintf(f, "\\\"");
-		else
+		else {
 			fputc(*c, f);
+			if (*c == '?' && c[1] == '?') {
+				/* Avoid trigraphs */
+				fprintf(f, "\" \"");
+			}
+		}
 		c++;
 	}
 }
diff -Nru a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
--- a/drivers/pcmcia/i82365.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/pcmcia/i82365.c	Fri Oct 11 21:23:03 2002
@@ -1631,7 +1631,7 @@
 #endif
     unregister_ss_entry(&pcic_operations);
     if (poll_interval != 0)
-	del_timer(&poll_timer);
+	del_timer_sync(&poll_timer);
 #ifdef CONFIG_ISA
     if (grab_irq != 0)
 	free_irq(cs_irq, pcic_interrupt);
diff -Nru a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
--- a/drivers/pcmcia/tcic.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/pcmcia/tcic.c	Fri Oct 11 21:22:59 2002
@@ -516,17 +516,12 @@
 
 static void __exit exit_tcic(void)
 {
-    u_long flags;
     unregister_ss_entry(&tcic_operations);
-    save_flags(flags);
-    cli();
+    del_timer_sync(&poll_timer);
     if (cs_irq != 0) {
 	tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
 	free_irq(cs_irq, tcic_interrupt);
     }
-    if (tcic_timer_pending)
-	del_timer(&poll_timer);
-    restore_flags(flags);
     release_region(tcic_base, 16);
 } /* exit_tcic */
 
diff -Nru a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
--- a/drivers/pcmcia/yenta.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/pcmcia/yenta.c	Fri Oct 11 21:23:00 2002
@@ -583,7 +583,7 @@
 	pci_socket_t * socket = (pci_socket_t *) data;
 
 	/* It's OK to overwrite this now */
-	INIT_WORK(&socket->tq_task, yenta_bh, NULL);
+	INIT_WORK(&socket->tq_task, yenta_bh, socket);
 
 	if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->name, socket)) {
 		/* No IRQ or request_irq failed. Poll */
diff -Nru a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
--- a/drivers/pnp/isapnp.c	Fri Oct 11 21:22:59 2002
+++ b/drivers/pnp/isapnp.c	Fri Oct 11 21:22:59 2002
@@ -28,6 +28,8 @@
  *  2001-11-07  Added isapnp_{,un}register_driver calls along the lines
  *              of the pci driver interface
  *              Kai Germaschewski <kai.germaschewski@gmx.de>
+ *  2002-06-06  Made the use of dma channel 0 configurable 
+ *              Gerald Teschl <gerald.teschl@univie.ac.at>
  */
 
 #include <linux/config.h>
@@ -56,13 +58,10 @@
 #define ISAPNP_DEBUG
 #endif
 
-struct resource *pidxr_res;
-struct resource *pnpwrp_res;
-struct resource *isapnp_rdp_res;
-
 int isapnp_disable;			/* Disable ISA PnP */
 int isapnp_rdp;				/* Read Data Port */
 int isapnp_reset = 1;			/* reset all PnP cards (deactivate) */
+int isapnp_allow_dma0 = -1;		/* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */
 int isapnp_skip_pci_scan;		/* skip PCI resource scanning */
 int isapnp_verbose = 1;			/* verbose mode */
 int isapnp_reserve_irq[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
@@ -78,6 +77,8 @@
 MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
 MODULE_PARM(isapnp_reset, "i");
 MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
+MODULE_PARM(isapnp_allow_dma0, "i");
+MODULE_PARM_DESC(isapnp_allow_dma0, "Allow dma value 0 during auto activation");
 MODULE_PARM(isapnp_skip_pci_scan, "i");
 MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning");
 MODULE_PARM(isapnp_verbose, "i");
@@ -1762,13 +1763,14 @@
 
 static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx)
 {
-	int i;
+	int i, mindma =1;
 	struct pci_dev *dev;
 
 	/* Some machines allow DMA 0, but others don't. In fact on some 
 	   boxes DMA 0 is the memory refresh. Play safe */
-	   
-	if (dma < 1 || dma == 4 || dma > 7)
+	if (isapnp_allow_dma0 == 1)
+		mindma = 0;
+	if (dma < mindma || dma == 4 || dma > 7)
 		return 1;
 	for (i = 0; i < 8; i++) {
 		if (isapnp_reserve_dma[i] == dma)
@@ -2150,19 +2152,13 @@
 	kfree(card);
 }
 
-#endif /* MODULE */
-
 static void isapnp_free_all_resources(void)
 {
 #ifdef ISAPNP_REGION_OK
-	if (pidxr_res)
-		release_resource(pidxr_res);
+	release_region(_PIDXR, 1);
 #endif
-	if (pnpwrp_res)
-		release_resource(pnpwrp_res);
-	if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff && isapnp_rdp_res)
-		release_resource(isapnp_rdp_res);
-#ifdef MODULE
+	release_region(_PNPWRP, 1);
+	release_region(isapnp_rdp, 1);
 #ifdef CONFIG_PROC_FS
 	isapnp_proc_done();
 #endif
@@ -2171,9 +2167,10 @@
 		list_del(list);
 		isapnp_free_card(pci_bus_b(list));
 	}
-#endif
 }
 
+#endif /* MODULE */
+
 static int isapnp_announce_device(struct isapnp_driver *drv, 
 				  struct pci_dev *dev)
 {
@@ -2290,6 +2287,8 @@
 	struct pci_bus *card;
 	struct pci_dev *parent = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
 
+	INIT_LIST_HEAD(&isapnp_device_driver.devices);
+
 	isapnp_for_each_card(card) {
 		struct list_head *devlist;
 
@@ -2327,14 +2326,12 @@
 		return 0;
 	}
 #ifdef ISAPNP_REGION_OK
-	pidxr_res=request_region(_PIDXR, 1, "isapnp index");
-	if(!pidxr_res) {
+	if (!request_region(_PIDXR, 1, "isapnp index")) {
 		printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR);
 		return -EBUSY;
 	}
 #endif
-	pnpwrp_res=request_region(_PNPWRP, 1, "isapnp write");
-	if(!pnpwrp_res) {
+	if (!request_region(_PNPWRP, 1, "isapnp write")) {
 		printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
 #ifdef ISAPNP_REGION_OK
 		release_region(_PIDXR, 1);
@@ -2350,13 +2347,12 @@
 	printk(KERN_INFO "isapnp: Scanning for PnP cards...\n");
 	if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
 		isapnp_rdp |= 3;
-		isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
-		if(!isapnp_rdp_res) {
+		if (!request_region(isapnp_rdp, 1, "isapnp read")) {
 			printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);
 #ifdef ISAPNP_REGION_OK
 			release_region(_PIDXR, 1);
 #endif
-			release_region(isapnp_rdp, 1);
+			release_region(_PNPWRP, 1);
 			return -EBUSY;
 		}
 		isapnp_set_rdp();
@@ -2366,12 +2362,15 @@
 		cards = isapnp_isolate();
 		if (cards < 0 || 
 		    (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
-			isapnp_free_all_resources();
+#ifdef ISAPNP_REGION_OK
+			release_region(_PIDXR, 1);
+#endif
+			release_region(_PNPWRP, 1);
 			isapnp_detected = 0;
 			printk(KERN_INFO "isapnp: No Plug & Play device found\n");
 			return 0;
 		}
-		isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
+		request_region(isapnp_rdp, 1, "isapnp read");
 	}
 	isapnp_build_device_list();
 	cards = 0;
diff -Nru a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c
--- a/drivers/pnp/isapnp_proc.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/pnp/isapnp_proc.c	Fri Oct 11 21:22:55 2002
@@ -950,6 +950,22 @@
 	res->start = res->end = dma;
 	res->flags = IORESOURCE_DMA;
 }
+
+extern int isapnp_allow_dma0;
+static int isapnp_set_allow_dma0(char *line)
+{
+	int i;
+	char value[32];
+
+	isapnp_get_str(value, line, sizeof(value));
+	i = simple_strtoul(value, NULL, 0);
+	if (i < 0 || i > 1) {
+		printk("isapnp: wrong value %i for allow_dma0\n", i);
+		return 1;
+	}
+	isapnp_allow_dma0 = i;
+	return 0;
+}
  
 static int isapnp_set_dma(char *line)
 {
@@ -1036,6 +1052,8 @@
 	char cmd[32];
 
 	line = isapnp_get_str(cmd, line, sizeof(cmd));
+	if (!strcmp(cmd, "allow_dma0"))
+		return isapnp_set_allow_dma0(line);
 	if (!strcmp(cmd, "card"))
 		return isapnp_set_card(line);
 	if (!strcmp(cmd, "csn"))
diff -Nru a/drivers/pnp/pnpbios_proc.c b/drivers/pnp/pnpbios_proc.c
--- a/drivers/pnp/pnpbios_proc.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/pnp/pnpbios_proc.c	Fri Oct 11 21:23:04 2002
@@ -218,7 +218,7 @@
 	create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
 	create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
 	create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
-	create_proc_read_entry("escd", 0, proc_pnp, proc_read_escd, NULL);
+	create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
 	create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
 	
 	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
diff -Nru a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
--- a/drivers/pnp/quirks.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/pnp/quirks.c	Fri Oct 11 21:23:03 2002
@@ -102,6 +102,28 @@
 	return;
 }
 
+extern int isapnp_allow_dma0;
+static void __init quirk_opl3sax_resources(struct pci_dev *dev)
+{
+	/* This really isn't a device quirk but isapnp core code
+	 * doesn't allow a DMA channel of 0, afflicted card is an
+	 * OPL3Sax where x=4.
+	 */
+	struct isapnp_resources *res;
+	int max;
+	res = (struct isapnp_resources *)dev->sysdata;
+	max = res->dma->map;
+	for (res = res->alt; res; res = res->alt) {
+		if (res->dma->map > max)
+			max = res->dma->map;
+	}
+	if (max == 1 && isapnp_allow_dma0 == -1) {
+		printk(KERN_INFO "isapnp: opl3sa4 quirk: Allowing dma 0.\n");
+		isapnp_allow_dma0 = 1;
+	}
+	return;
+}
+
 /*
  *  ISAPnP Quirks
  *  Cards or devices that need some tweaking due to broken hardware
@@ -133,6 +155,8 @@
 		quirk_sb16audio_resources },
 	{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0045),
 		quirk_sb16audio_resources },
+	{ ISAPNP_VENDOR('Y','M','H'), ISAPNP_DEVICE(0x0021),
+		quirk_opl3sax_resources },
 	{ 0 }
 };
 
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/s390/block/dasd.c	Fri Oct 11 21:22:57 2002
@@ -93,6 +93,7 @@
 static void dasd_int_handler(int, void *, struct pt_regs *);
 static void dasd_flush_ccw_queue(dasd_device_t *, int);
 static void dasd_tasklet(dasd_device_t *);
+static void do_kick_device(void *data);
 
 /*
  * Parameter parsing functions. There are two for the dasd driver:
@@ -228,7 +229,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 	/* Get one page for error recovery. */
-	device->erp_mem = (void *) get_free_page(GFP_ATOMIC | GFP_DMA);
+	device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA);
 	if (device->erp_mem == NULL) {
 		free_pages((unsigned long) device->ccw_mem, 1);
 		kfree(device);
@@ -254,6 +255,7 @@
 		     (unsigned long) device);
 	INIT_LIST_HEAD(&device->ccw_queue);
 	init_timer(&device->timer);
+	INIT_WORK(&device->kick_work, do_kick_device, (void *) (addr_t) device->devinfo.devno);
 	device->state = DASD_STATE_NEW;
 	device->target = DASD_STATE_NEW;
 
@@ -590,11 +592,13 @@
  * event daemon.
  */
 static void
-do_kick_device(int devno)
+do_kick_device(void *data)
 {
+	int devno;
 	dasd_devmap_t *devmap;
 	dasd_device_t *device;
 
+	devno = (long) data;
 	devmap = dasd_devmap_from_devno(devno);
 	device = (devmap != NULL) ?
 		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
@@ -610,10 +614,8 @@
 dasd_kick_device(dasd_device_t *device)
 {
 	atomic_inc(&device->ref_count);
-	device->kick_tq.routine = (void *) do_kick_device;
-	device->kick_tq.data = (void *) (addr_t) device->devinfo.devno;
 	/* queue call to dasd_kick_device to the kernel event daemon. */
-	schedule_task(&device->kick_tq);
+	schedule_work(&device->kick_work);
 }
 
 /*
@@ -784,7 +786,7 @@
 do_not_oper_handler(void *data)
 {
 	struct {
-		struct tq_struct tq;
+		struct work_struct work;
 		int irq;
 	} *p;
 	dasd_device_t *device;
@@ -815,7 +817,7 @@
 dasd_not_oper_handler(int irq, int status)
 {
 	struct {
-		struct tq_struct tq;
+		struct work_struct work;
 		int irq;
 	} *p;
 
@@ -823,11 +825,10 @@
 	if (p == NULL)
 		/* FIXME: No memory, we loose. */
 		return;
-	p->tq.routine = (void *) do_not_oper_handler;
-	p->tq.data = (void *) p;
+	INIT_WORK(&p->work, (void *) do_not_oper_handler, p);
 	p->irq = irq;
 	/* queue call to do_not_oper_handler to the kernel event daemon. */
-	schedule_task(&p->tq);
+	schedule_work(&p->work);
 }
 
 /*
@@ -837,7 +838,7 @@
 do_oper_handler(void *data)
 {
 	struct {
-		struct tq_struct tq;
+		struct work_struct work;
 		int devno;
 	} *p;
 	dasd_devmap_t *devmap;
@@ -868,7 +869,7 @@
 dasd_oper_handler(int irq, devreg_t * devreg)
 {
 	struct {
-		struct tq_struct tq;
+		struct work_struct work;
 		int devno;
 	} *p;
 
@@ -879,10 +880,9 @@
 	p->devno = get_devno_by_irq(irq);
 	if (p->devno == -ENODEV)
 		return -ENODEV;
-	p->tq.routine = (void *) do_oper_handler;
-	p->tq.data = (void *) p;
+	INIT_WORK(&p->work, (void *) do_oper_handler, p);
 	/* queue call to do_oper_handler to the kernel event daemon. */
-	schedule_task(&p->tq);
+	schedule_work(&p->work);
         return 0;
 
 }
@@ -1317,7 +1317,7 @@
 do_state_change_pending(void *data)
 {
 	struct {
-		struct tq_struct tq;
+		struct work_struct work;
 		unsigned short devno;
 	} *p;
 	dasd_devmap_t *devmap;
@@ -1355,7 +1355,7 @@
 dasd_handle_state_change_pending(devstat_t * stat)
 {
 	struct {
-		struct tq_struct tq;
+		struct work_struct work;
 		unsigned short devno;
 	} *p;
 
@@ -1363,11 +1363,10 @@
 	if (p == NULL)
 		/* No memory, let the timeout do the reactivation. */
 		return;
-	p->tq.routine = (void *) do_state_change_pending;
-	p->tq.data = (void *) p;
+	INIT_WORK(&p->work, (void *) do_state_change_pending, p);
 	p->devno = stat->devno;
 	/* queue call to do_state_change_pending to the kernel event daemon. */
-	schedule_task(&p->tq);
+	schedule_work(&p->work);
 }
 
 /*
diff -Nru a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
--- a/drivers/s390/block/dasd_diag.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/s390/block/dasd_diag.c	Fri Oct 11 21:22:51 2002
@@ -274,7 +274,7 @@
 	mdsk_term_io(device);
 
 	/* figure out blocksize of device */
-	label = (long *) get_free_page(GFP_KERNEL);
+	label = (long *) get_zeroed_page(GFP_KERNEL);
 	if (label == NULL)  {
 		MESSAGE(KERN_WARNING, "%s",
 			"No memory to allocate initialization request");
@@ -437,7 +437,7 @@
 {
 	char *page;
 
-	page = (char *) get_free_page(GFP_KERNEL);
+	page = (char *) get_zeroed_page(GFP_KERNEL);
 	if (page == NULL) {
 		MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
 		return;
diff -Nru a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
--- a/drivers/s390/block/dasd_eckd.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/s390/block/dasd_eckd.c	Fri Oct 11 21:22:50 2002
@@ -1344,7 +1344,7 @@
 	ccw1_t *act;
 	int len, sl, sct;
 
-	page = (char *) get_free_page(GFP_ATOMIC);
+	page = (char *) get_zeroed_page(GFP_ATOMIC);
 	if (page == NULL) {
 		MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
 		return;
diff -Nru a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
--- a/drivers/s390/block/dasd_fba.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/s390/block/dasd_fba.c	Fri Oct 11 21:23:00 2002
@@ -363,7 +363,7 @@
 {
 	char *page;
 
-	page = (char *) get_free_page(GFP_KERNEL);
+	page = (char *) get_zeroed_page(GFP_KERNEL);
 	if (page == NULL) {
 		MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
 		return;
diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
--- a/drivers/s390/block/dasd_genhd.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/s390/block/dasd_genhd.c	Fri Oct 11 21:23:02 2002
@@ -195,7 +195,6 @@
 		return ERR_PTR(-ENOMEM);
 
 	/* Initialize gendisk structure. */
-	memset(gdp, 0, sizeof(struct gendisk));
 	gdp->major = mi->major;
 	gdp->first_minor = index << DASD_PARTN_BITS;
 	gdp->minor_shift = DASD_PARTN_BITS;
diff -Nru a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
--- a/drivers/s390/block/dasd_int.h	Fri Oct 11 21:23:02 2002
+++ b/drivers/s390/block/dasd_int.h	Fri Oct 11 21:23:02 2002
@@ -58,6 +58,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <asm/debug.h>
 #include <asm/dasd.h>
 #include <asm/idals.h>
@@ -292,7 +293,7 @@
 
 	atomic_t tasklet_scheduled;
         struct tasklet_struct tasklet;
-	struct tq_struct kick_tq;
+	struct work_struct kick_work;
 	struct timer_list timer;
 
 	debug_info_t *debug_area;
diff -Nru a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
--- a/drivers/s390/char/con3215.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/s390/char/con3215.c	Fri Oct 11 21:22:54 2002
@@ -89,7 +89,7 @@
         int written;                  /* number of bytes in write requests */
 	devstat_t devstat;	      /* device status structure for do_IO */
 	struct tty_struct *tty;	      /* pointer to tty structure if present */
-	struct work_struct tqueue;      /* task queue to bottom half */
+	struct tasklet_struct tasklet;
 	raw3215_req *queued_read;     /* pointer to queued read requests */
 	raw3215_req *queued_write;    /* pointer to queued write requests */
 	wait_queue_head_t empty_wait; /* wait queue for flushing */
@@ -351,7 +351,7 @@
 	s390irq_spin_lock_irqsave(raw->irq, flags);
         raw3215_mk_write_req(raw);
         raw3215_try_io(raw);
-        raw->flags &= ~RAW3215_BH_PENDING;
+	raw->flags &= ~RAW3215_BH_PENDING;
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
 	/* Check for pending message from raw3215_irq */
 	if (raw->message != NULL) {
@@ -369,16 +369,13 @@
 }
 
 /*
- * Function to safely add raw3215_softint to tq_immediate.
- * The s390irq spinlock must be held.
  */
-static inline void raw3215_sched_bh(raw3215_info *raw)
+static inline void raw3215_sched_tasklet(raw3215_info *raw)
 {
-        if (raw->flags & RAW3215_BH_PENDING)
-                return;       /* already pending */
-        raw->flags |= RAW3215_BH_PENDING;
-	INIT_WORK(&raw->tqueue, raw3215_softint, raw);
-        schedule_work(&raw->tqueue);
+	if (raw->flags & RAW3215_BH_PENDING)
+		return;		/* already pending */
+	raw->flags |= RAW3215_BH_PENDING;
+	tasklet_hi_schedule(&raw->tasklet);
 }
 
 /*
@@ -421,7 +418,7 @@
 				"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
 			raw->msg_dstat = dstat;
 			raw->msg_cstat = cstat;
-                        raw3215_sched_bh(raw);
+			raw3215_sched_tasklet(raw);
 		}
 	}
         if (dstat & 0x01) { /* we got a unit exception */
@@ -438,7 +435,7 @@
 		raw3215_mk_read_req(raw);
                 if (MACHINE_IS_P390)
                         memset(raw->inbuf, 0, RAW3215_INBUF_SIZE);
-                raw3215_sched_bh(raw);
+ 		raw3215_sched_tasklet(raw);
 		break;
 	case 0x08:
 	case 0x0C:
@@ -512,7 +509,7 @@
 		    raw->queued_read == NULL) {
 			wake_up_interruptible(&raw->empty_wait);
 		}
-                raw3215_sched_bh(raw);
+ 		raw3215_sched_tasklet(raw);
 		break;
 	default:
 		/* Strange interrupt, I'll do my best to clean up */
@@ -532,7 +529,7 @@
 			"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
 		raw->msg_dstat = dstat;
 		raw->msg_cstat = cstat;
-                raw3215_sched_bh(raw);
+ 		raw3215_sched_tasklet(raw);
 	}
 	return;
 }
@@ -868,7 +865,6 @@
 			kfree(raw);
 			return -ENOMEM;
 		}
-		INIT_WORK(&raw->tqueue, raw3215_softint, raw);
                 init_waitqueue_head(&raw->empty_wait);
 		raw3215[line] = raw;
 	}
@@ -1110,7 +1106,9 @@
 	/* Find the first console */
 	raw->irq = irq;
 	raw->flags |= RAW3215_FIXED;
-	INIT_WORK(&raw->tqueue, raw3215_softint, raw);
+	tasklet_init(&raw->tasklet, 
+		     (void (*)(unsigned long)) raw3215_tasklet,
+		     (unsigned long) raw);
         init_waitqueue_head(&raw->empty_wait);
 
 	/* Request the console irq */
diff -Nru a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c
--- a/drivers/s390/char/ctrlchar.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/s390/char/ctrlchar.c	Fri Oct 11 21:23:05 2002
@@ -23,10 +23,7 @@
 	handle_sysrq(ctrlchar_sysrq_key, NULL, tty);
 }
 
-static struct tq_struct ctrlchar_tq = {
-	.list = LIST_HEAD_INIT(ctrlchar_tq.list),
-	.routine = ctrlchar_handle_sysrq,
-};
+static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, 0);
 #endif
 
 
@@ -56,8 +53,8 @@
 	/* racy */
 	if (len == 3 && buf[1] == '-') {
 		ctrlchar_sysrq_key = buf[2];
-		ctrlchar_tq.data = tty;
-		schedule_task(&ctrlchar_tq);
+		ctrlchar_work.data = tty;
+		schedule_work(&ctrlchar_work);
 		return CTRLCHAR_SYSRQ;
 	}
 #endif
diff -Nru a/drivers/s390/char/tuball.c b/drivers/s390/char/tuball.c
--- a/drivers/s390/char/tuball.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/s390/char/tuball.c	Fri Oct 11 21:22:55 2002
@@ -228,6 +228,16 @@
 	MOD_DEC_USE_COUNT;
 }
 
+static int
+tub3270_is_ours(s390_dev_info_t *dp)
+{
+	if ((dp->sid_data.cu_type & 0xfff0) == 0x3270)
+		return 1;
+	if (dp->sid_data.cu_type == 0x3174)
+		return 1;
+	return 0;
+}
+
 /*
  * tub3270_init() called by kernel or module initialization
  */
@@ -283,7 +293,7 @@
 		}
 #endif /* LINUX_VERSION_CODE */
 #endif /* CONFIG_TN3270_CONSOLE */
-		if ((d.sid_data.cu_type & 0xfff0) != 0x3270)
+		if (!tub3270_is_ours(&d))
 			continue;
 
 		rc = tubmakemin(i, &d);
@@ -498,6 +508,10 @@
 			tty3270_rcl_fini(tubp);
 			kfree(tubp->tty_bcb.bc_buf);
 			tubp->tty_bcb.bc_buf = NULL;
+			if (tubp->tty_input) {
+				kfree(tubp->tty_input);
+				tubp->tty_input = NULL;
+			}
 			tubp->ttyscreen = NULL;
 			kfree(tubp);
 			*tubpp = NULL;
diff -Nru a/drivers/s390/char/tubfs.c b/drivers/s390/char/tubfs.c
--- a/drivers/s390/char/tubfs.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/s390/char/tubfs.c	Fri Oct 11 21:23:00 2002
@@ -226,19 +226,25 @@
 }
 
 /*
- * fs3270_bh(tubp) -- Perform back-half processing
+ * fs3270_tasklet(tubp) -- Perform back-half processing
  */
 static void
 fs3270_tasklet(unsigned long data)
 {
 	long flags;
 	tub_t *tubp;
+	addr_t *ip;
 
 	tubp = (tub_t *) data;
 	TUBLOCK(tubp->irq, flags);
 	tubp->flags &= ~TUB_BHPENDING;
 
 	if (tubp->wbuf) {       /* if we were writing */
+		for (ip = tubp->wbuf; ip < tubp->wbuf+33; ip++) {
+			if (*ip == 0)
+				break;
+			kfree(phys_to_virt(*ip));
+		}
 		kfree(tubp->wbuf);
 		tubp->wbuf = NULL;
 	}
@@ -256,17 +262,18 @@
 }
 
 /*
- * fs3270_sched_bh(tubp) -- Schedule the back half
+ * fs3270_sched_tasklet(tubp) -- Schedule the back half
  * Irq lock must be held on entry and remains held on exit.
  */
 static void
-fs3270_sched_bh(tub_t *tubp)
+fs3270_sched_tasklet(tub_t *tubp)
 {
 	if (tubp->flags & TUB_BHPENDING)
 		return;
 	tubp->flags |= TUB_BHPENDING;
-	INIT_WORK(&tubp->tqueue, fs3270_bh, tubp);
-	schedule_work(&tubp->tqueue);
+	tasklet_init(&tubp->tasklet, fs3270_tasklet,
+		     (unsigned long) tubp);
+	tasklet_schedule(&tubp->tasklet);
 }
 
 /*
@@ -279,8 +286,6 @@
 #define	DEV_UE_BUSY \
 	(DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
 
-	tubp->dstat = dsp->dstat;
-
 #ifdef RBHNOTYET
 	/* XXX needs more work; must save 2d arg to fs370_io() */
 	/* Handle CE-DE-UE and subsequent UDE */
@@ -316,7 +321,7 @@
 		tubp->flags &= ~TUB_WORKING;
 
 	if ((tubp->flags & TUB_WORKING) == 0)
-		fs3270_sched_bh(tubp);
+		fs3270_sched_tasklet(tubp);
 }
 
 /*
@@ -363,47 +368,78 @@
 	ccw1_t *cp;
 	int rc;
 	long flags;
+	addr_t *idalp, *ip;
+	char *tp;
+	int count, piece;
+	int size;
+
+	if (len == 0 || len > 65535) {
+		return -EINVAL;
+	}
 
 	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
 		return -ENODEV;
-	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
-		TUBUNLOCK(tubp->irq, flags);
-		return rc;
+
+	ip = idalp = kmalloc(33*sizeof(addr_t), GFP_ATOMIC|GFP_DMA);
+	if (idalp == NULL)
+		return -EFAULT;
+	memset(idalp, 0, 33 * sizeof *idalp);
+	count = len;
+	while (count) {
+		piece = MIN(count, 0x800);
+		size = count == len? piece: 0x800;
+		if ((kp = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
+			len = -ENOMEM;
+			goto do_cleanup;
+		}
+		*ip++ = virt_to_phys(kp);
+		count -= piece;
 	}
 
-	kp = kmalloc(len, GFP_KERNEL|GFP_DMA);
-	if (kp == NULL) {
+	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
 		TUBUNLOCK(tubp->irq, flags);
-		return -ENOMEM;
+		len = rc;
+		goto do_cleanup;
 	}
-
 	cp = &tubp->rccw;
 	if (tubp->icmd == 0 && tubp->ocmd != 0)  tubp->icmd = 6;
 	cp->cmd_code = tubp->icmd?:2;
-	cp->flags = CCW_FLAG_SLI;
+	cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
 	cp->count = len;
-	cp->cda = virt_to_phys(kp);
+	cp->cda = virt_to_phys(idalp);
 	tubp->flags |= TUB_RDPENDING;
 	TUBUNLOCK(tubp->irq, flags);
 
 	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
 		tubp->flags &= ~TUB_RDPENDING;
+		len = rc;
 		TUBUNLOCK(tubp->irq, flags);
-		kfree(kp);
-		return rc;
+		goto do_cleanup;
 	}
+	TUBUNLOCK(tubp->irq, flags);
 
 	len -= tubp->cswl;
-	TUBUNLOCK(tubp->irq, flags);
-	if (tubdebug & 1)
-		printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n",
-			tubp->minor,
-			*(int*)((long)kp + 0),
-			*(int*)((long)kp + 4),
-			*(int*)((long)kp + 8),
-			*(int*)((long)kp + 12));
-	copy_to_user(dp, kp, len);
-	kfree(kp);
+	count = len;
+	tp = dp;
+	ip = idalp;
+	while (count) {
+		piece = MIN(count, 0x800);
+		if (copy_to_user(tp, phys_to_virt(*ip), piece) != 0) {
+			len = -EFAULT;
+			goto do_cleanup;
+		}
+		count -= piece;
+		tp += piece;
+		ip++;
+	}
+
+do_cleanup:
+	for (ip = idalp; ip < idalp+33; ip++) {
+		if (*ip == 0)
+			break;
+		kfree(phys_to_virt(*ip));
+	}
+	kfree(idalp);
 	return len;
 }
 
@@ -418,34 +454,65 @@
 	int rc;
 	long flags;
 	void *kb;
+	addr_t *idalp, *ip;
+	int count, piece;
+	int index;
+	int size;
+
+	if (len > 65535 || len == 0)
+		return -EINVAL;
 
 	/* Locate the tube */
 	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
 		return -ENODEV;
 
-	/* Copy data to write from user address space */
-	if ((kb = kmalloc(len, GFP_KERNEL|GFP_DMA)) == NULL)
-		return -ENOMEM;
-	if (copy_from_user(kb, dp, len) != 0) {
-		kfree(kb);
+	ip = idalp = kmalloc(33*sizeof(addr_t), GFP_ATOMIC|GFP_DMA);
+	if (idalp == NULL)
 		return -EFAULT;
+	memset(idalp, 0, 33 * sizeof *idalp);
+
+	count = len;
+	index = 0;
+	while (count) {
+		piece = MIN(count, 0x800);
+		size = count == len? piece: 0x800;
+		if ((kb = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
+			len = -ENOMEM;
+			goto do_cleanup;
+		}
+		*ip++ = virt_to_phys(kb);
+		if (copy_from_user(kb, &dp[index], piece) != 0) {
+			len = -EFAULT;
+			goto do_cleanup;
+		}
+		count -= piece;
+		index += piece;
 	}
 
 	/* Wait till tube's not working or signal is pending */
 	if ((rc = fs3270_wait(tubp, &flags))) {
+		len = rc;
 		TUBUNLOCK(tubp->irq, flags);
-		kfree(kb);
-		return rc;
+		goto do_cleanup;
 	}
 
-	/* Make CCW and start I/O.  Back end will free buffer. */
-	tubp->wbuf = kb;
+	/* Make CCW and start I/O.  Back end will free buffers & idal. */
+	tubp->wbuf = idalp;
 	cp = &tubp->wccw;
 	cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1;
-	cp->flags = CCW_FLAG_SLI;
+	cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
 	cp->count = len;
 	cp->cda = virt_to_phys(tubp->wbuf);
 	fs3270_io(tubp, cp);
 	TUBUNLOCK(tubp->irq, flags);
+	return len;
+
+do_cleanup:
+	for (ip = idalp; ip < idalp+33; ip++) {
+		if (*ip == 0)
+			break;
+		kfree(phys_to_virt(*ip));
+	}
+	kfree(idalp);
 	return len;
 }
diff -Nru a/drivers/s390/char/tubio.h b/drivers/s390/char/tubio.h
--- a/drivers/s390/char/tubio.h	Fri Oct 11 21:22:50 2002
+++ b/drivers/s390/char/tubio.h	Fri Oct 11 21:22:50 2002
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/idals.h>
 #include <linux/console.h>
 #include <linux/interrupt.h>
 #include <asm/ebcdic.h>
@@ -81,10 +82,17 @@
 #define TAT_CHARS 0x43
 #define TAT_TRANS 0x46
 
+/* Extended-Highlighting Bytes */
+#define TAX_RESET 0x00
+#define TAX_BLINK 0xf1
+#define TAX_REVER 0xf2
+#define TAX_UNDER 0xf4
+
 /* Reset value */
 #define TAR_RESET 0x00
 
 /* Color values */
+#define TAC_RESET 0x00
 #define TAC_BLUE 0xf1
 #define TAC_RED 0xf2
 #define TAC_PINK 0xf3
@@ -220,7 +228,7 @@
 	devstat_t       devstat;
 	ccw1_t          rccw;
 	ccw1_t          wccw;
-	void            *wbuf;
+	addr_t		*wbuf;
 	int             cswl;
 	void            (*intv)(struct tub_s *, devstat_t *);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
@@ -242,12 +250,13 @@
 
 	/* Stuff for tty-driver support */
 	struct tty_struct *tty;
-	char tty_input[GEOM_MAXINPLEN]; /* tty input area */
+	char *tty_input;		/* tty input area */
 	int tty_inattr;         	/* input-area field attribute */
 #define TTY_OUTPUT_SIZE 1024
 	bcb_t tty_bcb;			/* Output buffer control info */
 	int tty_oucol;                  /* Kludge */
 	int tty_nextlogx;               /* next screen-log position */
+	int tty_savecursor;		/* saved cursor position */
 	int tty_scrolltime;             /* scrollforward wait time, sec */
 	struct timer_list tty_stimer;   /* timer for scrolltime */
 	aid_t tty_aid[64];              /* Aid descriptors */
diff -Nru a/drivers/s390/char/tubtty.c b/drivers/s390/char/tubtty.c
--- a/drivers/s390/char/tubtty.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/s390/char/tubtty.c	Fri Oct 11 21:23:03 2002
@@ -216,8 +216,10 @@
 	tubp->tty = tty;
 	tubp->lnopen = 1;
 	tty->driver_data = tubp;
-	tty->winsize.ws_row = tubp->geom_rows;
+	tty->winsize.ws_row = tubp->geom_rows - 2;
 	tty->winsize.ws_col = tubp->geom_cols;
+	if (tubp->tty_input == NULL)
+		tubp->tty_input = kmalloc(GEOM_INPLEN, GFP_KERNEL|GFP_DMA);
 	tubp->tty_inattr = TF_INPUT;
 	tubp->cmd = cmd;
 	tty3270_build(tubp);
@@ -801,7 +803,9 @@
 static void
 tty3270_start_input(tub_t *tubp)
 {
-	tubp->ttyccw.cda = virt_to_phys(&tubp->tty_input);
+	if (tubp->tty_input == NULL)
+		return;
+	tubp->ttyccw.cda = virt_to_phys(tubp->tty_input);
 	tubp->ttyccw.cmd_code = TC_READMOD;
 	tubp->ttyccw.count = GEOM_INPLEN;
 	tubp->ttyccw.flags = CCW_FLAG_SLI;
@@ -818,7 +822,8 @@
 	char *aidstring;
 
 	count = GEOM_INPLEN - tubp->cswl;
-	in = tubp->tty_input;
+	if ((in = tubp->tty_input) == NULL)
+		goto do_build;
 	tty3270_aid_get(tubp, in[0], &aidflags, &aidstring);
 
 	if (aidflags & TA_CLEARKEY) {
diff -Nru a/drivers/s390/char/tubttybld.c b/drivers/s390/char/tubttybld.c
--- a/drivers/s390/char/tubttybld.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/s390/char/tubttybld.c	Fri Oct 11 21:22:55 2002
@@ -15,10 +15,12 @@
 extern int tty3270_io(tub_t *);
 static void tty3270_set_status_area(tub_t *, char **);
 static int tty3270_next_char(tub_t *);
+static void tty3270_unnext_char(tub_t *, char);
 static void tty3270_update_log_area(tub_t *, char **);
-static void tty3270_update_log_area_esc(tub_t *, char **);
+static int tty3270_update_log_area_esc(tub_t *, char **, int *);
 static void tty3270_clear_log_area(tub_t *, char **);
 static void tty3270_tub_bufadr(tub_t *, int, char **);
+static void tty3270_set_bufadr(tub_t *, char **, int *);
 
 /*
  * tty3270_clear_log_area(tub_t *tubp, char **cpp)
@@ -47,69 +49,73 @@
 	int sba_needed = 1;
 	char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
 
-	/* Place characters */
-	while (tubp->tty_bcb.bc_cnt != 0) {
-		if (tubp->tty_nextlogx >= lastx) {
-			if (sba_needed == 0 || tubp->stat == TBS_RUNNING) {
-				tubp->stat = TBS_MORE;
-				tty3270_set_status_area(tubp, cpp);
-				tty3270_scl_settimer(tubp);
-			}
-			break;
+	/* Check for possible ESC sequence work to do */
+	if (tubp->tty_escx != 0) {
+		/* If compiling new escape sequence */
+		if (tubp->tty_esca[0] == 0x1b) {
+			if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
+				return;
+		/* If esc seq needs refreshing after a write */
+		} else if (tubp->tty_esca[0] == TO_SA) {
+			tty3270_set_bufadr(tubp, cpp, &sba_needed);
+			for (i = 0; i < tubp->tty_escx; i++)
+				*(*cpp)++ = tubp->tty_esca[i];
+		} else {
+			printk(KERN_WARNING "tty3270_update_log_area esca "
+			"character surprising:  %.2x\n", tubp->tty_esca[0]);
 		}
+	}
 
-		/* Check for room for another char + possible ESCs */
-		if (&(*cpp)[tubp->tty_escx + 1] >= overrun)
+	/* Place characters */
+	while (tubp->tty_bcb.bc_cnt != 0) {
+		/* Check for room.  TAB could take up to 4 chars. */
+		if (&(*cpp)[4] >= overrun)
 			break;
 
 		/* Fetch a character */
 		if ((c = tty3270_next_char(tubp)) == -1)
 			break;
 
-		/* Add a Set-Buffer-Address Order if we haven't */
-		if (sba_needed) {
-			sba_needed = 0;
-			*(*cpp)++ = TO_SBA;
-			TUB_BUFADR(tubp->tty_nextlogx, cpp);
-		}
-
 		switch(c) {
 		default:
-			if (c < ' ')    /* Blank it if we don't know it */
-				c = ' ';
-			for (i = 0; i < tubp->tty_escx; i++)
-				*(*cpp)++ = tubp->tty_esca[i];
-			tubp->tty_escx = 0;
-			*(*cpp)++ = tub_ascebc[(int)c];
+			if (tubp->tty_nextlogx >= lastx) {
+				if (sba_needed == 0 ||
+				    tubp->stat == TBS_RUNNING) {
+					tty3270_unnext_char(tubp, c);
+					tubp->stat = TBS_MORE;
+					tty3270_set_status_area(tubp, cpp);
+					tty3270_scl_settimer(tubp);
+				}
+				goto do_return;
+			}
+			tty3270_set_bufadr(tubp, cpp, &sba_needed);
+			/* Use blank if we don't know the character */
+			*(*cpp)++ = tub_ascebc[(int)(c < ' '? ' ': c)];
 			tubp->tty_nextlogx++;
 			tubp->tty_oucol++;
 			break;
 		case 0x1b:              /* ESC */
-			tty3270_update_log_area_esc(tubp, cpp);
+			tubp->tty_escx = 0;
+			if (tty3270_update_log_area_esc(tubp, cpp, &sba_needed))
+				return;
+			break;
+		case '\r':		/* 0x0d -- Carriage Return */
+			tubp->tty_nextlogx -=
+				tubp->tty_nextlogx % GEOM_COLS;
+			sba_needed = 1;
 			break;
-		case '\r':
-			break;          /* completely ignore 0x0d = CR. */
-		case '\n':
+		case '\n':		/* 0x0a -- New Line */
 			if (tubp->tty_oucol == GEOM_COLS) {
 				tubp->tty_oucol = 0;
 				break;
 			}
 			next = (tubp->tty_nextlogx + GEOM_COLS) /
 				GEOM_COLS * GEOM_COLS;
-			next = MIN(next, lastx);
-			fill = next - tubp->tty_nextlogx;
-			if (fill < 5) {
-				for (i = 0; i < fill; i++)
-					*(*cpp)++ = tub_ascebc[' '];
-			} else {
-				*(*cpp)++ = TO_RA;
-				TUB_BUFADR(next, cpp);
-				*(*cpp)++ = tub_ascebc[' '];
-			}
 			tubp->tty_nextlogx = next;
 			tubp->tty_oucol = 0;
+			sba_needed = 1;
 			break;
-		case '\t':
+		case '\t':		/* 0x09 -- Tabulate */
 			fill = (tubp->tty_nextlogx % GEOM_COLS) % 8;
 			for (; fill < 8; fill++) {
 				if (tubp->tty_nextlogx >= lastx)
@@ -119,72 +125,116 @@
 				tubp->tty_oucol++;
 			}
 			break;
-		case '\a':
+		case '\a':		/* 0x07 -- Alarm */
 			tubp->flags |= TUB_ALARM;
 			break;
-		case '\f':
+		case '\f':		/* 0x0c -- Form Feed */
 			tty3270_clear_log_area(tubp, cpp);
 			break;
+		case 0xf:	/* SuSE "exit alternate mode" */
+			break;
 		}
 	}
+do_return:
 }
 
 #define NUMQUANT 8
-static void
-tty3270_update_log_area_esc(tub_t *tubp, char **cpp)
+static int
+tty3270_update_log_area_esc(tub_t *tubp, char **cpp, int *sba_needed)
 {
-	int lastx = GEOM_INPUT;
 	int c;
-	int i;
-	int start, next, fill;
+	int i, j;
+	int start, end, next;
 	int quant[NUMQUANT];
+	char *overrun = &(*tubp->ttyscreen)[tubp->ttyscreenl - TS_LENGTH];
+	char sabuf[NUMQUANT*3], *sap = sabuf, *cp;
 
-	if ((c = tty3270_next_char(tubp)) != '[') {
-		return;
+	/* If starting a sequence, stuff ESC at [0] */
+	if (tubp->tty_escx == 0)
+		tubp->tty_esca[tubp->tty_escx++] = 0x1b;
+
+	/* Now that sequence is started, see if room in buffer */
+	if (&(*cpp)[NUMQUANT * 3] >= overrun)
+		return tubp->tty_escx;
+
+	/* Gather the rest of the sequence's characters */
+	while (tubp->tty_escx < sizeof tubp->tty_esca) {
+		if ((c = tty3270_next_char(tubp)) == -1)
+			return tubp->tty_escx;
+		if (tubp->tty_escx == 1) {
+			switch(c) {
+			case '[':
+				tubp->tty_esca[tubp->tty_escx++] = c;
+				continue;
+			case '7':
+				tubp->tty_savecursor = tubp->tty_nextlogx;
+				goto done_return;
+			case '8':
+				next = tubp->tty_savecursor;
+				goto do_setcur;
+			default:
+				goto error_return;
+			}
+		}
+		tubp->tty_esca[tubp->tty_escx++] = c;
+		if (c != ';' && (c < '0' || c > '9'))
+			break;
 	}
 
-	/*
-	 * Parse potentially empty string "nn;nn;nn..."
-	 */
+	/* Check for overrun */
+	if (tubp->tty_escx == sizeof tubp->tty_esca)
+		goto error_return;
+
+	/* Parse potentially empty string "nn;nn;nn..." */
 	i = -1;
+	j = 2;		/* skip ESC, [ */
 	c = ';';
 	do {
 		if (c == ';') {
 			if (++i == NUMQUANT)
-				break;
+				goto error_return;
 			quant[i] = 0;
 		} else if (c < '0' || c > '9') {
 			break;
 		} else {
 			quant[i] = quant[i] * 10 + c - '0';
 		}
-	} while ((c = tty3270_next_char(tubp)) != -1);
-	if (c == -1) {
-		return;
-	}
-	if (i >= NUMQUANT) {
-		return;
-	}
+		c = tubp->tty_esca[j];
+	} while (j++ < tubp->tty_escx);
+
+	/* Add 3270 data stream output to execute the sequence */
 	switch(c) {
-	case -1:
-		return;
 	case 'm':		/* Set Attribute */
 		for (next = 0; next <= i; next++) {
 			int type = -1, value = 0;
 
-			if (tubp->tty_escx + 3 > MAX_TTY_ESCA)
-				break;
 			switch(quant[next]) {
 			case 0:		/* Reset */
-				tubp->tty_esca[tubp->tty_escx++] = TO_SA;
-				tubp->tty_esca[tubp->tty_escx++] = TAT_RESET;
-				tubp->tty_esca[tubp->tty_escx++] = TAR_RESET;
+				next = tubp->tty_nextlogx;
+				tty3270_set_bufadr(tubp, cpp, sba_needed);
+				*(*cpp)++ = TO_SA;
+				*(*cpp)++ = TAT_EXTHI;
+				*(*cpp)++ = TAX_RESET;
+				*(*cpp)++ = TO_SA;
+				*(*cpp)++ = TAT_COLOR;
+				*(*cpp)++ = TAC_RESET;
+				tubp->tty_nextlogx = next;
+				*sba_needed = 1;
+				sap = sabuf;
 				break;
 			case 1:		/* Bright */
+				break;
 			case 2:		/* Dim */
+				break;
 			case 4:		/* Underscore */
+				type = TAT_EXTHI; value = TAX_UNDER;
+				break;
 			case 5:		/* Blink */
+				type = TAT_EXTHI; value = TAX_BLINK;
+				break;
 			case 7:		/* Reverse */
+				type = TAT_EXTHI; value = TAX_REVER;
+				break;
 			case 8:		/* Hidden */
 				break;		/* For now ... */
 			/* Foreground Colors */
@@ -230,53 +280,110 @@
 				break;
 			}
 			if (type != -1) {
-				tubp->tty_esca[tubp->tty_escx++] = TO_SA;
-				tubp->tty_esca[tubp->tty_escx++] = type;
-				tubp->tty_esca[tubp->tty_escx++] = value;
+				tty3270_set_bufadr(tubp, cpp, sba_needed);
+				*(*cpp)++ = TO_SA;
+				*(*cpp)++ = type;
+				*(*cpp)++ = value;
+				*sap++ = TO_SA;
+				*sap++ = type;
+				*sap++ = value;
 			}
 		}
 		break;
+
 	case 'H':		/* Cursor Home */
 	case 'f':		/* Force Cursor Position */
-		return;
+		if (quant[0]) quant[0]--;
+		if (quant[1]) quant[1]--;
+		next = quant[0] * GEOM_COLS + quant[1];
+		goto do_setcur;
 	case 'A':		/* Cursor Up */
-		return;
+		if (quant[i] == 0) quant[i] = 1;
+		next = tubp->tty_nextlogx - GEOM_COLS * quant[i];
+		goto do_setcur;
 	case 'B':		/* Cursor Down */
-		return;
+		if (quant[i] == 0) quant[i] = 1;
+		next = tubp->tty_nextlogx + GEOM_COLS * quant[i];
+		goto do_setcur;
 	case 'C':		/* Cursor Forward */
+		if (quant[i] == 0) quant[i] = 1;
 		next = tubp->tty_nextlogx % GEOM_COLS;
 		start = tubp->tty_nextlogx - next;
 		next = start + MIN(next + quant[i], GEOM_COLS - 1);
-		next = MIN(next, lastx);
-do_fill:
-		fill = next - tubp->tty_nextlogx;
-		if (fill < 5) {
-			for (i = 0; i < fill; i++)
-				*(*cpp)++ = tub_ascebc[' '];
-		} else {
-			*(*cpp)++ = TO_RA;
-			TUB_BUFADR(next, cpp);
-			*(*cpp)++ = tub_ascebc[' '];
-		}
-		tubp->tty_nextlogx = next;
-		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
-		break;
+		goto do_setcur;
 	case 'D':		/* Cursor Backward */
+		if (quant[i] == 0) quant[i] = 1;
 		next = MIN(quant[i], tubp->tty_nextlogx % GEOM_COLS);
-		tubp->tty_nextlogx -= next;
+		next = tubp->tty_nextlogx - next;
+		goto do_setcur;
+	case 'G':
+		if (quant[0]) quant[0]--;
+		next = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS + quant[0];
+do_setcur:
+		if (next < 0)
+			break;
+		tubp->tty_nextlogx = next;
 		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+		*sba_needed = 1;
+		break;
+
+	case 'r':		/* Define scroll area */
+		start = quant[0];
+		if (start <= 0) start = 1;
+		if (start > GEOM_ROWS - 2) start = GEOM_ROWS - 2;
+		tubp->tty_nextlogx = (start - 1) * GEOM_COLS;
+		tubp->tty_oucol = 0;
+		*sba_needed = 1;
+		break;
+
+	case 'X':		/* Erase for n chars from cursor */
+		start = tubp->tty_nextlogx;
+		end = start + (quant[0]?: 1);
+		goto do_fill;
+	case 'J':		/* Erase to screen end from cursor */
+		*(*cpp)++ = TO_SBA;
+		TUB_BUFADR(tubp->tty_nextlogx, cpp);
+		*(*cpp)++ = TO_RA;
+		TUB_BUFADR(GEOM_INPUT, cpp);
+		*(*cpp)++ = tub_ascebc[' '];
 		*(*cpp)++ = TO_SBA;
 		TUB_BUFADR(tubp->tty_nextlogx, cpp);
 		break;
-	case 'G':
-		start = tubp->tty_nextlogx / GEOM_COLS * GEOM_COLS;
-		next = MIN(quant[i], GEOM_COLS - 1) + start;
-		next = MIN(next, lastx);
-		goto do_fill;
+	case 'K':
+		start = tubp->tty_nextlogx;
+		end = (start + GEOM_COLS) / GEOM_COLS * GEOM_COLS;
+do_fill:
+		if (start >= GEOM_INPUT)
+			break;
+		if (end > GEOM_INPUT)
+			end = GEOM_INPUT;
+		if (end <= start)
+			break;
+		*(*cpp)++ = TO_SBA;
+		TUB_BUFADR(start, cpp);
+		if (end - start > 4) {
+			*(*cpp)++ = TO_RA;
+			TUB_BUFADR(end, cpp);
+			*(*cpp)++ = tub_ascebc[' '];
+		} else while (start++ < end) {
+			*(*cpp)++ = tub_ascebc[' '];
+		}
+		tubp->tty_nextlogx = end;
+		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+		*sba_needed = 1;
+		break;
 	}
+done_return:
+	tubp->tty_escx = 0;
+	cp = sabuf;
+	while (cp != sap)
+		tubp->tty_esca[tubp->tty_escx++] = *cp++;
+	return 0;
+error_return:
+	tubp->tty_escx = 0;
+	return 0;
 }
 
-
 static int
 tty3270_next_char(tub_t *tubp)
 {
@@ -293,6 +400,18 @@
 	return c;
 }
 
+static void
+tty3270_unnext_char(tub_t *tubp, char c)
+{
+	bcb_t *ib;
+
+	ib = &tubp->tty_bcb;
+	if (ib->bc_rd == 0)
+		ib->bc_rd = ib->bc_len;
+	ib->bc_buf[--ib->bc_rd] = c;
+	ib->bc_cnt++;
+}
+
 
 static void
 tty3270_clear_input_area(tub_t *tubp, char **cpp)
@@ -451,4 +570,18 @@
 		*(*cpp)++ = tub_ebcgraf[(adr >> 6) & 0x3f];
 		*(*cpp)++ = tub_ebcgraf[adr & 0x3f];
 	}
+}
+
+static void
+tty3270_set_bufadr(tub_t *tubp, char **cpp, int *sba_needed)
+{
+	if (!*sba_needed)
+		return;
+	if (tubp->tty_nextlogx >= GEOM_INPUT) {
+		tubp->tty_nextlogx = GEOM_INPUT - 1;
+		tubp->tty_oucol = tubp->tty_nextlogx % GEOM_COLS;
+	}
+	*(*cpp)++ = TO_SBA;
+	TUB_BUFADR(tubp->tty_nextlogx, cpp);
+	*sba_needed = 0;
 }
diff -Nru a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
--- a/drivers/s390/cio/cio.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/s390/cio/cio.c	Fri Oct 11 21:23:05 2002
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.26 $
+ *   $Revision: 1.27 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                            IBM Corporation
@@ -27,6 +27,7 @@
 #include "cio.h"
 #include "cio_debug.h"
 #include "ioinfo.h"
+#include "chsc.h"
 #include "s390io.h" /* FIXME: try to do without this */
 
 static atomic_t sync_isc = ATOMIC_INIT (-1);
diff -Nru a/drivers/s390/misc/chandev.c b/drivers/s390/misc/chandev.c
--- a/drivers/s390/misc/chandev.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/s390/misc/chandev.c	Fri Oct 11 21:22:55 2002
@@ -24,7 +24,7 @@
 #include <asm/s390dyn.h>
 #include <asm/queue.h>
 #include <linux/kmod.h>
-#include <linux/tqueue.h>
+#include <linux/workqueue.h>
 #ifndef MIN
 #define MIN(a,b) ((a<b)?a:b)
 #endif
@@ -190,8 +190,8 @@
 
 static unsigned long chandev_last_machine_check;
 
-
-static struct tq_struct chandev_msck_task_tq;
+static void chandev_msck_task(void *unused);
+static DECLARE_WORK(chandev_msck_work, chandev_msck_task, 0);
 static atomic_t chandev_msck_thread_lock;
 static atomic_t chandev_new_msck;
 static unsigned long chandev_last_startmsck_list_update;
@@ -666,7 +666,7 @@
 	chandev_last_machine_check=jiffies;
 	if(atomic_dec_and_test(&chandev_msck_thread_lock))
 	{
-		schedule_task(&chandev_msck_task_tq);
+		schedule_work(&chandev_msck_work);
 	}
 	atomic_set(&chandev_new_msck,TRUE);
 	return(0);
@@ -686,7 +686,7 @@
 		spin_unlock(&chandev_not_oper_spinlock);
 		if(atomic_dec_and_test(&chandev_msck_thread_lock))
 		{
-			schedule_task(&chandev_msck_task_tq);
+			schedule_work(&chandev_msck_work);
 		}
 	}
 	else
@@ -3208,13 +3208,6 @@
 #if CONFIG_PROC_FS
 	chandev_create_proc();
 #endif
-	chandev_msck_task_tq.routine=
-		chandev_msck_task;
-#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-	INIT_LIST_HEAD(&chandev_msck_task_tq.list);
-	chandev_msck_task_tq.sync=0;
-#endif
-	chandev_msck_task_tq.data=NULL;
 	chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
 	atomic_set(&chandev_msck_thread_lock,1);
 	chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
diff -Nru a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
--- a/drivers/s390/net/ctcmain.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/s390/net/ctcmain.c	Fri Oct 11 21:22:55 2002
@@ -49,7 +49,6 @@
 #include <linux/interrupt.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
-#include <linux/tqueue.h>
 
 #include <linux/signal.h>
 #include <linux/string.h>
@@ -234,11 +233,6 @@
 	devstat_t           *devstat;
 
 	/**
-	 * Bottom half task queue.
-	 */
-	struct tq_struct    tq;
-
-	/**
 	 * RX/TX buffer size
 	 */
 	int                 max_bufsize;
@@ -797,19 +791,6 @@
 }
 
 /**
- * Bottom half routine.
- *
- * @param ch The channel to work on.
- */
-static void ctc_bh(channel *ch)
-{
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&ch->io_queue)))
-		ctc_unpack_skb(ch, skb);
-}
-
-/**
  * Check return code of a preceeding do_IO, halt_IO etc...
  *
  * @param ch          The channel, the error belongs to.
@@ -1328,11 +1309,6 @@
 		       "allocation until first transfer\n",
 		       dev->name, 
 		       (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
-
-	INIT_LIST_HEAD(&ch->tq.list);
-	ch->tq.sync    = 0;
-	ch->tq.routine = (void *)(void *)ctc_bh;
-	ch->tq.data    = ch;
 
 	ch->ccw[0].cmd_code = CCW_CMD_PREPARE;
 	ch->ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
diff -Nru a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c
--- a/drivers/s390/net/fsm.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/s390/net/fsm.c	Fri Oct 11 21:22:58 2002
@@ -9,6 +9,7 @@
 #include <linux/version.h>
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/timer.h>
 
 fsm_instance *
 init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
@@ -172,19 +173,6 @@
 	       this->fi->name, this, millisec);
 #endif
 
-#if LINUX_VERSION_CODE >= 0x020300
-	if (this->tl.list.next || this->tl.list.prev) {
-		printk(KERN_WARNING "fsm(%s): timer already active!\n",
-			this->fi->name);
-		return -1;
-	}
-#else
-	if (this->tl.next || this->tl.prev) {
-		printk(KERN_WARNING "fsm(%s): timer already active!\n",
-			this->fi->name);
-		return -1;
-	}
-#endif
 	init_timer(&this->tl);
 	this->tl.function = (void *)fsm_expire_timer;
 	this->tl.data = (long)this;
@@ -205,13 +193,7 @@
 		this->fi->name, this, millisec);
 #endif
 
-#if LINUX_VERSION_CODE >= 0x020300
-	if (this->tl.list.next || this->tl.list.prev)
-		del_timer(&this->tl);
-#else
-	if (this->tl.next || this->tl.prev)
-		del_timer(&this->tl);
-#endif
+	del_timer(&this->tl);
 	init_timer(&this->tl);
 	this->tl.function = (void *)fsm_expire_timer;
 	this->tl.data = (long)this;
diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
--- a/drivers/s390/net/lcs.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/s390/net/lcs.c	Fri Oct 11 21:22:53 2002
@@ -461,7 +461,7 @@
 int                  lock_owner;            \
 int                  lock_cnt;              \
 wait_queue_head_t    wait;                  \
-struct  tq_struct    retry_task;            \
+struct work_struct   retry_task;            \
 devstat_t	     devstat;               \
 lcs_chan_busy_state  chan_busy_state;       \
 ccw1_t               ccw[num_io_buffs+1];   \
@@ -491,7 +491,7 @@
 	u32 tx_idx;		/* last buffer successfully transmitted */
 	unsigned long pkts_still_being_txed;
 	unsigned long bytes_still_being_txed;
-	struct tq_struct resume_task;
+	struct work_struct resume_task;
 	int resume_queued;
 	int resume_loopcnt;
 	uint64_t last_lcs_txpacket_time;
@@ -542,7 +542,7 @@
 	/* To insure only one kernel thread runs at a time */
 	atomic_t kernel_thread_lock;
 	int (*kernel_thread_routine) (lcs_drvr_globals * drvr_globals);
-	struct tq_struct kernel_thread_task;
+	struct work_struct kernel_thread_task;
 	u16 lgw_sequence_no;	/* this isn't required just being thorough */
 	atomic_t retry_cnt;
 	struct net_device_stats stats __attribute__ ((aligned(4)));
@@ -1024,7 +1024,9 @@
 	lcs_write_globals *write;
 	lcs_read_globals *read;
 	int cnt;
+#if LINUX_VERSION_CODE<KERNEL_VERSION(2,5,41)
 	struct tq_struct *lcs_tq;
+#endif
 
 	lcs_debug_event(2, "lcs_alloc_drvr_globals called\n");
 	drvr_globals = lcs_dma_alloc(LCS_ALLOCSIZE);
@@ -1058,6 +1060,15 @@
 	read->drvr_globals = drvr_globals;
 	write->drvr_globals = drvr_globals;
 	lcs_resetstate(drvr_globals);
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,41)
+	INIT_WORK(&drvr_globals->kernel_thread_task, lcs_kernel_thread,
+		  (unsigned long) drvr_globals);
+	INIT_WORK(&read->retry_task, lcs_queued_restartreadio, 
+		  (unsigned long) drvr_globals);
+	INIT_WORK(&write->retry_task, lcs_queued_restartwriteio,
+		  (unsigned long) drvr_globals);
+	INIT_WORK(&resume_task, lcs_resume_writetask, (unsigned long) write);
+#else
 	lcs_tq = &drvr_globals->kernel_thread_task;
 	lcs_tq->routine = (void (*)(void *)) lcs_kernel_thread;
 	lcs_tq->data = (void *) drvr_globals;
@@ -1075,6 +1086,7 @@
 	write->retry_task.data = read->retry_task.data = (void *) drvr_globals;
 	write->resume_task.routine = (void (*)(void *)) lcs_resume_writetask;
 	write->resume_task.data = (void *) write;
+#endif
 	read->chan_busy_state = write->chan_busy_state = chan_dead;
 	atomic_set(&drvr_globals->kernel_thread_lock, 1);
 	spin_lock(&lcs_card_list_lock);
@@ -1093,11 +1105,15 @@
 	lcs_debug_event(1, "lcs_retry subchannel %04x scheduling retry\n",
 			chan_globals->subchannel);
 	MOD_INC_USE_COUNT;
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,41)
+	schedule_work(&chan_globals->retry_task);
+#else
 #if LINUX_VERSION_CODE>KERNEL_VERSION(2,2,16)
 	schedule_task(&chan_globals->retry_task);
 #else
 	queue_task(&chan_globals->retry_task, &tq_scheduler);
 #endif
+#endif
 }
 
 static int
@@ -1445,7 +1461,11 @@
 	 * needing mod usage counts */
 	lcs_debug_event(2, "lcs_queue_write write=%p\n", write);
 	write->resume_queued = TRUE;
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,41)
+	schedule_work(&write->resume_task);
+#else
 	queue_task(&write->resume_task, &tq_immediate);
+#endif
 	mark_bh(IMMEDIATE_BH);
 }
 
@@ -1631,10 +1651,14 @@
 		netif_stop_queue(drvr_globals->dev);
 		MOD_INC_USE_COUNT;
 		drvr_globals->kernel_thread_routine = routine;
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,5,41)
+		schedule_work(&drvr_globals->kernel_thread_task);
+#else
 #if LINUX_VERSION_CODE<=KERNEL_VERSION(2,2,16)
 		queue_task(&drvr_globals->kernel_thread_task, &tq_scheduler);
 #else
 		schedule_task(&drvr_globals->kernel_thread_task);
+#endif
 #endif
 	} else
 		lcs_debug_event(1,"lcs_queue_thread busy drvr_globals=%p "
diff -Nru a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
--- a/drivers/s390/sysinfo.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/s390/sysinfo.c	Fri Oct 11 21:22:55 2002
@@ -228,7 +228,7 @@
                              off_t off, int count,
                              int *eof, void *data)
 {
-	unsigned long info_page = get_free_page (GFP_KERNEL); 
+	unsigned long info_page = get_zeroed_page (GFP_KERNEL); 
 	union s390_sysinfo *info = (union s390_sysinfo *) info_page;
 	int len = 0;
 	int level;
diff -Nru a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
--- a/drivers/sbus/char/aurora.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/sbus/char/aurora.c	Fri Oct 11 21:22:54 2002
@@ -1194,10 +1194,10 @@
 		return 0;
 		
 	if (!port->xmit_buf) {
-		/* We may sleep in get_free_page() */
+		/* We may sleep in get_zeroed_page() */
 		unsigned long tmp;
 		
-		if (!(tmp = get_free_page(GFP_KERNEL)))
+		if (!(tmp = get_zeroed_page(GFP_KERNEL)))
 			return -ENOMEM;
 		    
 		if (port->xmit_buf) {
@@ -2303,7 +2303,7 @@
 #ifdef AURORA_DEBUG
 	printk("aurora_init_drivers: start\n");
 #endif
-	tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+	tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
 	if (tmp_buf == NULL) {
 		printk(KERN_ERR "aurora: Couldn't get free page.\n");
 		return 1;
diff -Nru a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
--- a/drivers/sbus/char/uctrl.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/sbus/char/uctrl.c	Fri Oct 11 21:23:05 2002
@@ -107,7 +107,7 @@
 	u8 speaker_volume; /* 0x23 */
 	u8 control_tft_brightness; /* 0x24 */
 	u8 control_kbd_repeat_delay; /* 0x28 */
-	u8 control_kbd_repeat_rate; /* 0x29 */
+	u8 control_kbd_repeat_period; /* 0x29 */
 	u8 control_screen_contrast; /* 0x2F */
 };
 
diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
--- a/drivers/scsi/3w-xxxx.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/scsi/3w-xxxx.c	Fri Oct 11 21:23:04 2002
@@ -2102,12 +2102,12 @@
 
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (unsigned long)disk->capacity / (heads * sectors);
 
 	if (disk->capacity >= 0x200000) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (unsigned long)disk->capacity / (heads * sectors);
 	}
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
diff -Nru a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
--- a/drivers/scsi/53c7xx.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/scsi/53c7xx.c	Fri Oct 11 21:23:06 2002
@@ -3034,7 +3034,7 @@
  *
  * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
  *	structures for this device, do so.  Attempt to complete all scheduled
- *	allocations using get_free_page(), putting NCR53c7x0_cmd structures on
+ *	allocations using get_zeroed_page(), putting NCR53c7x0_cmd structures on
  *	the free list.  Teach programmers not to drink and hack.
  *
  * Inputs : cmd - SCSI command
@@ -3101,7 +3101,7 @@
             printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
 	    return NULL;
 	}
-        real = get_free_page(GFP_ATOMIC);
+        real = get_zeroed_page(GFP_ATOMIC);
         if (real == 0)
         	return NULL;
         memset((void *)real, 0, 4096);
diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
--- a/drivers/scsi/BusLogic.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/scsi/BusLogic.c	Fri Oct 11 21:23:04 2002
@@ -4200,7 +4200,7 @@
       DiskParameters->Sectors = 32;
     }
   DiskParameters->Cylinders =
-    Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+    (unsigned long)Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
   buf = scsi_bios_ptable(Device);
   if (buf == NULL) return 0;
   /*
@@ -4244,7 +4244,7 @@
 	  PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F;
 	}
       DiskParameters->Cylinders =
-	Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+	(unsigned long)Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
       if (PartitionNumber < 4 &&
 	  PartitionEntryEndSector == DiskParameters->Sectors)
 	{
diff -Nru a/drivers/scsi/Config.in b/drivers/scsi/Config.in
--- a/drivers/scsi/Config.in	Fri Oct 11 21:22:56 2002
+++ b/drivers/scsi/Config.in	Fri Oct 11 21:22:56 2002
@@ -57,11 +57,6 @@
 source drivers/scsi/aic7xxx/Config.in
 if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then
    dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI
-   if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "n" ]; then
-      bool '  Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
-      int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE 8
-      bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_OLD_PROC_STATS
-   fi
 fi
 # All the I2O code and drivers do not seem to be 64bit safe.
 if [ "$CONFIG_X86_64" != "y" ]; then
diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/Makefile	Fri Oct 11 21:22:55 2002
@@ -137,7 +137,7 @@
 $(obj)/53c7,8xx.o: $(obj)/53c8xx_d.h $(obj)/53c8xx_u.h
 $(obj)/53c7xx.o:   $(obj)/53c7xx_d.h $(obj)/53c7xx_u.h
 $(obj)/sim710.o:   $(obj)/sim710_d.h
-$(obj)/53c700.o $(MODVERDIR)/53c700.ver: $(obj)/53c700_d.h
+$(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h
 
 # If you want to play with the firmware, uncomment
 # GENERATE_FIRMWARE := 1
@@ -162,4 +162,4 @@
 $(obj)/53c700_d.h: $(src)/53c700.scr $(src)/script_asm.pl
 	$(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) < $<
 
-endif
\ No newline at end of file
+endif
diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
--- a/drivers/scsi/NCR53C9x.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/scsi/NCR53C9x.c	Fri Oct 11 21:22:54 2002
@@ -869,17 +869,19 @@
 	for(i = 0; i < 15; i++) {
 		if(esp->targets_present & (1 << i)) {
 			Scsi_Device *SDptr = esp->ehost->host_queue;
+			struct esp_device *esp_dev;
 
 			while((SDptr->host != esp->ehost) &&
 			      (SDptr->id != i) &&
 			      (SDptr->next))
 				SDptr = SDptr->next;
 
+			esp_dev = SDptr->hostdata;
 			copy_info(&info, "%d\t\t", i);
 			copy_info(&info, "%08lx\t", esp->config3[i]);
-			copy_info(&info, "[%02lx,%02lx]\t\t\t", SDptr->sync_max_offset,
-				  SDptr->sync_min_period);
-			copy_info(&info, "%s\n", SDptr->disconnect ? "yes" : "no");
+			copy_info(&info, "[%02lx,%02lx]\t\t\t", esp_dev->sync_max_offset,
+				  esp_dev->sync_min_period);
+			copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no");
 		}
 	}
 
@@ -1012,6 +1014,7 @@
 static void esp_exec_cmd(struct NCR_ESP *esp)
 {
 	struct ESP_regs *eregs = esp->eregs;
+	struct esp_device *esp_dev;
 	Scsi_Cmnd *SCptr;
 	Scsi_Device *SDptr;
 	volatile unchar *cmdp = esp->esp_command;
@@ -1033,9 +1036,29 @@
 		panic("esp: esp_exec_cmd and issue queue is NULL");
 
 	SDptr = SCptr->device;
+	esp_dev = SDptr->hostdata;
 	lun = SCptr->lun;
 	target = SCptr->target;
 
+	/*
+	 * If esp_dev == NULL then we need to allocate a struct for our data
+	 */
+	if (!esp_dev) {
+		esp_dev = kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+		if (!esp_dev) {
+			/* We're SOL.  Print a message and bail */
+			printk(KERN_WARNING "esp: no mem for esp_device %d/%d\n",
+					target, lun);
+			esp->current_SC = NULL;
+			SCptr->result = DID_ERROR << 16;
+			SCptr->done(SCptr);
+			return;
+		}
+		memset(esp_dev, 0, sizeof(struct esp_device));
+		SDptr->hostdata = esp_dev;
+	}
+
+
 	esp->snip = 0;
 	esp->msgout_len = 0;
 
@@ -1071,12 +1094,12 @@
 	 * selections should not confuse SCSI-1 we hope.
 	 */
 
-	if(SDptr->sync) {
+	if(esp_dev->sync) {
 		/* this targets sync is known */
 #ifdef CONFIG_SCSI_MAC_ESP
 do_sync_known:
 #endif
-		if(SDptr->disconnect)
+		if(esp_dev->disconnect)
 			*cmdp++ = IDENTIFY(1, lun);
 		else
 			*cmdp++ = IDENTIFY(0, lun);
@@ -1088,7 +1111,7 @@
 			the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
 			esp_advance_phase(SCptr, in_slct_norm);
 		}
-	} else if(!(esp->targets_present & (1<<target)) || !(SDptr->disconnect)) {
+	} else if(!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) {
 		/* After the bootup SCSI code sends both the
 		 * TEST_UNIT_READY and INQUIRY commands we want
 		 * to at least attempt allowing the device to
@@ -1096,8 +1119,8 @@
 		 */
 		ESPMISC(("esp: Selecting device for first time. target=%d "
 			 "lun=%d\n", target, SCptr->lun));
-		if(!SDptr->borken && !SDptr->disconnect)
-			SDptr->disconnect = 1;
+		if(!SDptr->borken && !esp_dev->disconnect)
+			esp_dev->disconnect = 1;
 
 		*cmdp++ = IDENTIFY(0, lun);
 		esp->prevmsgout = NOP;
@@ -1105,8 +1128,8 @@
 		the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
 
 		/* Take no chances... */
-		SDptr->sync_max_offset = 0;
-		SDptr->sync_min_period = 0;
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
 	} else {
 		int toshiba_cdrom_hwbug_wkaround = 0;
 
@@ -1115,10 +1138,10 @@
 		 * Macintosh. Well, maybe later when we figured out how to 
 		 * do DMA on the machines that support it ...
 		 */
-		SDptr->disconnect = 1;
-		SDptr->sync_max_offset = 0;
-		SDptr->sync_min_period = 0;
-		SDptr->sync = 1;
+		esp_dev->disconnect = 1;
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+		esp_dev->sync = 1;
 		esp->snip = 0;
 		goto do_sync_known;
 #endif
@@ -1140,7 +1163,7 @@
 		} else {
 			build_sync_nego_msg(esp, 0, 0);
 		}
-		SDptr->sync = 1;
+		esp_dev->sync = 1;
 		esp->snip = 1;
 
 		/* A fix for broken SCSI1 targets, when they disconnect
@@ -1170,7 +1193,7 @@
 		   toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
 			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
 				 "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
-			SDptr->disconnect = 0;
+			esp_dev->disconnect = 0;
 			*cmdp++ = IDENTIFY(0, lun);
 		} else {
 			*cmdp++ = IDENTIFY(1, lun);
@@ -1192,13 +1215,13 @@
 			*cmdp++ = SCptr->cmnd[i];
 
 	esp_write(eregs->esp_busid, (target & 7));
-	if (esp->prev_soff != SDptr->sync_max_offset ||
-	    esp->prev_stp  != SDptr->sync_min_period ||
+	if (esp->prev_soff != esp_dev->sync_max_offset ||
+	    esp->prev_stp  != esp_dev->sync_min_period ||
 	    (esp->erev > esp100a &&
 	     esp->prev_cfg3 != esp->config3[target])) {
-		esp->prev_soff = SDptr->sync_max_offset;
+		esp->prev_soff = esp_dev->sync_max_offset;
 		esp_write(eregs->esp_soff, esp->prev_soff);
-		esp->prev_stp = SDptr->sync_min_period;
+		esp->prev_stp = esp_dev->sync_min_period;
 		esp_write(eregs->esp_stp, esp->prev_stp); 
 		if(esp->erev > esp100a) {
 			esp->prev_cfg3 = esp->config3[target];
@@ -1697,14 +1720,15 @@
 			       Scsi_Cmnd *sp)
 {
 	Scsi_Device *dp = sp->device;
+	struct esp_device *esp_dev = dp->hostdata;
 
-	if(esp->prev_soff  != dp->sync_max_offset ||
-	   esp->prev_stp   != dp->sync_min_period ||
+	if(esp->prev_soff  != esp_dev->sync_max_offset ||
+	   esp->prev_stp   != esp_dev->sync_min_period ||
 	   (esp->erev > esp100a &&
 	    esp->prev_cfg3 != esp->config3[sp->target])) {
-		esp->prev_soff = dp->sync_max_offset;
+		esp->prev_soff = esp_dev->sync_max_offset;
 		esp_write(eregs->esp_soff, esp->prev_soff);
-		esp->prev_stp = dp->sync_min_period;
+		esp->prev_stp = esp_dev->sync_min_period;
 		esp_write(eregs->esp_stp, esp->prev_stp);
 		if(esp->erev > esp100a) {
 			esp->prev_cfg3 = esp->config3[sp->target];
@@ -1837,8 +1861,8 @@
 			else
 				ESPDATA(( /*"\n"*/ "\r"));
 #endif
-			save_flags(flags);
 #if 0
+			save_flags(flags);
 			cli();
 #endif
 			if(thisphase == in_datain) {
@@ -1929,7 +1953,9 @@
 			if (hmuch == 0)
 				ESPDATA(("done! \n"));
 
+#if 0
 			restore_flags(flags);
+#endif
 
 			/* check new bus phase */
 			if (newphase != oldphase && i < esp->current_transfer_size) {
@@ -1981,6 +2007,7 @@
 			      struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
 	int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
 
 	if(esp->dma_led_off)
@@ -2031,7 +2058,7 @@
 		 ecount, fifocnt));
 
 	/* If we were in synchronous mode, check for peculiarities. */
-	if(SCptr->device->sync_max_offset)
+	if(esp_dev->sync_max_offset)
 		bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt);
 	else
 		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
@@ -2102,7 +2129,7 @@
 		ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, 
 			SCptr->target));
 		SCptr->device->borken = 1;
-		SCptr->device->sync = 0;
+		esp_dev->sync = 0;
 		bytes_sent = 0;
 	}
 
@@ -2201,6 +2228,7 @@
 	esp->msgout_len = 0;
 	esp->prevmsgout = NOP;
 	if(esp->prevmsgin == COMMAND_COMPLETE) {
+		struct esp_device *esp_dev = SCptr->device->hostdata;
 		/* Normal end of nexus. */
 		if(esp->disconnected_SC)
 			esp_cmd(esp, eregs, ESP_CMD_ESEL);
@@ -2208,8 +2236,7 @@
 		if(SCptr->SCp.Status != GOOD &&
 		   SCptr->SCp.Status != CONDITION_GOOD &&
 		   ((1<<SCptr->target) & esp->targets_present) &&
-		   SCptr->device->sync &&
-		   SCptr->device->sync_max_offset) {
+		   esp_dev->sync && esp_dev->sync_max_offset) {
 			/* SCSI standard says that the synchronous capabilities
 			 * should be renegotiated at this point.  Most likely
 			 * we are about to request sense from this target
@@ -2227,7 +2254,7 @@
 			 * loading up a tape.
 			 */
 			if(esp_should_clear_sync(SCptr) != 0)
-				SCptr->device->sync = 0;
+				esp_dev->sync = 0;
 		}
 		ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
 		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
@@ -2476,7 +2503,7 @@
 					struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *sp = esp->current_SC;
-	Scsi_Device *dp = sp->device;
+	struct esp_device *esp_dev = sp->device->hostdata;
 
 	/* This means real problems if we see this
 	 * here.  Unless we were actually trying
@@ -2500,9 +2527,9 @@
 
 	case BUS_DEVICE_RESET:
 		ESPLOG(("device reset successful\n"));
-		dp->sync_max_offset = 0;
-		dp->sync_min_period = 0;
-		dp->sync = 0;
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+		esp_dev->sync = 0;
 		esp_advance_phase(sp, in_resetdev);
 		esp_done(esp, (DID_RESET << 16));
 		break;
@@ -2575,7 +2602,7 @@
 static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
-	Scsi_Device *SDptr = SCptr->device;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
 	int cmd_bytes_sent, fcnt;
 
 	fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
@@ -2604,7 +2631,7 @@
 
 		/* What if the target ignores the sdtr? */
 		if(esp->snip)
-			SDptr->sync = 1;
+			esp_dev->sync = 1;
 
 		/* See how far, if at all, we got in getting
 		 * the information out to the target.
@@ -2693,7 +2720,7 @@
 		 */
 		if(!fcnt && /* Fifo is empty and... */
 		   /* either we are not doing synchronous transfers or... */
-		   (!SDptr->sync_max_offset ||
+		   (!esp_dev->sync_max_offset ||
 		    /* We are not going into data in phase. */
 		    ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
 			esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */
@@ -2754,9 +2781,9 @@
 			esp->snip = 0;
 			ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
 				"lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
-			SDptr->sync_max_offset = 0;
-			SDptr->sync_min_period = 0;
-			SDptr->sync = 1; /* so we don't negotiate again */
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync = 1; /* so we don't negotiate again */
 
 			/* Run the command again, this time though we
 			 * won't try to negotiate for synchronous transfers.
@@ -2904,16 +2931,16 @@
 	case MESSAGE_REJECT:
 		ESPMISC(("msg reject, "));
 		if(esp->prevmsgout == EXTENDED_MESSAGE) {
-			Scsi_Device *SDptr = esp->current_SC->device;
+			struct esp_device *esp_dev = esp->current_SC->device->hostdata;
 
 			/* Doesn't look like this target can
 			 * do synchronous or WIDE transfers.
 			 */
 			ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
-			SDptr->sync = 1;
-			SDptr->wide = 1;
-			SDptr->sync_min_period = 0;
-			SDptr->sync_max_offset = 0;
+			esp_dev->sync = 1;
+			esp_dev->wide = 1;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync_max_offset = 0;
 			return 0;
 		} else {
 			ESPMISC(("not sync nego, sending ABORT\n"));
@@ -2929,13 +2956,13 @@
  */
 static int target_with_ants_in_pants(struct NCR_ESP *esp,
 				     Scsi_Cmnd *SCptr,
-				     Scsi_Device *SDptr)
+				     struct esp_device *esp_dev)
 {
-	if(SDptr->sync || SDptr->borken) {
+	if(esp_dev->sync || SCptr->device->borken) {
 		/* sorry, no can do */
 		ESPSDTR(("forcing to async, "));
 		build_sync_nego_msg(esp, 0, 0);
-		SDptr->sync = 1;
+		esp_dev->sync = 1;
 		esp->snip = 1;
 		ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
 		esp_advance_phase(SCptr, in_the_dark);
@@ -2984,7 +3011,7 @@
 			       struct ESP_regs *eregs)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
-	Scsi_Device *SDptr = SCptr->device;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
 	unchar regval = 0;
 	int message_out = 0;
 
@@ -3000,7 +3027,7 @@
 			/* Target negotiates first! */
 			ESPSDTR(("target jumps the gun, "));
 			message_out = EXTENDED_MESSAGE; /* we must respond */
-			rval = target_with_ants_in_pants(esp, SCptr, SDptr);
+			rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
 			if(rval)
 				return rval;
 		}
@@ -3045,8 +3072,8 @@
 		if(offset) {
 			unchar bit;
 
-			SDptr->sync_min_period = (regval & 0x1f);
-			SDptr->sync_max_offset = (offset | esp->radelay);
+			esp_dev->sync_min_period = (regval & 0x1f);
+			esp_dev->sync_max_offset = (offset | esp->radelay);
 			if(esp->erev > esp236) {
 				if(esp->erev == fas100a)
 					bit = ESP_CONFIG3_FAST;
@@ -3059,24 +3086,24 @@
 				esp->prev_cfg3 = esp->config3[SCptr->target];
 				esp_write(eregs->esp_cfg3, esp->prev_cfg3);
 			}
-			esp->prev_soff = SDptr->sync_min_period;
+			esp->prev_soff = esp_dev->sync_min_period;
 			esp_write(eregs->esp_soff, esp->prev_soff);
-			esp->prev_stp = SDptr->sync_max_offset;
+			esp->prev_stp = esp_dev->sync_max_offset;
 			esp_write(eregs->esp_stp, esp->prev_stp);
 
 			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
-				SDptr->sync_max_offset,
-				SDptr->sync_min_period,
+				esp_dev->sync_max_offset,
+				esp_dev->sync_min_period,
 				esp->config3[SCptr->target]));
 
 			esp->snip = 0;
-		} else if(SDptr->sync_max_offset) {
+		} else if(esp_dev->sync_max_offset) {
 			unchar bit;
 
 			/* back to async mode */
 			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
-			SDptr->sync_max_offset = 0;
-			SDptr->sync_min_period = 0;
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
 			esp->prev_soff = 0;
 			esp_write(eregs->esp_soff, 0);
 			esp->prev_stp = 0;
@@ -3095,7 +3122,7 @@
 		sync_report(esp);
 
 		ESPSDTR(("chk multibyte msg: sync is known, "));
-		SDptr->sync = 1;
+		esp_dev->sync = 1;
 
 		if(message_out) {
 			ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
@@ -3318,7 +3345,7 @@
 
 		default:
 			if(!fcount(esp, eregs) &&
-			   !(esp->current_SC->device->sync_max_offset))
+			   !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
 				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
 			break;
 
diff -Nru a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
--- a/drivers/scsi/NCR53C9x.h	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/NCR53C9x.h	Fri Oct 11 21:22:55 2002
@@ -283,6 +283,17 @@
   espunknown = 0x09
 };
 
+/* We allocate one of these for each scsi device and attach it to
+ * SDptr->hostdata for use in the driver
+ */
+struct esp_device {
+  unsigned char sync_min_period;
+  unsigned char sync_max_offset;
+  unsigned sync:1;
+  unsigned wide:1;
+  unsigned disconnect:1;
+};
+
 /* We get one of these for each ESP probed. */
 struct NCR_ESP {
   struct NCR_ESP *next;                   /* Next ESP on probed or NULL */
diff -Nru a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile
--- a/drivers/scsi/aacraid/Makefile	Fri Oct 11 21:23:03 2002
+++ b/drivers/scsi/aacraid/Makefile	Fri Oct 11 21:23:03 2002
@@ -1,10 +1,8 @@
+# Adaptec aacraid
+ 
+obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
 
-EXTRA_CFLAGS	+= -I$(TOPDIR)/drivers/scsi
-
-O_TARGET	:= aacraid.o
-obj-m		:= $(O_TARGET)
-
-obj-y		:= linit.o aachba.o commctrl.o comminit.o commsup.o \
+aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
 		   dpcsup.o rx.o sa.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/advansys.c	Fri Oct 11 21:22:55 2002
@@ -6140,7 +6140,7 @@
                 ip[1] = 32;
         }
     }
-    ip[2] = dp->capacity / (ip[0] * ip[1]);
+    ip[2] = (unsigned long)dp->capacity / (ip[0] * ip[1]);
     ASC_DBG(1, "advansys_biosparam: end\n");
     return 0;
 }
diff -Nru a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
--- a/drivers/scsi/aha152x.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/scsi/aha152x.c	Fri Oct 11 21:22:52 2002
@@ -250,6 +250,7 @@
 
 #include "aha152x.h"
 #include <linux/stat.h>
+#include <linux/workqueue.h>
 
 #include <scsi/scsicam.h>
 
@@ -1837,7 +1838,7 @@
 	/* try default translation */
 	info_array[0] = 64;
 	info_array[1] = 32;
-	info_array[2] = disk->capacity / (64 * 32);
+	info_array[2] = (unsigned long)disk->capacity / (64 * 32);
 
 	/* for disks >1GB do some guessing */
 	if (info_array[2] >= 1024) {
@@ -1852,7 +1853,7 @@
 				       "         using extended translation.\n");
 				info_array[0] = 255;
 				info_array[1] = 63;
-				info_array[2] = disk->capacity / (255 * 63);
+				info_array[2] = (unsigned long)disk->capacity / (255 * 63);
 			} else {
 				printk(KERN_NOTICE
 				       "aha152x: unable to verify geometry for disk with >1GB.\n"
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c	Fri Oct 11 21:22:57 2002
@@ -3720,7 +3720,7 @@
 
 /*
  * Reset the controller and record some information about it
- * that is only availabel just after a reset.
+ * that is only available just after a reset.
  */
 int
 ahc_reset(struct ahc_softc *ahc)
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c	Fri Oct 11 21:22:56 2002
@@ -2748,7 +2748,7 @@
 	}
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (unsigned long)disk->capacity / (heads * sectors);
 
 	if (aic7xxx_extended != 0)
 		extended = 1;
@@ -2759,7 +2759,7 @@
 	if (extended && cylinders >= 1024) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (unsigned long)disk->capacity / (heads * sectors);
 	}
 	geom[0] = heads;
 	geom[1] = sectors;
diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h
--- a/drivers/scsi/aic7xxx_old/aic7xxx.h	Fri Oct 11 21:22:51 2002
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.h	Fri Oct 11 21:22:51 2002
@@ -46,7 +46,8 @@
 	eh_host_reset_handler: NULL,				\
 	abort: aic7xxx_abort,					\
 	reset: aic7xxx_reset,					\
-	slave_attach: NULL,					\
+	slave_attach: aic7xxx_slave_attach,			\
+	slave_detach: aic7xxx_slave_detach,			\
 	bios_param: aic7xxx_biosparam,				\
 	can_queue: 255,		/* max simultaneous cmds      */\
 	this_id: -1,		/* scsi id of host adapter    */\
@@ -64,6 +65,8 @@
 extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
 extern int aic7xxx_abort(Scsi_Cmnd *);
 extern int aic7xxx_release(struct Scsi_Host *);
+extern int aic7xxx_slave_attach(Scsi_Device *);
+extern void aic7xxx_slave_detach(Scsi_Device *);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
 
diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
--- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Fri Oct 11 21:23:03 2002
@@ -33,7 +33,7 @@
 
 #define	BLS	(&aic7xxx_buffer[size])
 #define HDRB \
-"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
+"             0 - 4K     4 - 16K    16 - 64K   64 - 256K   256K - 1M    1M+"
 
 #ifdef PROC_DEBUG
 extern int vsprintf(char *, const char *, va_list);
@@ -85,10 +85,12 @@
 {
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
+  struct aic_dev_data *aic_dev;
+  struct scsi_device *sdptr;
   int    size = 0;
   unsigned char i;
-  struct aic7xxx_xferstats *sp;
-  unsigned char target;
+  unsigned char tindex;
+  struct list_head *list_item;
 
   HBAptr = NULL;
 
@@ -130,14 +132,9 @@
    */
 
   size = 4096;
-  for (target = 0; target < MAX_TARGETS; target++)
+  list_for_each(list_item, &p->aic_devs)
   {
-    if (p->dev_flags[target] & DEVICE_PRESENT)
-#ifdef AIC7XXX_PROC_STATS
-      size += 512;
-#else
-      size += 256;
-#endif
+    size += 512;
   }
   if (aic7xxx_buffer_size != size)
   {
@@ -167,11 +164,6 @@
 #else
   size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
 #endif
-#ifdef AIC7XXX_PROC_STATS
-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
-#endif
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
   size += sprintf(BLS, "           SCSI Adapter: %s\n",
@@ -271,8 +263,6 @@
   {
     size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
   }
-  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
-  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
   size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
   size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
                        "instance %d:\n", p->instance);
@@ -280,43 +270,27 @@
   for(i=0; i < (MAX_TARGETS - 1); i++)
     size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
   size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
-  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
-                       "instance %d:\n", p->instance);
-  size += sprintf(BLS, "      {");
-  for(i=0; i < (MAX_TARGETS - 1); i++)
-    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
-  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
 
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Statistics:\n\n");
-  for (target = 0; target < MAX_TARGETS; target++)
+  list_for_each(list_item, &p->aic_devs)
   {
-    sp = &p->stats[target];
-    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
-    {
-      continue;
-    }
-    if (p->features & AHC_TWIN)
-    {
-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-          p->host_no, (target >> 3), (target & 0x7), 0);
-    }
-    else
-    {
-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-          p->host_no, 0, target, 0);
-    }
+    aic_dev = list_entry(list_item, struct aic_dev_data, list);
+    sdptr = aic_dev->SDptr;
+    tindex = sdptr->channel << 3 | sdptr->id;
+    size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+        p->host_no, sdptr->channel, sdptr->id, sdptr->lun);
     size += sprintf(BLS, "  Device using %s/%s",
-          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
+          (aic_dev->cur.width == MSG_EXT_WDTR_BUS_16_BIT) ?
           "Wide" : "Narrow",
-          (p->transinfo[target].cur_offset != 0) ?
+          (aic_dev->cur.offset != 0) ?
           "Sync transfers at " : "Async transfers.\n" );
-    if (p->transinfo[target].cur_offset != 0)
+    if (aic_dev->cur.offset != 0)
     {
       struct aic7xxx_syncrate *sync_rate;
-      unsigned char options = p->transinfo[target].cur_options;
-      int period = p->transinfo[target].cur_period;
-      int rate = (p->transinfo[target].cur_width ==
+      unsigned char options = aic_dev->cur.options;
+      int period = aic_dev->cur.period;
+      int rate = (aic_dev->cur.width ==
                   MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
 
       sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
@@ -324,50 +298,45 @@
       {
         size += sprintf(BLS, "%s MByte/sec, offset %d\n",
                         sync_rate->rate[rate],
-                        p->transinfo[target].cur_offset );
+                        aic_dev->cur.offset );
       }
       else
       {
         size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
-                        p->transinfo[target].cur_offset );
+                        aic_dev->cur.offset );
       }
     }
     size += sprintf(BLS, "  Transinfo settings: ");
     size += sprintf(BLS, "current(%d/%d/%d/%d), ",
-                    p->transinfo[target].cur_period,
-                    p->transinfo[target].cur_offset,
-                    p->transinfo[target].cur_width,
-                    p->transinfo[target].cur_options);
+                    aic_dev->cur.period,
+                    aic_dev->cur.offset,
+                    aic_dev->cur.width,
+                    aic_dev->cur.options);
     size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
-                    p->transinfo[target].goal_period,
-                    p->transinfo[target].goal_offset,
-                    p->transinfo[target].goal_width,
-                    p->transinfo[target].goal_options);
+                    aic_dev->goal.period,
+                    aic_dev->goal.offset,
+                    aic_dev->goal.width,
+                    aic_dev->goal.options);
     size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
-                    p->transinfo[target].user_period,
-                    p->transinfo[target].user_offset,
-                    p->transinfo[target].user_width,
-                    p->transinfo[target].user_options);
-#ifdef AIC7XXX_PROC_STATS
+                    p->user[tindex].period,
+                    p->user[tindex].offset,
+                    p->user[tindex].width,
+                    p->user[tindex].options);
     size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+      aic_dev->r_total + aic_dev->w_total, aic_dev->r_total, aic_dev->w_total);
     size += sprintf(BLS, "%s\n", HDRB);
     size += sprintf(BLS, "   Reads:");
-    for (i = 0; i < NUMBER(sp->r_bins); i++)
+    for (i = 0; i < NUMBER(aic_dev->r_bins); i++)
     {
-      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
+      size += sprintf(BLS, " %7ld", aic_dev->r_bins[i]);
     }
     size += sprintf(BLS, "\n");
     size += sprintf(BLS, "  Writes:");
-    for (i = 0; i < NUMBER(sp->w_bins); i++)
+    for (i = 0; i < NUMBER(aic_dev->w_bins); i++)
     {
-      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
+      size += sprintf(BLS, " %7ld", aic_dev->w_bins[i]);
     }
     size += sprintf(BLS, "\n");
-#else
-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
-#endif /* AIC7XXX_PROC_STATS */
     size += sprintf(BLS, "\n\n");
   }
 
diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
--- a/drivers/scsi/aic7xxx_old.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/scsi/aic7xxx_old.c	Fri Oct 11 21:22:56 2002
@@ -253,7 +253,7 @@
 
 #include <linux/config.h>        /* for CONFIG_PCI */
 
-#define AIC7XXX_C_VERSION  "5.2.4"
+#define AIC7XXX_C_VERSION  "5.2.5"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -274,45 +274,11 @@
 #  define MMAPIO
 #endif
 
-#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-#    define cpuid smp_processor_id()
-#    define DRIVER_LOCK_INIT \
-       spin_lock_init(&p->spin_lock);
-#    define DRIVER_LOCK \
-       if(!p->cpu_lock_count[cpuid]) { \
-         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
-         p->cpu_lock_count[cpuid]++; \
-       } else { \
-         p->cpu_lock_count[cpuid]++; \
-       }
-#    define DRIVER_UNLOCK \
-       if(--p->cpu_lock_count[cpuid] == 0) \
-         spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
-#  else
-#    define DRIVER_LOCK_INIT
-#    define DRIVER_LOCK
-#    define DRIVER_UNLOCK
-#  endif
-
 /*
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
-#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
-#else
 #define AIC7XXX_CMDS_PER_DEVICE 32
-#endif
-
-/*
- * Control collection of SCSI transfer statistics for the /proc filesystem.
- *
- * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
- * NOTE: This does affect performance since it has to maintain statistics.
- */
-#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS
-#define AIC7XXX_PROC_STATS
-#endif
 
 /*
  * *** Determining commands per LUN ***
@@ -334,13 +300,8 @@
  * Make a define that will tell the driver not to use tagged queueing
  * by default.
  */
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
 #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
                               0, 0, 0, 0, 0, 0, 0, 0}
-#else
-#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
-                              255, 255, 255, 255, 255, 255, 255, 255}
-#endif
 
 /*
  * Modify this as you see fit for your system.  By setting tag_commands
@@ -640,6 +601,11 @@
 #define aic7xxx_mapping(cmd)	     ((cmd)->SCp.phase)
 
 /*
+ * Get out private data area from a scsi cmd pointer
+ */
+#define AIC_DEV(cmd)	((struct aic_dev_data *)(cmd)->device->hostdata)
+
+/*
  * So we can keep track of our host structs
  */
 static struct aic7xxx_host *first_aic7xxx = NULL;
@@ -718,7 +684,8 @@
                                   SCB_MSGOUT_WDTR,
         SCB_QUEUED_ABORT        = 0x1000,
         SCB_QUEUED_FOR_DONE     = 0x2000,
-        SCB_WAS_BUSY            = 0x4000
+        SCB_WAS_BUSY            = 0x4000,
+	SCB_QUEUE_FULL		= 0x8000
 } scb_flag_type;
 
 typedef enum {
@@ -901,20 +868,52 @@
 #define AHC_TRANS_USER   0x0008
 #define AHC_TRANS_QUITE  0x0010
 typedef struct {
-  unsigned char cur_width;
-  unsigned char goal_width;
-  unsigned char cur_period;
-  unsigned char goal_period;
-  unsigned char cur_offset;
-  unsigned char goal_offset;
-  unsigned char cur_options;
-  unsigned char goal_options;
-  unsigned char user_width;
-  unsigned char user_period;
-  unsigned char user_offset;
-  unsigned char user_options;
+  unsigned char width;
+  unsigned char period;
+  unsigned char offset;
+  unsigned char options;
 } transinfo_type;
 
+struct aic_dev_data {
+  volatile scb_queue_type  delayed_scbs;
+  volatile unsigned short  temp_q_depth;
+  unsigned short           max_q_depth;
+  volatile unsigned char   active_cmds;
+  unsigned char            cmds_sent;
+  /*
+   * Statistics Kept:
+   *
+   * Total Xfers (count for each command that has a data xfer),
+   * broken down by reads && writes.
+   *
+   * Further sorted into a few bins for keeping tabs on how many commands
+   * we get of various sizes.
+   *
+   */
+  long w_total;                          /* total writes */
+  long r_total;                          /* total reads */
+  long w_bins[6];                       /* binned write */
+  long r_bins[6];                       /* binned reads */
+  transinfo_type	cur;
+  transinfo_type	goal;
+#define  BUS_DEVICE_RESET_PENDING       0x01
+#define  DEVICE_RESET_DELAY             0x02
+#define  DEVICE_PRINT_DTR               0x04
+#define  DEVICE_WAS_BUSY                0x08
+#define  DEVICE_DTR_SCANNED		0x10
+#define  DEVICE_SCSI_3			0x20
+  volatile unsigned char   flags;
+  unsigned needppr:1;
+  unsigned needppr_copy:1;
+  unsigned needsdtr:1;
+  unsigned needsdtr_copy:1;
+  unsigned needwdtr:1;
+  unsigned needwdtr_copy:1;
+  unsigned dtr_pending:1;
+  struct scsi_device *SDptr;
+  struct list_head list;
+};
+
 /*
  * Define a structure used for each host adapter.  Note, in order to avoid
  * problems with architectures I can't test on (because I don't have one,
@@ -941,10 +940,6 @@
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
   scb_data_type           *scb_data;
-  volatile unsigned short  needppr;
-  volatile unsigned short  needsdtr;
-  volatile unsigned short  needwdtr;
-  volatile unsigned short  dtr_pending;
   struct aic7xxx_cmd_queue {
     Scsi_Cmnd *head;
     Scsi_Cmnd *tail;
@@ -954,9 +949,6 @@
    * Things read/written on nearly every entry into aic7xxx_queue()
    */
   volatile scb_queue_type  waiting_scbs;
-  unsigned short           discenable;       /* Targets allowed to disconnect */
-  unsigned short           tagenable;        /* Targets using tagged I/O */
-  unsigned short           orderedtag;       /* Ordered Q tags allowed */
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
   volatile unsigned char   qoutfifonext;
@@ -967,31 +959,13 @@
   volatile unsigned char  *qoutfifo;
   volatile unsigned char  *qinfifo;
 
-#define  DEVICE_PRESENT                 0x01
-#define  BUS_DEVICE_RESET_PENDING       0x02
-#define  DEVICE_RESET_DELAY             0x04
-#define  DEVICE_PRINT_DTR               0x08
-#define  DEVICE_WAS_BUSY                0x10
-#define  DEVICE_SCSI_3                  0x20
-#define  DEVICE_DTR_SCANNED             0x40
-  volatile unsigned char   dev_flags[MAX_TARGETS];
-  volatile unsigned char   dev_active_cmds[MAX_TARGETS];
-  volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
-  unsigned char            dev_commands_sent[MAX_TARGETS];
-
-  unsigned int             dev_timer_active; /* Which devs have a timer set */
-  struct timer_list        dev_timer;
-  unsigned long            dev_expires[MAX_TARGETS];
-
-  spinlock_t               spin_lock;
-  volatile unsigned char   cpu_lock_count[NR_CPUS];
-
   unsigned char            dev_last_queue_full[MAX_TARGETS];
   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
-  unsigned char            dev_max_queue_depth[MAX_TARGETS];
-
-  volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
-
+  unsigned short	   ultraenb;         /* Gets downloaded to card as a
+						bitmap */
+  unsigned short	   discenable;       /* Gets downloaded to card as a
+						bitmap */
+  transinfo_type           user[MAX_TARGETS];
 
   unsigned char            msg_buf[13];      /* The message for the target */
   unsigned char            msg_type;
@@ -1000,7 +974,6 @@
 #define MSG_TYPE_INITIATOR_MSGIN   0x02
   unsigned char            msg_len;          /* Length of message */
   unsigned char            msg_index;        /* Index into msg_buf array */
-  transinfo_type           transinfo[MAX_TARGETS];
 
 
   /*
@@ -1016,10 +989,6 @@
   int                      scsi_id_b;        /* channel B for twin adapters */
   unsigned int             bios_address;
   int                      board_name_index;
-  unsigned short           needppr_copy;     /* default config */
-  unsigned short           needsdtr_copy;    /* default config */
-  unsigned short           needwdtr_copy;    /* default config */
-  unsigned short           ultraenb;         /* Ultra mode target list */
   unsigned short           bios_control;     /* bios control - SEEPROM */
   unsigned short           adapter_control;  /* adapter control - SEEPROM */
   struct pci_dev	  *pdev;
@@ -1030,46 +999,13 @@
   unsigned short           sc_size;
   struct aic7xxx_host     *next;             /* allow for multiple IRQs */
   struct Scsi_Host        *host;             /* pointer to scsi host */
+  struct list_head	   aic_devs;	     /* all aic devs on host */
   int                      host_no;          /* SCSI host number */
   unsigned long            mbase;            /* I/O memory address */
   ahc_chip                 chip;             /* chip type */
   ahc_bugs                 bugs;
   dma_addr_t		   fifo_dma;	     /* DMA handle for fifo arrays */
 
-  /*
-   * Statistics Kept:
-   *
-   * Total Xfers (count for each command that has a data xfer),
-   * broken down further by reads && writes.
-   *
-   * Binned sizes, writes && reads:
-   *    < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
-   *
-   * Total amounts read/written above 512 bytes (amts under ignored)
-   *
-   * NOTE: Enabling this feature is likely to cause a noticeable performance
-   * decrease as the accesses into the stats structures blows apart multiple
-   * cache lines and is CPU time consuming.
-   *
-   * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM
-   * and blows apart all sorts of cache lines, I modified this so that we
-   * no longer look at the LUN.  All LUNs now go into the same bin on each
-   * device for stats purposes.
-   */
-  struct aic7xxx_xferstats {
-    long w_total;                          /* total writes */
-    long r_total;                          /* total reads */
-#ifdef AIC7XXX_PROC_STATS
-    long w_bins[8];                       /* binned write */
-    long r_bins[8];                       /* binned reads */
-#endif /* AIC7XXX_PROC_STATS */
-  } stats[MAX_TARGETS];                    /* [(channel << 3)|target] */
-
-#if 0
-  struct target_cmd       *targetcmds;
-  unsigned int             num_targetcmds;
-#endif
-
 };
 
 /*
@@ -1306,14 +1242,6 @@
 #ifdef MODULE
 static char * aic7xxx = NULL;
 MODULE_PARM(aic7xxx, "s");
-
-/*
- * Just in case someone uses commas to separate items on the insmod
- * command line, we define a dummy buffer here to avoid having insmod
- * write wild stuff into our code segment
- */
-static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
-
 #endif
 
 #define VERBOSE_NORMAL         0x0000
@@ -1346,6 +1274,13 @@
  *
  ***************************************************************************/
 
+static void aic7xxx_set_syncrate(struct aic7xxx_host *p, 
+		struct aic7xxx_syncrate *syncrate, int target, int channel,
+		unsigned int period, unsigned int offset, unsigned char options,
+		unsigned int type, struct aic_dev_data *aic_dev);
+static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel,
+		int lun, unsigned int width, unsigned int type,
+		struct aic_dev_data *aic_dev);
 static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
 static void aic7xxx_print_card(struct aic7xxx_host *p);
 static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
@@ -2138,7 +2073,7 @@
 static void
 aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
     int target, int channel, unsigned int period, unsigned int offset,
-    unsigned char options, unsigned int type)
+    unsigned char options, unsigned int type, struct aic_dev_data *aic_dev)
 {
   unsigned char tindex;
   unsigned short target_mask;
@@ -2155,9 +2090,9 @@
     offset = 0;
   }
 
-  old_period = p->transinfo[tindex].cur_period;
-  old_offset = p->transinfo[tindex].cur_offset;
-  old_options = p->transinfo[tindex].cur_options;
+  old_period = aic_dev->cur.period;
+  old_offset = aic_dev->cur.offset;
+  old_options = aic_dev->cur.options;
 
   
   if (type & AHC_TRANS_CUR)
@@ -2220,12 +2155,12 @@
       aic_outb(p, scsirate, SCSIRATE);
     }
     aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
-    p->transinfo[tindex].cur_period = period;
-    p->transinfo[tindex].cur_offset = offset;
-    p->transinfo[tindex].cur_options = options;
+    aic_dev->cur.period = period;
+    aic_dev->cur.offset = offset;
+    aic_dev->cur.options = options;
     if ( !(type & AHC_TRANS_QUITE) &&
          (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
-         (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+         (aic_dev->flags & DEVICE_PRINT_DTR) )
     {
       if (offset)
       {
@@ -2240,22 +2175,22 @@
         printk(INFO_LEAD "Using asynchronous transfers.\n",
                p->host_no, channel, target, lun);
       }
-      p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
+      aic_dev->flags &= ~DEVICE_PRINT_DTR;
     }
   }
 
   if (type & AHC_TRANS_GOAL)
   {
-    p->transinfo[tindex].goal_period = period;
-    p->transinfo[tindex].goal_offset = offset;
-    p->transinfo[tindex].goal_options = options;
+    aic_dev->goal.period = period;
+    aic_dev->goal.offset = offset;
+    aic_dev->goal.options = options;
   }
 
   if (type & AHC_TRANS_USER)
   {
-    p->transinfo[tindex].user_period = period;
-    p->transinfo[tindex].user_offset = offset;
-    p->transinfo[tindex].user_options = options;
+    p->user[tindex].period = period;
+    p->user[tindex].offset = offset;
+    p->user[tindex].options = options;
   }
 }
 
@@ -2268,7 +2203,7 @@
  *-F*************************************************************************/
 static void
 aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
-    unsigned int width, unsigned int type)
+    unsigned int width, unsigned int type, struct aic_dev_data *aic_dev)
 {
   unsigned char tindex;
   unsigned short target_mask;
@@ -2277,7 +2212,7 @@
   tindex = target | (channel << 3);
   target_mask = 1 << tindex;
   
-  old_width = p->transinfo[tindex].cur_width;
+  old_width = aic_dev->cur.width;
 
   if (type & AHC_TRANS_CUR) 
   {
@@ -2294,11 +2229,11 @@
     if (type & AHC_TRANS_ACTIVE)
       aic_outb(p, scsirate, SCSIRATE);
 
-    p->transinfo[tindex].cur_width = width;
+    aic_dev->cur.width = width;
 
     if ( !(type & AHC_TRANS_QUITE) &&
           (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && 
-          (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+          (aic_dev->flags & DEVICE_PRINT_DTR) )
     {
       printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
         lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
@@ -2306,23 +2241,23 @@
   }
 
   if (type & AHC_TRANS_GOAL)
-    p->transinfo[tindex].goal_width = width;
+    aic_dev->goal.width = width;
   if (type & AHC_TRANS_USER)
-    p->transinfo[tindex].user_width = width;
+    p->user[tindex].width = width;
 
-  if (p->transinfo[tindex].goal_offset)
+  if (aic_dev->goal.offset)
   {
     if (p->features & AHC_ULTRA2)
     {
-      p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+      aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
     }
     else if (width == MSG_EXT_WDTR_BUS_16_BIT)
     {
-      p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+      aic_dev->goal.offset = MAX_OFFSET_16BIT;
     }
     else
     {
-      p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+      aic_dev->goal.offset = MAX_OFFSET_8BIT;
     }
   }
 }
@@ -2353,16 +2288,10 @@
 static inline void
 scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
-
-  DRIVER_LOCK
   scb->q_next = queue->head;
   queue->head = scb;
   if (queue->tail == NULL)       /* If list was empty, update tail. */
     queue->tail = queue->head;
-  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -2377,17 +2306,12 @@
 scbq_remove_head(volatile scb_queue_type *queue)
 {
   struct aic7xxx_scb * scbp;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
 
-  DRIVER_LOCK
   scbp = queue->head;
   if (queue->head != NULL)
     queue->head = queue->head->q_next;
   if (queue->head == NULL)       /* If list is now empty, update tail. */
     queue->tail = NULL;
-  DRIVER_UNLOCK
   return(scbp);
 }
 
@@ -2402,11 +2326,6 @@
 static inline void
 scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
-
-  DRIVER_LOCK
   if (queue->head == scb)
   {
     /* At beginning of queue, remove from head. */
@@ -2435,7 +2354,6 @@
       }
     }
   }
-  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -2449,18 +2367,12 @@
 static inline void
 scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
-
-  DRIVER_LOCK
   scb->q_next = NULL;
   if (queue->tail != NULL)       /* Add the scb at the end of the list. */
     queue->tail->q_next = scb;
   queue->tail = scb;             /* Update the tail. */
   if (queue->head == NULL)       /* If list was empty, update head. */
     queue->head = queue->tail;
-  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -2740,11 +2652,7 @@
 aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned int cpu_flags = 0;
-#endif
   
-  DRIVER_LOCK
   while (p->completeq.head != NULL)
   {
     cmd = p->completeq.head;
@@ -2752,7 +2660,6 @@
     cmd->host_scribble = NULL;
     cmd->scsi_done(cmd);
   }
-  DRIVER_UNLOCK
 }
 
 /*+F*************************************************************************
@@ -2789,6 +2696,7 @@
 aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   Scsi_Cmnd *cmd = scb->cmd;
+  struct aic_dev_data *aic_dev = cmd->device->hostdata;
   int tindex = TARGET_INDEX(cmd);
   struct aic7xxx_scb *scbp;
   unsigned char queue_depth;
@@ -2820,94 +2728,6 @@
     cmd->result |= (DID_RESET << 16);
   }
 
-  if (!(p->dev_flags[tindex] & DEVICE_PRESENT))
-  {
-    if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
-    {
-    
-      p->dev_flags[tindex] |= DEVICE_PRESENT;
-#define WIDE_INQUIRY_BITS 0x60
-#define SYNC_INQUIRY_BITS 0x10
-#define SCSI_VERSION_BITS 0x07
-#define SCSI_DT_BIT       0x04
-      if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) {
-        char *buffer;
-
-        if(cmd->use_sg)
-          BUG();
-
-        buffer = (char *)cmd->request_buffer;
-
-        if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
-             (p->features & AHC_WIDE) )
-        {
-          p->needwdtr |= (1<<tindex);
-          p->needwdtr_copy |= (1<<tindex);
-          p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
-        }
-        else
-        {
-          p->needwdtr &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-          pause_sequencer(p);
-          aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
-                            MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
-                                                     AHC_TRANS_GOAL |
-                                                     AHC_TRANS_CUR) );
-          unpause_sequencer(p, FALSE);
-        }
-        if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
-              p->transinfo[tindex].user_offset )
-        {
-          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-          p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
-          if (p->features & AHC_ULTRA2)
-            p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-          else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
-            p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-          else
-            p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-          if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) ||
-                 (buffer[56] & SCSI_DT_BIT) ||
-                 (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
-                 (p->transinfo[tindex].user_period <= 9) &&
-                 (p->transinfo[tindex].user_options) )
-          {
-            p->needppr |= (1<<tindex);
-            p->needppr_copy |= (1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-            p->needwdtr &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-            p->dev_flags[tindex] |= DEVICE_SCSI_3;
-          }
-          else
-          {
-            p->needsdtr |= (1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-            p->transinfo[tindex].goal_period = 
-              MAX(10, p->transinfo[tindex].goal_period);
-            p->transinfo[tindex].goal_options = 0;
-          }
-        }
-        else
-        {
-          p->needsdtr &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
-          p->transinfo[tindex].goal_period = 255;
-          p->transinfo[tindex].goal_offset = 0;
-          p->transinfo[tindex].goal_options = 0;
-        }
-        p->dev_flags[tindex] |= DEVICE_DTR_SCANNED;
-        p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
-      }
-#undef WIDE_INQUIRY_BITS
-#undef SYNC_INQUIRY_BITS
-#undef SCSI_VERSION_BITS
-#undef SCSI_DT_BIT
-    }
-  }
-
   if ((scb->flags & SCB_MSGOUT_BITS) != 0)
   {
     unsigned short mask;
@@ -2931,7 +2751,7 @@
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+             (aic_dev->flags & DEVICE_PRINT_DTR) )
         {
           printk(INFO_LEAD "Device failed to complete Wide Negotiation "
             "processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -2940,8 +2760,7 @@
           printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
             CTL_OF_SCB(scb));
         }
-        p->needwdtr &= ~mask;
-        p->needwdtr_copy &= ~mask;
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
       }
     }
     if (scb->flags & SCB_MSGOUT_SDTR)
@@ -2949,7 +2768,7 @@
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+             (aic_dev->flags & DEVICE_PRINT_DTR) )
         {
           printk(INFO_LEAD "Device failed to complete Sync Negotiation "
             "processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -2957,10 +2776,9 @@
             "disabling future\n", p->host_no, CTL_OF_SCB(scb));
           printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
             CTL_OF_SCB(scb));
-          p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
+          aic_dev->flags &= ~DEVICE_PRINT_DTR;
         }
-        p->needsdtr &= ~mask;
-        p->needsdtr_copy &= ~mask;
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
       }
     }
     if (scb->flags & SCB_MSGOUT_PPR)
@@ -2968,7 +2786,7 @@
       if(message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+             (aic_dev->flags & DEVICE_PRINT_DTR) )
         {
           printk(INFO_LEAD "Device failed to complete Parallel Protocol "
             "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
@@ -2980,20 +2798,17 @@
         /*
          * Disable PPR negotiation and revert back to WDTR and SDTR setup
          */
-        p->needppr &= ~mask;
-        p->needppr_copy &= ~mask;
-        p->needsdtr |= mask;
-        p->needsdtr_copy |= mask;
-        p->needwdtr |= mask;
-        p->needwdtr_copy |= mask;
+        aic_dev->needppr = aic_dev->needppr_copy = 0;
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
       }
     }
   }
 
-  queue_depth = p->dev_temp_queue_depth[tindex];
-  if (queue_depth >= p->dev_active_cmds[tindex])
+  queue_depth = aic_dev->temp_q_depth;
+  if (queue_depth >= aic_dev->active_cmds)
   {
-    scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+    scbp = scbq_remove_head(&aic_dev->delayed_scbs);
     if (scbp)
     {
       if (queue_depth == 1)
@@ -3015,9 +2830,9 @@
         printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n",
                p->host_no, CTL_OF_SCB(scbp));
 #endif
-      if (queue_depth > p->dev_active_cmds[tindex])
+      if (queue_depth > aic_dev->active_cmds)
       {
-        scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+        scbp = scbq_remove_head(&aic_dev->delayed_scbs);
         if (scbp)
           scbq_insert_tail(&p->waiting_scbs, scbp);
       }
@@ -3027,92 +2842,46 @@
   {
     aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
                               /* unbusy */ TRUE);
-    if (p->tagenable & (1<<tindex))
+    if (cmd->device->simple_tags)
     {
-      p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+      aic_dev->temp_q_depth = aic_dev->max_q_depth;
     }
   }
   if(scb->flags & SCB_DTR_SCB)
   {
-    p->dtr_pending &= ~(1 << tindex);
+    aic_dev->dtr_pending = 0;
   }
-  p->dev_active_cmds[tindex]--;
+  aic_dev->active_cmds--;
   p->activescbs--;
 
+  if ((scb->sg_length >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
   {
-    int actual;
+    long *ptr;
+    int x, i;
 
-    /*
-     * XXX: we should actually know how much actually transferred
-     * XXX: for each command, but apparently that's too difficult.
-     * 
-     * We set a lower limit of 512 bytes on the transfer length.  We
-     * ignore anything less than this because we don't have a real
-     * reason to count it.  Read/Writes to tapes are usually about 20K
-     * and disks are a minimum of 512 bytes unless you want to count
-     * non-read/write commands (such as TEST_UNIT_READY) which we don't
-     */
-    actual = scb->sg_length;
-    if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
-    {
-      struct aic7xxx_xferstats *sp;
-#ifdef AIC7XXX_PROC_STATS
-      long *ptr;
-      int x;
-#endif /* AIC7XXX_PROC_STATS */
-
-      sp = &p->stats[TARGET_INDEX(cmd)];
 
-      /*
-       * For block devices, cmd->request.cmd is always == either READ or
-       * WRITE.  For character devices, this isn't always set properly, so
-       * we check data_cmnd[0].  This catches the conditions for st.c, but
-       * I'm still not sure if request.cmd is valid for sg devices.
-       */
-      if ( (rq_data_dir(cmd->request) == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
-           (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
-      {
-        sp->w_total++;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if ( (sp->w_total > 16) && (aic7xxx_verbose > 0xffff) )
-          aic7xxx_verbose &= 0xffff;
-#endif
-#ifdef AIC7XXX_PROC_STATS
-        ptr = sp->w_bins;
-#endif /* AIC7XXX_PROC_STATS */
-      }
-      else
-      {
-        sp->r_total++;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if ( (sp->r_total > 16) && (aic7xxx_verbose > 0xffff) )
-          aic7xxx_verbose &= 0xffff;
-#endif
-#ifdef AIC7XXX_PROC_STATS
-        ptr = sp->r_bins;
-#endif /* AIC7XXX_PROC_STATS */
-      }
-#ifdef AIC7XXX_PROC_STATS
-      x = -11;
-      while(actual)
-      {
-        actual >>= 1;
-        x++;
-      }
-      if (x < 0)
-      {
-        ptr[0]++;
-      }
-      else if (x > 7)
-      {
-        ptr[7]++;
-      }
-      else
-      {
-        ptr[x]++;
+    if (rq_data_dir(cmd->request) == WRITE)
+    {
+      aic_dev->w_total++;
+      ptr = aic_dev->w_bins;
+    }
+    else
+    {
+      aic_dev->r_total++;
+      ptr = aic_dev->r_bins;
+    }
+    x = scb->sg_length;
+    x >>= 10;
+    for(i=0; i<6; i++)
+    {
+      x >>= 2;
+      if(!x) {
+        ptr[i]++;
+	break;
       }
-#endif /* AIC7XXX_PROC_STATS */
     }
+    if(i == 6 && x)
+      ptr[5]++;
   }
   aic7xxx_free_scb(p, scb);
   aic7xxx_queue_cmd_complete(p, cmd);
@@ -3139,18 +2908,25 @@
     scb = p->scb_data->scb_array[i];
     if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
-      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-        printk(INFO_LEAD "Aborting scb %d\n",
-             p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+      if (scb->flags & SCB_QUEUE_FULL)
+      {
+	scb->cmd->result = QUEUE_FULL << 1;
+      }
+      else
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+          printk(INFO_LEAD "Aborting scb %d\n",
+               p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+        /*
+         * Clear any residual information since the normal aic7xxx_done() path
+         * doesn't touch the residuals.
+         */
+        scb->hscb->residual_SG_segment_count = 0;
+        scb->hscb->residual_data_count[0] = 0;
+        scb->hscb->residual_data_count[1] = 0;
+        scb->hscb->residual_data_count[2] = 0;
+      }
       found++;
-      /*
-       * Clear any residual information since the normal aic7xxx_done() path
-       * doesn't touch the residuals.
-       */
-      scb->hscb->residual_SG_segment_count = 0;
-      scb->hscb->residual_data_count[0] = 0;
-      scb->hscb->residual_data_count[1] = 0;
-      scb->hscb->residual_data_count[2] = 0;
       aic7xxx_done(p, scb);
     }
   }
@@ -3251,12 +3027,12 @@
          {
            scbq_remove(queue, scbp);
            scbq_remove(&p->waiting_scbs, scbp);
-           scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
-           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+           scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp);
+           AIC_DEV(scbp->cmd)->active_cmds++;
            p->activescbs++;
          }
          scbq_insert_tail(queue, scbp);
-         p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+         AIC_DEV(scbp->cmd)->active_cmds--;
          p->activescbs--;
          scbp->flags |= SCB_WAITINGQ;
          if ( !(scbp->tag_action & TAG_ENB) )
@@ -3353,9 +3129,12 @@
 aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
                      int lun, unsigned char tag)
 {
-  struct aic7xxx_scb *scbp;
+  struct aic7xxx_scb *scbp, *prev_scbp;
+  struct scsi_device *sd;
   unsigned char active_scb, tcl;
-  int i = 0, j, init_lists = FALSE;
+  int i = 0, init_lists = FALSE;
+  struct list_head *list_item, *list_head;
+  struct aic_dev_data *aic_dev;
 
   /*
    * Restore this when we're done
@@ -3382,107 +3161,48 @@
   /*
    * Deal with the busy target and linked next issues.
    */
+  list_head = &p->aic_devs;
+  list_for_each(list_item, list_head)
   {
-    int min_target, max_target;
-    struct aic7xxx_scb *scbp, *prev_scbp;
-
-    /* Make all targets 'relative' to bus A. */
-    if (target == ALL_TARGETS)
-    {
-      switch (channel)
-      {
-        case 0:
-                 min_target = 0;
-                 max_target = (p->features & AHC_WIDE) ? 15 : 7;
-                 break;
-        case 1:
-                 min_target = 8;
-                 max_target = 15;
-                 break;
-        case ALL_CHANNELS:
-        default:
-                 min_target = 0;
-                 max_target = (p->features & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
-                 break;
-      }
-    }
-    else
-    { 
-      min_target = target | (channel << 3);
-      max_target = min_target;
-    }
-
+    aic_dev = list_entry(list_item, struct aic_dev_data, list);
+    sd = aic_dev->SDptr;
 
-    for (i = min_target; i <= max_target; i++)
-    {
-      if ( i == p->scsi_id )
-      {
-        continue;
-      }
-      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    if((target != ALL_TARGETS && target != sd->id) ||
+       (channel != ALL_CHANNELS && channel != sd->channel))
+      continue;
+    if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
         printk(INFO_LEAD "Cleaning up status information "
-          "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
-      if ( tag == SCB_LIST_NULL )
-      {
-        p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
-        p->dev_expires[i] = jiffies + (1 * HZ);
-        p->dev_timer_active |= (0x01 << i);
-        p->dev_last_queue_full_count[i] = 0;
-        p->dev_last_queue_full[i] = 0;
-        p->dev_temp_queue_depth[i] =
-          p->dev_max_queue_depth[i];
-      }
-      for(j=0; j<MAX_LUNS; j++)
+          "and delayed_scbs.\n", p->host_no, sd->channel, sd->id, sd->lun);
+    aic_dev->flags &= ~BUS_DEVICE_RESET_PENDING;
+    if ( tag == SCB_LIST_NULL )
+    {
+      aic_dev->dtr_pending = 0;
+      aic_dev->needppr = aic_dev->needppr_copy;
+      aic_dev->needsdtr = aic_dev->needsdtr_copy;
+      aic_dev->needwdtr = aic_dev->needwdtr_copy;
+      aic_dev->flags = DEVICE_PRINT_DTR;
+      aic_dev->temp_q_depth = aic_dev->max_q_depth;
+    }
+    tcl = (sd->id << 4) | (sd->channel << 3) | sd->lun;
+    if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+         (tag == SCB_LIST_NULL) )
+      aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+    prev_scbp = NULL; 
+    scbp = aic_dev->delayed_scbs.head;
+    while (scbp != NULL)
+    {
+      prev_scbp = scbp;
+      scbp = scbp->q_next;
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
       {
-        if (channel == 1)
-          tcl = ((i << 4) & 0x70) | (channel << 3) | j;
-        else
-          tcl = (i << 4) | (channel << 3) | j;
-        if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
-             (tag == SCB_LIST_NULL) )
-          aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
-      }
-      j = 0; 
-      prev_scbp = NULL; 
-      scbp = p->delayed_scbs[i].head;
-      while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
-      {
-        prev_scbp = scbp;
-        scbp = scbp->q_next;
-        if ( prev_scbp == scbp )
-        {
-          if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-            printk(WARN_LEAD "Yikes!! scb->q_next == scb "
-              "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
-          scbp = NULL;
-          prev_scbp->q_next = NULL;
-          p->delayed_scbs[i].tail = prev_scbp;
-        }
-        if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+        scbq_remove(&aic_dev->delayed_scbs, prev_scbp);
+        if (prev_scbp->flags & SCB_WAITINGQ)
         {
-          scbq_remove(&p->delayed_scbs[i], prev_scbp);
-          if (prev_scbp->flags & SCB_WAITINGQ)
-          {
-            p->dev_active_cmds[i]++;
-            p->activescbs++;
-          }
-          prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-          prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          aic_dev->active_cmds++;
+          p->activescbs++;
         }
-      }
-      if ( j > (p->scb_data->numscbs + 1) )
-      {
-        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-          printk(WARN_LEAD "Yikes!! There's a loop in the "
-            "delayed_scbs queue!\n", p->host_no, channel, i, lun);
-        scbq_init(&p->delayed_scbs[i]);
-      }
-      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
-            time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
-      {
-        mod_timer(&p->dev_timer, p->dev_expires[i]);
-        p->dev_timer_active |= (0x01 << MAX_TARGETS);
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
   }
@@ -3502,41 +3222,24 @@
   {
     struct aic7xxx_scb *scbp, *prev_scbp;
 
-    j = 0; 
     prev_scbp = NULL; 
     scbp = p->waiting_scbs.head;
-    while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
+    while (scbp != NULL)
     {
       prev_scbp = scbp;
       scbp = scbp->q_next;
-      if ( prev_scbp == scbp )
-      {
-        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-          printk(WARN_LEAD "Yikes!! scb->q_next == scb "
-            "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
-        scbp = NULL;
-        prev_scbp->q_next = NULL;
-        p->waiting_scbs.tail = prev_scbp;
-      }
       if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
       {
         scbq_remove(&p->waiting_scbs, prev_scbp);
         if (prev_scbp->flags & SCB_WAITINGQ)
         {
-          p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
+          AIC_DEV(prev_scbp->cmd)->active_cmds++;
           p->activescbs++;
         }
         prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
         prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
-    if ( j > (p->scb_data->numscbs + 1) )
-    {
-      if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-        printk(WARN_LEAD "Yikes!! There's a loop in the "
-          "waiting_scbs queue!\n", p->host_no, channel, target, lun);
-      scbq_init(&p->waiting_scbs);
-    }
   }
 
 
@@ -3551,8 +3254,7 @@
 
     next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
-    j = 0;
-    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
+    while (next != SCB_LIST_NULL)
     {
       aic_outb(p, next, SCBPTR);
       scb_index = aic_inb(p, SCB_TAG);
@@ -3576,7 +3278,7 @@
           next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
           if (scbp->flags & SCB_WAITINGQ)
           {
-            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+            AIC_DEV(scbp->cmd)->active_cmds++;
             p->activescbs++;
           }
           scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
@@ -3600,12 +3302,6 @@
         }
       }
     }
-    if ( j > (p->scb_data->maxscbs + 1) )
-    {
-      printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
-        "selection list!\n", p->host_no, channel, target, lun);
-      init_lists = TRUE;
-    }
   }
 
   /*
@@ -3621,8 +3317,7 @@
 
     next = aic_inb(p, DISCONNECTED_SCBH);
     prev = SCB_LIST_NULL;
-    j = 0;
-    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
+    while (next != SCB_LIST_NULL)
     {
       aic_outb(p, next, SCBPTR);
       scb_index = aic_inb(p, SCB_TAG);
@@ -3641,7 +3336,7 @@
           next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
           if (scbp->flags & SCB_WAITINGQ)
           {
-            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+            AIC_DEV(scbp->cmd)->active_cmds++;
             p->activescbs++;
           }
           scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
@@ -3655,12 +3350,6 @@
         }
       }
     }
-    if ( j > (p->scb_data->maxscbs + 1) )
-    {
-      printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
-        p->host_no, channel, target, lun);
-      init_lists = TRUE;
-    }
   }
 
   /*
@@ -3671,16 +3360,8 @@
   {
     unsigned char next;
 
-    j = 0;
     next = aic_inb(p, FREE_SCBH);
-    if ( (next >= p->scb_data->maxhscbs) && (next != SCB_LIST_NULL) )
-    {
-      printk(WARN_LEAD "Bogus FREE_SCBH!.\n", p->host_no, channel,
-        target, lun);
-      init_lists = TRUE;
-      next = SCB_LIST_NULL;
-    }
-    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
+    while (next != SCB_LIST_NULL)
     {
       aic_outb(p, next, SCBPTR);
       if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs)
@@ -3697,12 +3378,6 @@
         next = aic_inb(p, SCB_NEXT);
       }
     }
-    if ( j > (p->scb_data->maxscbs + 1) )
-    {
-      printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
-        p->host_no, channel, target, lun);
-      init_lists = TRUE;
-    }
   }
 
   /*
@@ -3763,8 +3438,8 @@
       if (scbp->flags & SCB_WAITINGQ)
       {
         scbq_remove(&p->waiting_scbs, scbp);
-        scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
-        p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+        scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp);
+        AIC_DEV(scbp->cmd)->active_cmds++;
         p->activescbs++;
       }
       scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
@@ -3859,8 +3534,6 @@
 
   if (channel == 1)
   {
-    p->needsdtr |= (p->needsdtr_copy & 0xFF00);
-    p->dtr_pending &= 0x00FF;
     offset_min = 8;
     offset_max = 16;
   }
@@ -3869,17 +3542,11 @@
     if (p->features & AHC_TWIN)
     {
       /* Channel A */
-      p->needsdtr |= (p->needsdtr_copy & 0x00FF);
-      p->dtr_pending &= 0xFF00;
       offset_min = 0;
       offset_max = 8;
     }
     else
     {
-      p->needppr = p->needppr_copy;
-      p->needsdtr = p->needsdtr_copy;
-      p->needwdtr = p->needwdtr_copy;
-      p->dtr_pending = 0x0;
       offset_min = 0;
       if (p->features & AHC_WIDE)
       {
@@ -3982,11 +3649,8 @@
 aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
-  int tindex;
+  struct aic_dev_data *aic_dev;
   int sent;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
 
 
   if (p->waiting_scbs.head == NULL)
@@ -3997,25 +3661,21 @@
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  DRIVER_LOCK
   while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
   {
-    tindex = TARGET_INDEX(scb->cmd);
-    if ( !scb->tag_action && (p->tagenable & (1<<tindex)) )
+    aic_dev = scb->cmd->device->hostdata;
+    if ( !scb->tag_action )
     {
-      p->dev_temp_queue_depth[tindex] = 1;
+      aic_dev->temp_q_depth = 1;
     }
-    if ( (p->dev_active_cmds[tindex] >=
-          p->dev_temp_queue_depth[tindex]) ||
-         (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) ||
-         (p->flags & AHC_RESET_DELAY) )
+    if ( aic_dev->active_cmds >= aic_dev->temp_q_depth)
     {
-      scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+      scbq_insert_tail(&aic_dev->delayed_scbs, scb);
     }
     else
     {
         scb->flags &= ~SCB_WAITINGQ;
-        p->dev_active_cmds[tindex]++;
+        aic_dev->active_cmds++;
         p->activescbs++;
         if ( !(scb->tag_action) )
         {
@@ -4038,7 +3698,6 @@
     if (p->activescbs > p->max_activescbs)
       p->max_activescbs = p->activescbs;
   }
-  DRIVER_UNLOCK
 }
 
 #ifdef CONFIG_PCI
@@ -4099,81 +3758,6 @@
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_timer
- *
- * Description:
- *   Take expired extries off of delayed queues and place on waiting queue
- *   then run waiting queue to start commands.
- ***************************************************************************/
-static void
-aic7xxx_timer(struct aic7xxx_host *p)
-{
-  int i, j;
-  unsigned long cpu_flags = 0;
-  struct aic7xxx_scb *scb;
-
-  spin_lock_irqsave(p->host->host_lock, cpu_flags);
-  p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
-  if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
-       time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
-  {
-    p->flags &= ~AHC_RESET_DELAY;
-    p->dev_timer_active &= ~(0x01 << p->scsi_id);
-  }
-  for(i=0; i<MAX_TARGETS; i++)
-  {
-    if ( (i != p->scsi_id) &&
-         (p->dev_timer_active & (0x01 << i)) &&
-         time_after_eq(jiffies, p->dev_expires[i]) )
-    {
-      p->dev_timer_active &= ~(0x01 << i);
-      p->dev_flags[i] &= ~(DEVICE_RESET_DELAY|DEVICE_WAS_BUSY);
-      p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
-      j = 0;
-      while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
-              (j++ < p->scb_data->numscbs) )
-      {
-        scbq_insert_tail(&p->waiting_scbs, scb);
-      }
-      if (j == p->scb_data->numscbs)
-      {
-        printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n",
-          p->host_no, 0, i, -1);
-        scbq_init(&p->delayed_scbs[i]);
-        scbq_init(&p->waiting_scbs);
-        /*
-         * Well, things are screwed now, wait for a reset to clean the junk
-         * out.
-         */
-      }
-    }
-    else if ( p->dev_timer_active & (0x01 << i) )
-    {
-      if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
-      {
-        if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
-        {
-          p->dev_timer.expires = p->dev_expires[i];
-        }
-      }
-      else
-      {
-        p->dev_timer.expires = p->dev_expires[i];
-        p->dev_timer_active |= (0x01 << MAX_TARGETS);
-      }
-    }
-  }
-  if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
-  {
-    add_timer(&p->dev_timer);
-  }
-
-  aic7xxx_run_waiting_queues(p);
-  spin_unlock_irqrestore(p->host->host_lock, cpu_flags);
-}
-
-/*+F*************************************************************************
- * Function:
  *   aic7xxx_construct_ppr
  *
  * Description:
@@ -4183,16 +3767,14 @@
 static void
 aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  int tindex = TARGET_INDEX(scb->cmd);
-
   p->msg_buf[p->msg_index++] = MSG_EXTENDED;
   p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
   p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.period;
   p->msg_buf[p->msg_index++] = 0;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.offset;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.width;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.options;
   p->msg_len += 8;
 }
 
@@ -4290,11 +3872,7 @@
        * the mid layer didn't check residual data counts to see if the
        * command needs retried.
        */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
       cmd->resid = scb->sg_length - actual;
-#else
-      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-#endif
       aic7xxx_status(cmd) = hscb->target_status;
     }
   }
@@ -4319,19 +3897,13 @@
 static void
 aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
 {
-  unsigned short targ_mask;
   unsigned char tindex = target;
 
   tindex |= ((channel & 0x01) << 3);
 
-  targ_mask = (0x01 << tindex);
   /*
    * Go back to async/narrow transfers and renegotiate.
    */
-  p->needppr |= (p->needppr_copy & targ_mask);
-  p->needsdtr |= (p->needsdtr_copy & targ_mask);
-  p->needwdtr |= (p->needwdtr_copy & targ_mask);
-  p->dtr_pending &= ~targ_mask;
   aic_outb(p, 0, TARG_SCSIRATE + tindex);
   if (p->features & AHC_ULTRA2)
     aic_outb(p, 0, TARG_OFFSET + tindex);
@@ -4353,6 +3925,7 @@
 aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 {
   struct aic7xxx_scb *scb;
+  struct aic_dev_data *aic_dev;
   unsigned short target_mask;
   unsigned char target, lun, tindex;
   unsigned char queue_flag = FALSE;
@@ -4472,6 +4045,7 @@
 
         scb_index = aic_inb(p, SCB_TAG);
         scb = p->scb_data->scb_array[scb_index];
+	aic_dev = AIC_DEV(scb->cmd);
         last_msg = aic_inb(p, LAST_MSG);
 
         if ( (last_msg == MSG_IDENTIFYFLAG) &&
@@ -4486,7 +4060,8 @@
              * disable ordered tag commands and go on with life just like
              * normal.
              */
-            p->orderedtag &= ~target_mask;
+	    scsi_adjust_queue_depth(scb->cmd->device, MSG_SIMPLE_TAG,
+			    scb->cmd->device->new_queue_depth);
             scb->tag_action = MSG_SIMPLE_Q_TAG;
             scb->hscb->control &= ~SCB_TAG_TYPE;
             scb->hscb->control |= MSG_SIMPLE_Q_TAG;
@@ -4501,21 +4076,15 @@
           }
           else if (scb->tag_action == MSG_SIMPLE_Q_TAG)
           {
-            unsigned char i, reset = 0;
+            unsigned char i;
             struct aic7xxx_scb *scbp;
             int old_verbose;
             /*
-             * Hmmmm....the device is flaking out on tagged commands.  The
-             * bad thing is that we already have tagged commands enabled in
-             * the device struct in the mid level code.  We also have a queue
-             * set according to the tagged queue depth.  Gonna have to live
-             * with it by controlling our queue depth internally and making
-             * sure we don't set the tagged command flag any more.
+             * Hmmmm....the device is flaking out on tagged commands.
              */
-            p->tagenable &= ~target_mask;
-            p->orderedtag &= ~target_mask;
-            p->dev_max_queue_depth[tindex] =
-               p->dev_temp_queue_depth[tindex] = 1;
+	    scsi_adjust_queue_depth(scb->cmd->device, 0 /* untagged */,
+			    p->host->cmd_per_lun);
+            aic_dev->max_q_depth = aic_dev->temp_q_depth = 1;
             /*
              * We set this command up as a bus device reset.  However, we have
              * to clear the tag type as it's causing us problems.  We shouldnt
@@ -4533,7 +4102,7 @@
 
             old_verbose = aic7xxx_verbose;
             aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
-            for (i=0; i!=p->scb_data->numscbs; i++)
+            for (i=0; i < p->scb_data->numscbs; i++)
             {
               scbp = p->scb_data->scb_array[i];
               if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
@@ -4541,11 +4110,10 @@
                 if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
                 {
                   aic7xxx_reset_device(p, target, channel, lun, i);
-                  reset++;
                 }
-                aic7xxx_run_done_queue(p, TRUE);
               }
             }
+            aic7xxx_run_done_queue(p, TRUE);
             aic7xxx_verbose = old_verbose;
             /*
              * Wait until after the for loop to set the busy index since
@@ -4569,38 +4137,35 @@
            * a parity error during msg_out phase to signal that they don't
            * like our settings.
            */
-          p->needppr &= ~target_mask;
-          p->needppr_copy &= ~target_mask;
+          aic_dev->needppr = aic_dev->needppr_copy = 0;
           aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
-            (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+            (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE), aic_dev);
           aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-          p->transinfo[tindex].goal_options = 0;
-          p->dtr_pending &= ~target_mask;
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			       aic_dev);
+          aic_dev->goal.options = aic_dev->dtr_pending = 0;
           scb->flags &= ~SCB_MSGOUT_BITS;
           if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Device is rejecting PPR messages, falling "
               "back.\n", p->host_no, channel, target, lun);
           }
-          if ( p->transinfo[tindex].goal_width )
+          if ( aic_dev->goal.width )
           {
-            p->needwdtr |= target_mask;
-            p->needwdtr_copy |= target_mask;
-            p->dtr_pending |= target_mask;
+            aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
+            aic_dev->dtr_pending = 1;
             scb->flags |= SCB_MSGOUT_WDTR;
           }
-          if ( p->transinfo[tindex].goal_offset )
+          if ( aic_dev->goal.offset )
           {
-            p->needsdtr |= target_mask;
-            p->needsdtr_copy |= target_mask;
-            if( !(p->dtr_pending & target_mask) )
+            aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+            if( !aic_dev->dtr_pending )
             {
-              p->dtr_pending |= target_mask;
+              aic_dev->dtr_pending = 1;
               scb->flags |= SCB_MSGOUT_SDTR;
             }
           }
-          if ( p->dtr_pending & target_mask )
+          if ( aic_dev->dtr_pending )
           {
             aic_outb(p, HOST_MSG, MSG_OUT);
             aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
@@ -4611,30 +4176,29 @@
           /*
            * note 8bit xfers and clear flag
            */
-          p->needwdtr &= ~target_mask;
-          p->needwdtr_copy &= ~target_mask;
+          aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
           scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
-            (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
+            (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR), aic_dev);
           aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			       aic_dev);
           if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Device is rejecting WDTR messages, using "
               "narrow transfers.\n", p->host_no, channel, target, lun);
           }
-          p->needsdtr |= (p->needsdtr_copy & target_mask);
+          aic_dev->needsdtr = aic_dev->needsdtr_copy;
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
          /*
           * note asynch xfers and clear flag
           */
-          p->needsdtr &= ~target_mask;
-          p->needsdtr_copy &= ~target_mask;
+          aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
           scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-            (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
+            (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL), aic_dev);
           if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Device is rejecting SDTR messages, using "
@@ -4688,6 +4252,7 @@
         else
         {
           cmd = scb->cmd;
+	  aic_dev = AIC_DEV(scb->cmd);
           hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
           aic7xxx_status(cmd) = hscb->target_status;
 
@@ -4780,14 +4345,17 @@
               unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
               /*
                * We have to look three places for queued commands:
-               *  1: QINFIFO
-               *  2: p->waiting_scbs queue
+               *  1: p->waiting_scbs queue
+               *  2: QINFIFO
                *  3: WAITING_SCBS list on card (for commands that are started
                *     but haven't yet made it to the device)
+	       *
+	       * Of special note here is that commands on 2 or 3 above will
+	       * have already been marked as active, while commands on 1 will
+	       * not.  The aic7xxx_done() function will want to unmark them
+	       * from active, so any commands we pull off of 1 need to
+	       * up the active count.
                */
-              aic7xxx_search_qinfifo(p, target, channel, lun,
-                SCB_LIST_NULL, 0, TRUE,
-                &p->delayed_scbs[tindex]);
               next_scbp = p->waiting_scbs.head;
               while ( next_scbp != NULL )
               {
@@ -4797,10 +4365,14 @@
                      SCB_LIST_NULL) )
                 {
                   scbq_remove(&p->waiting_scbs, prev_scbp);
-                  scbq_insert_tail(&p->delayed_scbs[tindex],
-                    prev_scbp);
+		  scb->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL;
+		  p->activescbs++;
+		  aic_dev->active_cmds++;
                 }
               }
+              aic7xxx_search_qinfifo(p, target, channel, lun,
+                SCB_LIST_NULL, SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL,
+	       	FALSE, NULL);
               next_scbp = NULL;
               active_hscb = aic_inb(p, SCBPTR);
               prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
@@ -4815,18 +4387,7 @@
                   if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
                       SCB_LIST_NULL) )
                   {
-                    if (next_scbp->flags & SCB_WAITINGQ)
-                    {
-                      p->dev_active_cmds[tindex]++;
-                      p->activescbs--;
-                      scbq_remove(&p->delayed_scbs[tindex], next_scbp);
-                      scbq_remove(&p->waiting_scbs, next_scbp);
-                    }
-                    scbq_insert_head(&p->delayed_scbs[tindex],
-                      next_scbp);
-                    next_scbp->flags |= SCB_WAITINGQ;
-                    p->dev_active_cmds[tindex]--;
-                    p->activescbs--;
+		    next_scbp->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL;
                     next_hscb = aic_inb(p, SCB_NEXT);
                     aic_outb(p, 0, SCB_CONTROL);
                     aic_outb(p, SCB_LIST_NULL, SCB_TAG);
@@ -4856,39 +4417,8 @@
                 } /* scb_index >= p->scb_data->numscbs */
               }
               aic_outb(p, active_hscb, SCBPTR);
-              if (scb->flags & SCB_WAITINGQ)
-              {
-                scbq_remove(&p->delayed_scbs[tindex], scb);
-                scbq_remove(&p->waiting_scbs, scb);
-                p->dev_active_cmds[tindex]++;
-                p->activescbs++;
-              }
-              scbq_insert_head(&p->delayed_scbs[tindex], scb);
-              p->dev_active_cmds[tindex]--;
-              p->activescbs--;
-              scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+	      aic7xxx_run_done_queue(p, FALSE);
                   
-              if ( !(p->dev_timer_active & (0x01 << tindex)) ) 
-              {
-                p->dev_timer_active |= (0x01 << tindex);
-                if ( p->dev_active_cmds[tindex] )
-                {
-                  p->dev_expires[tindex] = jiffies + HZ;
-                }
-                else
-                {
-                  p->dev_expires[tindex] = jiffies + (HZ / 10);
-                }
-                if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) )
-                {
-                  p->dev_timer.expires = p->dev_expires[tindex];
-                  p->dev_timer_active |= (0x01 << MAX_TARGETS);
-                  add_timer(&p->dev_timer);
-                }
-                else if ( time_after_eq(p->dev_timer.expires,
-                                        p->dev_expires[tindex]) )
-                  mod_timer(&p->dev_timer, p->dev_expires[tindex]);
-              }
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
               if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
                   (aic7xxx_verbose > 0xffff) )
@@ -4896,13 +4426,12 @@
                 if (queue_flag)
                   printk(INFO_LEAD "Queue full received; queue depth %d, "
                     "active %d\n", p->host_no, CTL_OF_SCB(scb),
-                    p->dev_max_queue_depth[tindex],
-                    p->dev_active_cmds[tindex]);
+                    aic_dev->max_q_depth, aic_dev->active_cmds);
                 else
                   printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
-
               }
 #endif
+#if 0
               if (queue_flag)
               {
                 if ( p->dev_last_queue_full[tindex] !=
@@ -4919,15 +4448,29 @@
                 if ( (p->dev_last_queue_full_count[tindex] > 14) &&
                      (p->dev_active_cmds[tindex] > 4) )
                 {
+		  int diff, lun;
+		  if (p->dev_active_cmds[tindex] > p->dev_lun_queue_depth[tindex])
+		    /* We don't know what to do here, so bail. */
+		    break;
                   if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
                     printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
                       CTL_OF_SCB(scb), p->dev_active_cmds[tindex]);
-                  p->dev_max_queue_depth[tindex] = 
-                      p->dev_active_cmds[tindex];
+		  diff = p->dev_lun_queue_depth[tindex] -
+			 p->dev_active_cmds[tindex];
+		  p->dev_lun_queue_depth[tindex] -= diff;
+		  for(lun = 0; lun < p->host->max_lun; lun++)
+		  {
+		    if(p->Scsi_Dev[tindex][lun] != NULL)
+		    {
+		      p->dev_max_queue_depth[tindex] -= diff;
+		      scsi_adjust_queue_depth(p->Scsi_Dev[tindex][lun], 1,
+				              p->dev_lun_queue_depth[tindex]);
+		      if(p->dev_temp_queue_depth[tindex] > p->dev_max_queue_depth[tindex])
+		        p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+		    }
+		  }
                   p->dev_last_queue_full[tindex] = 0;
                   p->dev_last_queue_full_count[tindex] = 0;
-                  p->dev_temp_queue_depth[tindex] = 
-                    p->dev_active_cmds[tindex];
                 }
                 else if (p->dev_active_cmds[tindex] == 0)
                 {
@@ -4945,11 +4488,12 @@
                 }
                 else
                 {
-                  p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+                  aic_dev->flags[tindex] |= DEVICE_WAS_BUSY;
                   p->dev_temp_queue_depth[tindex] = 
                     p->dev_active_cmds[tindex];
                 }
               }
+#endif
               break;
             }
             
@@ -4974,6 +4518,7 @@
         scb_index = aic_inb(p, SCB_TAG);
         msg_out = aic_inb(p, MSG_OUT);
         scb = p->scb_data->scb_array[scb_index];
+	aic_dev = AIC_DEV(scb->cmd);
         p->msg_index = p->msg_len = 0;
         /*
          * This SCB had a MK_MESSAGE set in its control byte informing
@@ -5019,10 +4564,10 @@
           {
             printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
                    p->host_no, CTL_OF_SCB(scb),
-                   p->transinfo[tindex].goal_period,
-                   p->transinfo[tindex].goal_offset,
-                   p->transinfo[tindex].goal_width,
-                   p->transinfo[tindex].goal_options);
+                   aic_dev->goal.period,
+                   aic_dev->goal.offset,
+                   aic_dev->goal.width,
+                   aic_dev->goal.options);
           }
           aic7xxx_construct_ppr(p, scb);
         }
@@ -5033,7 +4578,7 @@
             printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
                    CTL_OF_SCB(scb));
           }
-          aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width);
+          aic7xxx_construct_wdtr(p, aic_dev->goal.width);
         }
         else if (scb->flags & SCB_MSGOUT_SDTR)
         {
@@ -5063,16 +4608,15 @@
           {
             max_sync = AHC_SYNCRATE_FAST;
           }
-          period = p->transinfo[tindex].goal_period;
+          period = aic_dev->goal.period;
           aic7xxx_find_syncrate(p, &period, max_sync, &options);
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
                    CTL_OF_SCB(scb), period,
-                   p->transinfo[tindex].goal_offset);
+                   aic_dev->goal.offset);
           }
-          aic7xxx_construct_sdtr(p, period,
-            p->transinfo[tindex].goal_offset);
+          aic7xxx_construct_sdtr(p, period, aic_dev->goal.offset);
         }
         else 
         {
@@ -5409,12 +4953,14 @@
   unsigned char trans_options, new_trans_options;
   unsigned int period, new_period, offset, new_offset, maxsync;
   struct aic7xxx_syncrate *syncrate;
+  struct aic_dev_data *aic_dev;
 
   target = scb->cmd->target;
   channel = scb->cmd->channel;
   lun = scb->cmd->lun;
   reply = reject = done = FALSE;
   tindex = TARGET_INDEX(scb->cmd);
+  aic_dev = AIC_DEV(scb->cmd);
   target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
   target_mask = (0x01 << tindex);
 
@@ -5504,44 +5050,43 @@
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
         {
-          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
+          if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
           {
             /*
              * We shouldn't get here unless this is a narrow drive, wide
              * devices should trigger this same section of code in the WDTR
              * handler first instead.
              */
-            p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
-            p->transinfo[tindex].goal_options = 0;
-            if(p->transinfo[tindex].user_offset)
+            aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT;
+            aic_dev->goal.options = 0;
+            if(p->user[tindex].offset)
             {
-              p->needsdtr_copy |= target_mask;
-              p->transinfo[tindex].goal_period =
-                MAX(10,p->transinfo[tindex].user_period);
+              aic_dev->needsdtr_copy = 1;
+              aic_dev->goal.period = MAX(10,p->user[tindex].period);
               if(p->features & AHC_ULTRA2)
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+                aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
               }
               else
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+                aic_dev->goal.offset = MAX_OFFSET_8BIT;
               }
             }
             else
             {
-              p->needsdtr_copy &= ~target_mask;
-              p->transinfo[tindex].goal_period = 255;
-              p->transinfo[tindex].goal_offset = 0;
+              aic_dev->needsdtr_copy = 0;
+              aic_dev->goal.period = 255;
+              aic_dev->goal.offset = 0;
             }
-            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+            aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
           }
-          else if ((p->needsdtr_copy & target_mask) == 0)
+          else if (aic_dev->needsdtr_copy == 0)
           {
             /*
              * This is a preemptive message from the target, we've already
              * scanned this target and set our options for it, and we
-             * don't need a WDTR with this target (for whatever reason),
-             * so reject this incoming WDTR
+             * don't need a SDTR with this target (for whatever reason),
+             * so reject this incoming SDTR
              */
             reject = TRUE;
             break;
@@ -5561,8 +5106,8 @@
            * the device isn't allowed to send values greater than the ones
            * we first sent to it.
            */
-          new_period = MAX(period, p->transinfo[tindex].goal_period);
-          new_offset = MIN(offset, p->transinfo[tindex].goal_offset);
+          new_period = MAX(period, aic_dev->goal.period);
+          new_offset = MIN(offset, aic_dev->goal.offset);
         }
  
         /*
@@ -5579,7 +5124,7 @@
          */
         if ((new_offset == 0) && (new_offset != offset))
         {
-          p->needsdtr_copy &= ~target_mask;
+          aic_dev->needsdtr_copy = 0;
           reply = TRUE;
         }
         
@@ -5596,7 +5141,8 @@
            */
           aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
                                new_offset, trans_options,
-                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			       aic_dev);
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_SDTR;
           aic_outb(p, HOST_MSG, MSG_OUT);
@@ -5606,8 +5152,8 @@
         {
           aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
                                new_offset, trans_options,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-          p->needsdtr &= ~target_mask;
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
+          aic_dev->needsdtr = 0;
         }
         done = TRUE;
         break;
@@ -5637,7 +5183,7 @@
             {
               reject = TRUE;
               if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                   ((aic_dev->flags & DEVICE_PRINT_DTR) ||
                     (aic7xxx_verbose > 0xffff)) )
               {
                 printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
@@ -5646,8 +5192,8 @@
             } /* We fall through on purpose */
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
-              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
-              p->needwdtr_copy &= ~target_mask;
+              aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic_dev->needwdtr_copy &= ~target_mask;
               break;
             }
             case MSG_EXT_WDTR_BUS_16_BIT:
@@ -5655,56 +5201,55 @@
               break;
             }
           }
-          p->needwdtr &= ~target_mask;
+          aic_dev->needwdtr = 0;
           aic7xxx_set_width(p, target, channel, lun, new_bus_width,
-                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
         }
         else
         {
-          if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
+          if ( !(aic_dev->flags & DEVICE_DTR_SCANNED) )
           {
             /* 
              * Well, we now know the WDTR and SYNC caps of this device since
              * it contacted us first, mark it as such and copy the user stuff
              * over to the goal stuff.
              */
-            if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width )
+            if( (p->features & AHC_WIDE) && p->user[tindex].width )
             {
-              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
-              p->needwdtr_copy |= target_mask;
+              aic_dev->goal.width = MSG_EXT_WDTR_BUS_16_BIT;
+              aic_dev->needwdtr_copy = 1;
             }
             
             /*
              * Devices that support DT transfers don't start WDTR requests
              */
-            p->transinfo[tindex].goal_options = 0;
+            aic_dev->goal.options = 0;
 
-            if(p->transinfo[tindex].user_offset)
+            if(p->user[tindex].offset)
             {
-              p->needsdtr_copy |= target_mask;
-              p->transinfo[tindex].goal_period =
-                MAX(10,p->transinfo[tindex].user_period);
+              aic_dev->needsdtr_copy = 1;
+              aic_dev->goal.period = MAX(10,p->user[tindex].period);
               if(p->features & AHC_ULTRA2)
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+                aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].goal_width )
+              else if( aic_dev->goal.width )
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+                aic_dev->goal.offset = MAX_OFFSET_16BIT;
               }
               else
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+                aic_dev->goal.offset = MAX_OFFSET_8BIT;
               }
             } else {
-              p->needsdtr_copy &= ~target_mask;
-              p->transinfo[tindex].goal_period = 255;
-              p->transinfo[tindex].goal_offset = 0;
+              aic_dev->needsdtr_copy = 0;
+              aic_dev->goal.period = 255;
+              aic_dev->goal.offset = 0;
             }
             
-            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+            aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
           }
-          else if ((p->needwdtr_copy & target_mask) == 0)
+          else if (aic_dev->needwdtr_copy == 0)
           {
             /*
              * This is a preemptive message from the target, we've already
@@ -5729,8 +5274,7 @@
             case MSG_EXT_WDTR_BUS_16_BIT:
             {
               if ( (p->features & AHC_WIDE) &&
-                   (p->transinfo[tindex].goal_width ==
-                    MSG_EXT_WDTR_BUS_16_BIT) )
+                   (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) )
               {
                 new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
                 break;
@@ -5739,21 +5283,21 @@
             default:
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
-              p->needwdtr_copy &= ~target_mask;
+              aic_dev->needwdtr_copy = 0;
               new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
               break;
             }
           }
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_WDTR;
-          p->needwdtr &= ~target_mask;
-          if((p->dtr_pending & target_mask) == 0)
+          aic_dev->needwdtr = 0;
+          if(aic_dev->dtr_pending == 0)
           {
             /* there is no other command with SCB_DTR_SCB already set that will
              * trigger the release of the dtr_pending bit.  Both set the bit
              * and set scb->flags |= SCB_DTR_SCB
              */
-            p->dtr_pending |= target_mask;
+            aic_dev->dtr_pending = 1;
             scb->flags |= SCB_DTR_SCB;
           }
           aic_outb(p, HOST_MSG, MSG_OUT);
@@ -5764,7 +5308,8 @@
            * goal settings as its guidelines.
            */
           aic7xxx_set_width(p, target, channel, lun, new_bus_width,
-                          AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                          AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			  aic_dev);
         }
         
         /*
@@ -5775,8 +5320,9 @@
          * of needstr.
          */
         aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-        p->needsdtr |= (p->needsdtr_copy & target_mask);
+                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			     aic_dev);
+        aic_dev->needsdtr = aic_dev->needsdtr_copy;
         done = TRUE;
         break;
       }
@@ -5816,19 +5362,16 @@
              (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
         { 
           /* Have we scanned the device yet? */
-          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
+          if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
           {
             /* The device is electing to use PPR messages, so we will too until
              * we know better */
-            p->needppr |= target_mask;
-            p->needppr_copy |= target_mask;
-            p->needsdtr &= ~target_mask;
-            p->needsdtr_copy &= ~target_mask;
-            p->needwdtr &= ~target_mask;
-            p->needwdtr_copy &= ~target_mask;
+            aic_dev->needppr = aic_dev->needppr_copy = 1;
+            aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+            aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
           
             /* We know the device is SCSI-3 compliant due to PPR */
-            p->dev_flags[tindex] |= DEVICE_SCSI_3;
+            aic_dev->flags |= DEVICE_SCSI_3;
           
             /*
              * Not only is the device starting this up, but it also hasn't
@@ -5838,38 +5381,35 @@
              * if we didn't find a SEEPROM, we stuffed default values into
              * the user settings anyway, so use those in all cases.
              */
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            if(p->transinfo[tindex].user_offset)
+            aic_dev->goal.width = p->user[tindex].width;
+            if(p->user[tindex].offset)
             {
-              p->transinfo[tindex].goal_period =
-                p->transinfo[tindex].user_period;
-              p->transinfo[tindex].goal_options =
-                p->transinfo[tindex].user_options;
+              aic_dev->goal.period = p->user[tindex].period;
+              aic_dev->goal.options = p->user[tindex].options;
               if(p->features & AHC_ULTRA2)
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+                aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].goal_width &&
+              else if( aic_dev->goal.width &&
                        (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
                        p->features & AHC_WIDE )
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+                aic_dev->goal.offset = MAX_OFFSET_16BIT;
               }
               else
               {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+                aic_dev->goal.offset = MAX_OFFSET_8BIT;
               }
             }
             else
             {
-              p->transinfo[tindex].goal_period = 255;
-              p->transinfo[tindex].goal_offset = 0;
-              p->transinfo[tindex].goal_options = 0;
+              aic_dev->goal.period = 255;
+              aic_dev->goal.offset = 0;
+              aic_dev->goal.options = 0;
             }
-            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+            aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
           }
-          else if ((p->needppr_copy & target_mask) == 0)
+          else if (aic_dev->needppr_copy == 0)
           {
             /*
              * This is a preemptive message from the target, we've already
@@ -5896,8 +5436,8 @@
         {
           case MSG_EXT_WDTR_BUS_16_BIT:
           {
-            if ( (p->transinfo[tindex].goal_width ==
-                  MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE)
+            if ( (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) &&
+			    p->features & AHC_WIDE)
             {
               break;
             }
@@ -5905,7 +5445,7 @@
           default:
           {
             if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                 ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                 ((aic_dev->flags & DEVICE_PRINT_DTR) ||
                   (aic7xxx_verbose > 0xffff)) )
             {
               reply = TRUE;
@@ -5933,24 +5473,26 @@
            * goal settings as its guidelines.
            */
           aic7xxx_set_width(p, target, channel, lun, new_bus_width,
-                            AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                            AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			    aic_dev);
           syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
                                            &new_trans_options);
           aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
           aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
                                new_offset, new_trans_options,
-                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			       aic_dev);
         }
         else
         {
           aic7xxx_set_width(p, target, channel, lun, new_bus_width,
-                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
           syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
                                            &new_trans_options);
           aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
           aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
                                new_offset, new_trans_options,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
         }
 
         /*
@@ -5962,17 +5504,14 @@
          */
         if(new_trans_options == 0)
         {
-          p->needppr &= ~target_mask;
-          p->needppr_copy &= ~target_mask;
+          aic_dev->needppr = aic_dev->needppr_copy = 0;
           if(new_offset)
           {
-            p->needsdtr |= target_mask;
-            p->needsdtr_copy |= target_mask;
+            aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
           }
           if (new_bus_width)
           {
-            p->needwdtr |= target_mask;
-            p->needwdtr_copy |= target_mask;
+            aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
           }
         }
 
@@ -5995,7 +5534,7 @@
         }
         else
         {
-          p->needppr &= ~target_mask;
+          aic_dev->needppr = 0;
         }
         done = TRUE;
         break;
@@ -6150,6 +5689,7 @@
   unsigned char scb_index;
   unsigned char status;
   struct aic7xxx_scb *scb;
+  struct aic_dev_data *aic_dev;
 
   scb_index = aic_inb(p, SCB_TAG);
   status = aic_inb(p, SSTAT1);
@@ -6432,7 +5972,6 @@
     unsigned char mesg_out = MSG_NOOP;
     unsigned char lastphase = aic_inb(p, LASTPHASE);
     unsigned char sstat2 = aic_inb(p, SSTAT2);
-    unsigned char tindex = TARGET_INDEX(scb->cmd);
 
     cmd = scb->cmd;
     switch (lastphase)
@@ -6505,33 +6044,33 @@
        * a parity error during msg_out phase to signal that they don't
        * like our settings.
        */
-      p->needppr &= ~(1 << tindex);
-      p->needppr_copy &= ~(1 << tindex);
+      aic_dev = AIC_DEV(scb->cmd);
+      aic_dev->needppr = aic_dev->needppr_copy = 0;
       aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun,
                         MSG_EXT_WDTR_BUS_8_BIT,
-                        (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+                        (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE),
+			aic_dev);
       aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
-                           0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-      p->transinfo[tindex].goal_options = 0;
+                           0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			   aic_dev);
+      aic_dev->goal.options = 0;
       scb->flags &= ~SCB_MSGOUT_BITS;
       if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
       {
         printk(INFO_LEAD "parity error during PPR message, reverting "
                "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb));
       }
-      if ( p->transinfo[tindex].goal_width )
+      if ( aic_dev->goal.width )
       {
-        p->needwdtr |= (1 << tindex);
-        p->needwdtr_copy |= (1 << tindex);
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
       }
-      if ( p->transinfo[tindex].goal_offset )
+      if ( aic_dev->goal.offset )
       {
-        if( p->transinfo[tindex].goal_period <= 9 )
+        if( aic_dev->goal.period <= 9 )
         {
-          p->transinfo[tindex].goal_period = 10;
+          aic_dev->goal.period = 10;
         }
-        p->needsdtr |= (1 << tindex);
-        p->needsdtr_copy |= (1 << tindex);
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
       }
       scb = NULL;
     }
@@ -6736,6 +6275,7 @@
 aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb = NULL;
+  struct aic_dev_data *aic_dev;
   Scsi_Cmnd *cmd;
   unsigned char scb_index, tindex;
 
@@ -6777,6 +6317,7 @@
       continue;
     }
     tindex = TARGET_INDEX(scb->cmd);
+    aic_dev = AIC_DEV(scb->cmd);
     if (scb->flags & SCB_QUEUED_ABORT)
     {
       pause_sequencer(p);
@@ -6809,40 +6350,18 @@
         /*
          * Signal that we need to re-negotiate things.
          */
-        p->needppr |= (p->needppr_copy & (1<<tindex));
-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+        aic_dev->needppr = aic_dev->needppr_copy;
+        aic_dev->needsdtr = aic_dev->needsdtr_copy;
+        aic_dev->needwdtr = aic_dev->needwdtr_copy;
       }
     }
-    switch (status_byte(scb->hscb->target_status))
+    cmd = scb->cmd;
+    if (scb->hscb->residual_SG_segment_count != 0)
     {
-      case QUEUE_FULL:
-      case BUSY:
-        scb->hscb->target_status = 0;
-        scb->cmd->result = 0;
-        scb->hscb->residual_SG_segment_count = 0;
-        scb->hscb->residual_data_count[0] = 0;
-        scb->hscb->residual_data_count[1] = 0;
-        scb->hscb->residual_data_count[2] = 0;
-        aic7xxx_error(scb->cmd) = DID_OK;
-        aic7xxx_status(scb->cmd) = 0;
-        /*
-         * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
-         * this command on a timer and allowing us to retry it.  Here, we
-         * just 0 out a few values so that they don't carry through to when
-         * the command finally does complete.
-         */
-        break;
-      default:
-        cmd = scb->cmd;
-        if (scb->hscb->residual_SG_segment_count != 0)
-        {
-          aic7xxx_calculate_residual(p, scb);
-        }
-        cmd->result |= (aic7xxx_error(cmd) << 16);
-        aic7xxx_done(p, scb);
-        break;
-    }      
+      aic7xxx_calculate_residual(p, scb);
+    }
+    cmd->result |= (aic7xxx_error(cmd) << 16);
+    aic7xxx_done(p, scb);
   }
 }
 
@@ -7008,6 +6527,79 @@
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_init_aic_dev
+ *
+ * Description:
+ *   Set up the initial aic_dev values from the BIOS settings and data
+ *   we got back from INQUIRY commands.
+ *-F*************************************************************************/
+static void
+aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
+{
+  struct scsi_device *sdpnt = aic_dev->SDptr;
+  unsigned char tindex;
+
+  tindex = sdpnt->id | (sdpnt->channel << 3);
+
+  scbq_init(&aic_dev->delayed_scbs);
+
+  if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
+  {
+    aic_dev->flags |= DEVICE_DTR_SCANNED;
+
+    if ( sdpnt->wdtr && (p->features & AHC_WIDE) )
+    {
+      aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
+      aic_dev->goal.width = p->user[tindex].width;
+    }
+    else
+    {
+      aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
+      pause_sequencer(p);
+      aic7xxx_set_width(p, sdpnt->id, sdpnt->channel, sdpnt->lun,
+                        MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+                                                 AHC_TRANS_GOAL |
+                                                 AHC_TRANS_CUR), aic_dev );
+      unpause_sequencer(p, FALSE);
+    }
+    if ( sdpnt->sdtr && p->user[tindex].offset )
+    {
+      aic_dev->goal.period = p->user[tindex].period;
+      aic_dev->goal.options = p->user[tindex].options;
+      if (p->features & AHC_ULTRA2)
+        aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
+      else if (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT)
+        aic_dev->goal.offset = MAX_OFFSET_16BIT;
+      else
+        aic_dev->goal.offset = MAX_OFFSET_8BIT;
+      if ( sdpnt->ppr && p->user[tindex].period <= 9 &&
+             p->user[tindex].options )
+      {
+        aic_dev->needppr = aic_dev->needppr_copy = 1;
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
+        aic_dev->flags |= DEVICE_SCSI_3;
+      }
+      else
+      {
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+        aic_dev->goal.period = MAX(10, aic_dev->goal.period);
+        aic_dev->goal.options = 0;
+      }
+    }
+    else
+    {
+      aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+      aic_dev->goal.period = 255;
+      aic_dev->goal.offset = 0;
+      aic_dev->goal.options = 0;
+    }
+    aic_dev->flags |= DEVICE_PRINT_DTR;
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_device_queue_depth
  *
  * Description:
@@ -7023,36 +6615,28 @@
  *   with queue depths for individual devices.  It also allows tagged
  *   queueing to be [en|dis]abled for a specific adapter.
  *-F*************************************************************************/
-static int
+static void
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
-  int default_depth = 3;
+  int default_depth = p->host->hostt->cmd_per_lun;
+  struct aic_dev_data *aic_dev = device->hostdata;
   unsigned char tindex;
-  unsigned short target_mask;
 
   tindex = device->id | (device->channel << 3);
-  target_mask = (1 << tindex);
 
-  if (p->dev_max_queue_depth[tindex] > 1)
-  {
-    /*
-     * We've already scanned this device, leave it alone
-     */
-    return(p->dev_max_queue_depth[tindex]);
-  }
+  if (device->simple_tags)
+    return; // We've already enabled this device
 
-  device->queue_depth = default_depth;
-  p->dev_temp_queue_depth[tindex] = 1;
-  p->dev_max_queue_depth[tindex] = 1;
-  p->tagenable &= ~target_mask;
+  aic_dev->temp_q_depth = 1;
+  aic_dev->max_q_depth = 1;
 
   if (device->tagged_supported)
   {
     int tag_enabled = TRUE;
 
     default_depth = AIC7XXX_CMDS_PER_DEVICE;
- 
-    if (!(p->discenable & target_mask))
+
+    if (!(p->discenable & (1 << tindex)))
     {
       if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
         printk(INFO_LEAD "Disconnection disabled, unable to "
@@ -7072,7 +6656,7 @@
                            " the aic7xxx.c source file.\n");
           print_warning = FALSE;
         }
-        device->queue_depth = default_depth;
+        aic_dev->max_q_depth = aic_dev->temp_q_depth = default_depth;
       }
       else
       {
@@ -7080,65 +6664,88 @@
         if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
         {
           tag_enabled = FALSE;
-          device->queue_depth = 3;  /* Tagged queueing is disabled. */
         }
         else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
-          device->queue_depth = default_depth;
+          aic_dev->max_q_depth = aic_dev->temp_q_depth = default_depth;
         }
         else
         {
-          device->queue_depth =
+          aic_dev->max_q_depth = aic_dev->temp_q_depth = 
             aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
       }
-      if ((device->tagged_queue == 0) && tag_enabled)
+      if (tag_enabled)
       {
         if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
         {
               printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
                 p->host_no, device->channel, device->id,
-                device->lun, device->queue_depth);
+                device->lun, aic_dev->max_q_depth);
         }
-        p->dev_max_queue_depth[tindex] = device->queue_depth;
-        p->dev_temp_queue_depth[tindex] = device->queue_depth;
-        p->tagenable |= target_mask;
-        p->orderedtag |= target_mask;
-        device->tagged_queue = 1;
-        device->current_tag = SCB_LIST_NULL;
+	scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth);
       }
     }
   }
-  return(p->dev_max_queue_depth[tindex]);
+  return;
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_select_queue_depth
+ *   aic7xxx_slave_detach
  *
  * Description:
- *   Sets the queue depth for each SCSI device hanging off the input
- *   host adapter.  We use a queue depth of 2 for devices that do not
- *   support tagged queueing.  If AIC7XXX_CMDS_PER_LUN is defined, we
- *   use that for tagged queueing devices; otherwise we use our own
- *   algorithm for determining the queue depth based on the maximum
- *   SCBs for the controller.
+ *   prepare for this device to go away
  *-F*************************************************************************/
-static void
-aic7xxx_select_queue_depth(struct Scsi_Host *host,
-    Scsi_Device *scsi_devs)
+void
+aic7xxx_slave_detach(Scsi_Device *sdpnt)
+{
+  struct aic_dev_data *aic_dev = sdpnt->hostdata;
+
+  list_del(&aic_dev->list);
+  sdpnt->hostdata = NULL;
+  kfree(aic_dev);
+  return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_slave_attach
+ *
+ * Description:
+ *   Configure the device we are attaching to the controller.  This is
+ *   where we get to do things like scan the INQUIRY data, set queue
+ *   depths, allocate command structs, etc.
+ *-F*************************************************************************/
+int
+aic7xxx_slave_attach(Scsi_Device *sdpnt)
 {
-  Scsi_Device *device;
-  struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  struct aic7xxx_host *p = (struct aic7xxx_host *) sdpnt->host->hostdata;
+  struct aic_dev_data *aic_dev;
   int scbnum;
+  struct list_head *list_ptr, *list_head;
+
+  if(!sdpnt->hostdata) {
+    sdpnt->hostdata = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC);
+    if(!sdpnt->hostdata)
+      return 1;
+    memset(sdpnt->hostdata, 0, sizeof(struct aic_dev_data));
+  }
+
+  aic_dev = sdpnt->hostdata;
+  aic_dev->SDptr = sdpnt;
+
+  aic7xxx_init_aic_dev(p, aic_dev);
+  
+  list_add(&aic_dev->list, &p->aic_devs);
+
+  aic7xxx_device_queue_depth(p, sdpnt);
 
   scbnum = 0;
-  for (device = scsi_devs; device != NULL; device = device->next)
-  {
-    if (device->host == host)
-    {
-      scbnum += aic7xxx_device_queue_depth(p, device);
-    }
+  list_head = &p->aic_devs;
+  list_for_each(list_ptr, list_head) {
+    aic_dev = list_entry(list_ptr, struct aic_dev_data, list);
+    scbnum += aic_dev->max_q_depth;
   }
   while (scbnum > p->scb_data->numscbs)
   {
@@ -7148,8 +6755,11 @@
      * the SCB in order to perform a swap operation (possible deadlock)
      */
     if ( aic7xxx_allocate_scb(p) == 0 )
-      return;
+      break;
   }
+
+
+  return(0);
 }
 
 /*+F*************************************************************************
@@ -8246,7 +7856,6 @@
   host->can_queue = AIC7XXX_MAXSCB;
   host->cmd_per_lun = 3;
   host->sg_tablesize = AIC7XXX_MAX_SG;
-  host->select_queue_depths = aic7xxx_select_queue_depth;
   host->this_id = p->scsi_id;
   host->io_port = p->base;
   host->n_io_port = 0xFF;
@@ -8270,10 +7879,6 @@
   p->completeq.tail = NULL;
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
-  init_timer(&p->dev_timer);
-  p->dev_timer.data = (unsigned long)p;
-  p->dev_timer.function = (void *)aic7xxx_timer;
-  p->dev_timer_active = 0;
 
   /*
    * We currently have no commands of any type
@@ -8281,19 +7886,6 @@
   p->qinfifonext = 0;
   p->qoutfifonext = 0;
 
-  for (i = 0; i < MAX_TARGETS; i++)
-  {
-    p->dev_commands_sent[i] = 0;
-    p->dev_flags[i] = 0;
-    p->dev_active_cmds[i] = 0;
-    p->dev_last_queue_full[i] = 0;
-    p->dev_last_queue_full_count[i] = 0;
-    p->dev_max_queue_depth[i] = 1;
-    p->dev_temp_queue_depth[i] = 1;
-    p->dev_expires[i] = 0;
-    scbq_init(&p->delayed_scbs[i]);
-  }
-
   printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
     board_names[p->board_name_index]);
   switch(p->chip)
@@ -8513,22 +8105,6 @@
   {
     /*
      * If we reset the bus, then clear the transfer settings, else leave
-     * them be
-     */
-    for (i = 0; i < max_targets; i++)
-    {
-      aic_outb(p, 0, TARG_SCSIRATE + i);
-      if (p->features & AHC_ULTRA2)
-      {
-        aic_outb(p, 0, TARG_OFFSET + i);
-      }
-      p->transinfo[i].cur_offset = 0;
-      p->transinfo[i].cur_period = 0;
-      p->transinfo[i].cur_width = MSG_EXT_WDTR_BUS_8_BIT;
-    }
-
-    /*
-     * If we reset the bus, then clear the transfer settings, else leave
      * them be.
      */
     aic_outb(p, 0, ULTRA_ENB);
@@ -8699,19 +8275,6 @@
     
     aic7xxx_reset_current_bus(p);
 
-    /*
-     * Delay for the reset delay by setting the timer, this will delay
-     * future commands sent to any devices.
-     */
-    p->flags |= AHC_RESET_DELAY;
-    for(i=0; i<MAX_TARGETS; i++)
-    {
-      p->dev_expires[i] = jiffies + (4 * HZ);
-      p->dev_timer_active |= (0x01 << i);
-    }
-    p->dev_timer.expires = p->dev_expires[p->scsi_id];
-    add_timer(&p->dev_timer);
-    p->dev_timer_active |= (0x01 << MAX_TARGETS);
   }
   else
   {
@@ -8828,7 +8391,6 @@
 {
   struct aic7xxx_host *p = NULL;
   struct Scsi_Host *host;
-  int i;
 
   /*
    * Allocate a storage area by registering us with the mid-level
@@ -8842,7 +8404,6 @@
     memset(p, 0, sizeof(struct aic7xxx_host));
     *p = *temp;
     p->host = host;
-    host->max_sectors = 512;
 
     p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
     if (p->scb_data != NULL)
@@ -8861,16 +8422,6 @@
       return(NULL);
     }
     p->host_no = host->host_no;
-    p->tagenable = 0;
-    p->orderedtag = 0;
-    for (i=0; i<MAX_TARGETS; i++)
-    {
-      p->transinfo[i].goal_period = 255;
-      p->transinfo[i].goal_offset = 0;
-      p->transinfo[i].goal_options = 0;
-      p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
-    }
-    DRIVER_LOCK_INIT
   }
   scsi_set_pci_device(host, p->pdev);
   return (p);
@@ -9086,7 +8637,7 @@
   }
 
   p->discenable = 0;
-    
+
   /*
    * Limit to 16 targets just in case.  The 2842 for one is known to
    * blow the max_targets setting, future cards might also.
@@ -9120,11 +8671,11 @@
          * Just make our sc->device_flags[i] entry match what the card has
          * set for this device.
          */
-        p->discenable = 
-          ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) );
+	p->discenable =
+	  ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) );
         p->ultraenb =
           (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) );
-        sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0;
+	sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0;
         if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER)
           sc->device_flags[i] |= CFWIDEB;
         if (p->features & AHC_ULTRA2)
@@ -9214,110 +8765,69 @@
     {
       sc->device_flags[i] &= ~CFXFER;
       p->ultraenb &= ~mask;
-      p->transinfo[i].user_offset = 0;
-      p->transinfo[i].user_period = 0;
-      p->transinfo[i].user_options = 0;
-      p->transinfo[i].cur_offset = 0;
-      p->transinfo[i].cur_period = 0;
-      p->transinfo[i].cur_options = 0;
-      p->needsdtr_copy &= ~mask;
+      p->user[i].offset = 0;
+      p->user[i].period = 0;
+      p->user[i].options = 0;
     }
     else
     {
       if (p->features & AHC_ULTRA3)
       {
-        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
-        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+        p->user[i].offset = MAX_OFFSET_ULTRA2;
         if( (sc->device_flags[i] & CFXFER) < 0x03 )
         {
           scsirate = (sc->device_flags[i] & CFXFER);
-          p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
-          if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
-          {
-            p->transinfo[i].cur_options = 
-              ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
-                 MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
-          }
-          else
-          {
-            p->transinfo[i].cur_options = 0;
-          }
+          p->user[i].options = MSG_EXT_PPR_OPTION_DT_CRC;
         }
         else
         {
           scsirate = (sc->device_flags[i] & CFXFER) |
                      ((p->ultraenb & mask) ? 0x18 : 0x10);
-          p->transinfo[i].user_options = 0;
-          p->transinfo[i].cur_options = 0;
+          p->user[i].options = 0;
         }
-        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
-                                       AHC_SYNCRATE_ULTRA3);
-        p->transinfo[i].cur_period = aic7xxx_find_period(p,
-                                       aic_inb(p, TARG_SCSIRATE + i),
+        p->user[i].period = aic7xxx_find_period(p, scsirate,
                                        AHC_SYNCRATE_ULTRA3);
       }
       else if (p->features & AHC_ULTRA2)
       {
-        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
-        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+        p->user[i].offset = MAX_OFFSET_ULTRA2;
         scsirate = (sc->device_flags[i] & CFXFER) |
                    ((p->ultraenb & mask) ? 0x18 : 0x10);
-        p->transinfo[i].user_options = 0;
-        p->transinfo[i].cur_options = 0;
-        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
-                                       AHC_SYNCRATE_ULTRA2);
-        p->transinfo[i].cur_period = aic7xxx_find_period(p,
-                                       aic_inb(p, TARG_SCSIRATE + i),
+        p->user[i].options = 0;
+        p->user[i].period = aic7xxx_find_period(p, scsirate,
                                        AHC_SYNCRATE_ULTRA2);
       }
       else
       {
         scsirate = (sc->device_flags[i] & CFXFER) << 4;
-        p->transinfo[i].user_options = 0;
-        p->transinfo[i].cur_options = 0;
-        p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
+        p->user[i].options = 0;
+        p->user[i].offset = MAX_OFFSET_8BIT;
         if (p->features & AHC_ULTRA)
         {
           short ultraenb;
           ultraenb = aic_inb(p, ULTRA_ENB) |
             (aic_inb(p, ULTRA_ENB + 1) << 8);
-          p->transinfo[i].user_period = aic7xxx_find_period(p,
-                                          scsirate,
+          p->user[i].period = aic7xxx_find_period(p, scsirate,
                                           (p->ultraenb & mask) ?
                                           AHC_SYNCRATE_ULTRA :
                                           AHC_SYNCRATE_FAST);
-          p->transinfo[i].cur_period = aic7xxx_find_period(p,
-                                         aic_inb(p, TARG_SCSIRATE + i),
-                                         (ultraenb & mask) ? 
-                                         AHC_SYNCRATE_ULTRA :
-                                         AHC_SYNCRATE_FAST);
         }
         else
-          p->transinfo[i].user_period = aic7xxx_find_period(p,
-                                          scsirate, AHC_SYNCRATE_FAST);
+          p->user[i].period = aic7xxx_find_period(p, scsirate,
+			  		  AHC_SYNCRATE_FAST);
       }
-      p->needsdtr_copy |= mask;
     }
     if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) )
     {
-      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_16_BIT;
-      p->needwdtr_copy |= mask;
+      p->user[i].width = MSG_EXT_WDTR_BUS_16_BIT;
     }
     else
     {
-      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_8_BIT;
-      p->needwdtr_copy &= ~mask;
+      p->user[i].width = MSG_EXT_WDTR_BUS_8_BIT;
     }
-    p->transinfo[i].cur_width =
-      (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) ?
-      MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT;
   }
   aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
   aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
-  p->needppr = p->needppr_copy = 0;
-  p->needwdtr = p->needwdtr_copy;
-  p->needsdtr = p->needsdtr_copy;
-  p->dtr_pending = 0;
 
   /*
    * We set the p->ultraenb from the SEEPROM to begin with, but now we make
@@ -9483,17 +8993,11 @@
    */
   if(aic7xxx)
     aic7xxx_setup(aic7xxx);
-  if(dummy_buffer[0] != 'P')
-    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
-      "/scsi/README.aic7xxx\n"
-      "aic7xxx: to see the proper way to specify options to the aic7xxx "
-      "module\n"
-      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
-      "aic7xxx: insmod or else it might trash certain memory areas.\n");
 #endif
 
   template->proc_name = "aic7xxx";
   template->sg_tablesize = AIC7XXX_MAX_SG;
+  template->max_sectors = 2048;
 
 
 #ifdef CONFIG_PCI
@@ -10651,6 +10155,8 @@
 {
   unsigned short mask;
   struct aic7xxx_hwscb *hscb;
+  struct aic_dev_data *aic_dev = cmd->device->hostdata;
+  struct scsi_device *sdptr = cmd->device;
   unsigned char tindex = TARGET_INDEX(cmd);
 
   mask = (0x01 << tindex);
@@ -10666,50 +10172,40 @@
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
-    if ( (p->tagenable & mask) &&
+    if ( (sdptr->simple_tags) &&
          (cmd->cmnd[0] != TEST_UNIT_READY) )
     {
-      p->dev_commands_sent[tindex]++;
-      if (p->dev_commands_sent[tindex] < 200)
+      aic_dev->cmds_sent++;
+      if (aic_dev->cmds_sent >= 254 && sdptr->ordered_tags)
       {
-        hscb->control |= MSG_SIMPLE_Q_TAG;
-        scb->tag_action = MSG_SIMPLE_Q_TAG;
+        aic_dev->cmds_sent = 0;
+        hscb->control |= MSG_ORDERED_Q_TAG;
+        scb->tag_action = MSG_ORDERED_Q_TAG;
       }
       else
       {
-        if (p->orderedtag & mask)
-        {
-          hscb->control |= MSG_ORDERED_Q_TAG;
-          scb->tag_action = MSG_ORDERED_Q_TAG;
-        }
-        else
-        {
-          hscb->control |= MSG_SIMPLE_Q_TAG;
-          scb->tag_action = MSG_SIMPLE_Q_TAG;
-        }
-        p->dev_commands_sent[tindex] = 0;
+        hscb->control |= MSG_SIMPLE_Q_TAG;
+        scb->tag_action = MSG_SIMPLE_Q_TAG;
       }
     }
   }
-  if ( !(p->dtr_pending & mask) &&
-        ( (p->needppr & mask) ||
-          (p->needwdtr & mask) ||
-          (p->needsdtr & mask) ) &&
-        (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
+  if ( !(aic_dev->dtr_pending) &&
+        (aic_dev->needppr || aic_dev->needwdtr || aic_dev->needsdtr) &&
+        (aic_dev->flags & DEVICE_DTR_SCANNED) )
   {
-    p->dtr_pending |= mask;
+    aic_dev->dtr_pending = 1;
     scb->tag_action = 0;
     hscb->control &= DISCENB;
     hscb->control |= MK_MESSAGE;
-    if(p->needppr & mask)
+    if(aic_dev->needppr)
     {
       scb->flags |= SCB_MSGOUT_PPR;
     }
-    else if(p->needwdtr & mask)
+    else if(aic_dev->needwdtr)
     {
       scb->flags |= SCB_MSGOUT_WDTR;
     }
-    else if(p->needsdtr & mask)
+    else if(aic_dev->needsdtr)
     {
       scb->flags |= SCB_MSGOUT_SDTR;
     }
@@ -10810,6 +10306,7 @@
 {
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
+  struct aic_dev_data *aic_dev;
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
   int tindex = TARGET_INDEX(cmd);
 #endif
@@ -10852,34 +10349,25 @@
   }
 #endif
 
+  if(!cmd->device->hostdata) {
+    aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC);
+    if(!aic_dev)
+      return 1;
+    memset(aic_dev, 0, sizeof(struct aic_dev_data));
+    cmd->device->hostdata = aic_dev;
+  }
+
   scb = scbq_remove_head(&p->scb_data->free_scbs);
   if (scb == NULL)
   {
-    DRIVER_LOCK
     aic7xxx_allocate_scb(p);
-    DRIVER_UNLOCK
     scb = scbq_remove_head(&p->scb_data->free_scbs);
     if(scb == NULL)
+    {
       printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
              CTL_OF_CMD(cmd));
-  }
-  while (scb == NULL)
-  {
-    /*
-     * Well, all SCBs are currently active on the bus.  So, we spin here
-     * running the interrupt handler until one completes and becomes free.
-     * We can do this safely because we either A) hold the driver lock (in
-     * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
-     * kernels) and so either way, we won't take any other interrupts and
-     * the queue path will block until we release it.  Also, we would worry
-     * about running the completion queues, but obviously there are plenty
-     * of commands outstanding to trigger a later interrupt that will do
-     * that for us, so skip it here.
-     */
-    DRIVER_LOCK
-    aic7xxx_isr(p->irq, p, NULL);
-    DRIVER_UNLOCK
-    scb = scbq_remove_head(&p->scb_data->free_scbs);
+      return 1;
+    }
   }
   scb->cmd = cmd;
   aic7xxx_position(cmd) = scb->hscb->tag;
@@ -10904,13 +10392,11 @@
 
   scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-  DRIVER_LOCK
   scbq_insert_tail(&p->waiting_scbs, scb);
   if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
   {
     aic7xxx_run_waiting_queues(p);
   }
-  DRIVER_UNLOCK
   return (0);
 }
 
@@ -10935,6 +10421,7 @@
   unsigned char saved_scbptr, lastphase;
   unsigned char hscb_index;
   int disconnected;
+  struct aic_dev_data *aic_dev = AIC_DEV(cmd);
 
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   hscb = scb->hscb;
@@ -11018,9 +10505,8 @@
           printk(INFO_LEAD "Device reset message in "
                 "message buffer\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-        aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
-                BUS_DEVICE_RESET_PENDING;
+        aic7xxx_error(cmd) = DID_RESET;
+        aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
         /* Send the abort message to the active SCB. */
         aic_outb(p, HOST_MSG, MSG_OUT);
         aic_outb(p, lastphase | ATNO, SCSISIGO);
@@ -11038,9 +10524,8 @@
         printk(WARN_LEAD "Device reset, Message buffer "
                 "in use\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-        aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
-                BUS_DEVICE_RESET_PENDING;
+        aic7xxx_error(cmd) = DID_RESET;
+        aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
         return(SCSI_RESET_ERROR);
       }
     }
@@ -11066,8 +10551,7 @@
          */
     scb->hscb->control |= MK_MESSAGE;
     scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-    p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
-        BUS_DEVICE_RESET_PENDING;
+    aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
     if (hscb_index != SCB_LIST_NULL)
     {
       unsigned char scb_control;
@@ -11147,11 +10631,9 @@
 {
   struct aic7xxx_scb  *scb = NULL;
   struct aic7xxx_host *p;
+  struct aic_dev_data *aic_dev = AIC_DEV(cmd);
   int    result, found=0;
   unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
@@ -11167,8 +10649,6 @@
   if (aic7xxx_panic_on_abort)
     aic7xxx_panic_abort(p, cmd);
 
-  DRIVER_LOCK
-
 /*
  *  Run the isr to grab any command in the QOUTFIFO and any other misc.
  *  assundry tasks.  This should also set up the bh handler if there is
@@ -11190,7 +10670,6 @@
       printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
         "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
     unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
     return(SCSI_ABORT_NOT_RUNNING);
   }
   if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
@@ -11208,7 +10687,6 @@
       printk(INFO_LEAD "Abort called for already completed"
         " command.\n", p->host_no, CTL_OF_CMD(cmd));
     unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
     return(SCSI_ABORT_NOT_RUNNING);
   }
     
@@ -11243,18 +10721,15 @@
       printk(INFO_LEAD "SCB aborted once already, "
         "escalating.\n", p->host_no, CTL_OF_SCB(scb));
     unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
     return(SCSI_ABORT_SNOOZE);
   }
   if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
-          (p->dev_flags[TARGET_INDEX(scb->cmd)] & 
-           BUS_DEVICE_RESET_PENDING) )
+          (aic_dev->flags & BUS_DEVICE_RESET_PENDING) )
   {
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
       printk(INFO_LEAD "Reset/Abort pending for this "
         "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
     unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
     return(SCSI_ABORT_PENDING);
   }
 
@@ -11316,7 +10791,6 @@
         p->flags &= ~AHC_IN_ABORT;
         scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
         p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
-        DRIVER_UNLOCK                   /*  muck with other SCBs if this   */
         return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
         break;                          /*  out.                           */
       default:
@@ -11326,14 +10800,13 @@
 
   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
-    int tindex = TARGET_INDEX(cmd);
 
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
       printk(INFO_LEAD "SCB found on waiting list and "
           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
     scbq_remove(&p->waiting_scbs, scb);
-    scbq_remove(&p->delayed_scbs[tindex], scb);
-    p->dev_active_cmds[tindex]++;
+    scbq_remove(&aic_dev->delayed_scbs, scb);
+    aic_dev->active_cmds++;
     p->activescbs++;
     scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
     scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
@@ -11442,7 +10915,6 @@
   }
   p->flags &= ~AHC_IN_ABORT;
   unpause_sequencer(p, FALSE);
-  DRIVER_UNLOCK
 
 /*
  *  On the return value.  If we found the command and aborted it, then we know
@@ -11476,11 +10948,9 @@
 {
   struct aic7xxx_scb *scb = NULL;
   struct aic7xxx_host *p;
+  struct aic_dev_data *aic_dev;
   int    tindex;
   int    result = -1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
 #define DEVICE_RESET 0x01
 #define BUS_RESET    0x02
 #define HOST_RESET   0x04
@@ -11496,7 +10966,15 @@
   }
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  aic_dev = AIC_DEV(cmd);
+  if(aic_dev)
+  {
+    scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  }
+  else
+  {
+    scb = NULL;
+  }
   tindex = TARGET_INDEX(cmd);
 
   /*
@@ -11510,8 +10988,6 @@
   if (aic7xxx_panic_on_abort)
     aic7xxx_panic_abort(p, cmd);
 
-  DRIVER_LOCK
-
   pause_sequencer(p);
 
   if(flags & SCSI_RESET_SYNCHRONOUS)
@@ -11531,7 +11007,6 @@
     aic7xxx_done_cmds_complete(p);
     aic7xxx_run_waiting_queues(p);
     unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
     return(SCSI_RESET_NOT_RUNNING);
   }
   else
@@ -11568,12 +11043,11 @@
      */
     aic7xxx_run_waiting_queues(p);
     unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
     return(SCSI_RESET_SUCCESS);
   }
     
   if ( (action & DEVICE_RESET) && 
-        (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
+        (aic_dev->flags & BUS_DEVICE_RESET_PENDING) )
   {
     if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
       printk(INFO_LEAD "Bus device reset already sent to "
@@ -11604,7 +11078,7 @@
   {
     action = HOST_RESET;
   }
-  if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) &&
+  if ( (aic_dev->flags & DEVICE_RESET_DELAY) &&
        !(action & (HOST_RESET | BUS_RESET)))
   {
     if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
@@ -11633,7 +11107,6 @@
     case RESET_DELAY:
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
       if(scb == NULL)
         return(SCSI_RESET_PUNT);
       else
@@ -11648,21 +11121,12 @@
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       p->flags &= ~AHC_IN_RESET;
-      DRIVER_UNLOCK
       return(result);
       break;
     case BUS_RESET:
     case HOST_RESET:
     default:
       p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
-      p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
-      p->dev_timer_active |= (0x01 << p->scsi_id);
-      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
-            time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
-      {
-        mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]);
-        p->dev_timer_active |= (0x01 << MAX_TARGETS);
-      }
       aic7xxx_reset_channel(p, cmd->channel, TRUE);
       if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
       {
@@ -11699,7 +11163,6 @@
        */
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
       if(scb == NULL)
         return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
       else
@@ -11735,13 +11198,13 @@
   
   heads = 64;
   sectors = 32;
-  cylinders = disk->capacity / (heads * sectors);
+  cylinders = (unsigned long)disk->capacity / (heads * sectors);
 
   if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
   {
     heads = 255;
     sectors = 63;
-    cylinders = disk->capacity / (heads * sectors);
+    cylinders = (unsigned long)disk->capacity / (heads * sectors);
   }
 
   geom[0] = heads;
diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
--- a/drivers/scsi/atp870u.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/atp870u.c	Fri Oct 11 21:22:55 2002
@@ -902,10 +902,12 @@
 		0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27
 	};
 
-
+/*  I can't believe we need this before we've even done anything.  Remove it
+ *  and see if anyone bitches.
 	for (i = 0; i < 0x10; i++) {
 		udelay(0xffff);
 	}
+ */
 
 	tmport = dev->ioport + 1;
 	outb(0x08, tmport++);
@@ -993,8 +995,7 @@
 	inb(0x80);		/* 2 deskew delay(45ns*2=90ns) */
 	val &= 0x007f;		/* no bsy  */
 	outw(val, tmport);
-	udelay(0xffff);		/* recommanded SCAM selection response time */
-	udelay(0xffff);
+	mdelay(128);
 	val &= 0x00fb;		/* after 1ms no msg */
 	outw(val, tmport);
 wait_nomsg:
@@ -2420,9 +2421,9 @@
 			k = (inb(tmport) & 0xf3) | 0x10;
 			outb(k, tmport);
 			outb((k & 0xdf), tmport);
-			udelay(0x8000);
+			mdelay(32);
 			outb(k, tmport);
-			udelay(0x8000);
+			mdelay(32);
 			tmport = base_io;
 			outb((host_id | 0x08), tmport);
 			tmport += 0x18;
@@ -2539,9 +2540,9 @@
 			outb(k, tmport);
 			tmport += 0x03;
 			outb(0x20, tmport);
-			udelay(0x8000);
+			mdelay(32);
 			outb(0, tmport);
-			udelay(0x8000);
+			mdelay(32);
 			tmport = base_io + 0x5b;
 			inb(tmport);
 			tmport -= 0x04;
@@ -2581,7 +2582,7 @@
 			shpnt->n_io_port = 0x40;	/* Number of bytes of I/O space used */
 		}
 		shpnt->irq = irq;
-		restore_flags(flags);
+		spin_unlock_irqrestore(shpnt->host_lock, flags);
 		if (dev_id[h] == 0x8081) {
 			request_region(base_io, 0x60, "atp870u");	/* Register the IO ports that we use */
 		} else {
@@ -2719,12 +2720,12 @@
 
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (unsigned long)disk->capacity / (heads * sectors);
 
 	if (cylinders > 1024) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (unsigned long)disk->capacity / (heads * sectors);
 	}
 	ip[0] = heads;
 	ip[1] = sectors;
diff -Nru a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h
--- a/drivers/scsi/cpqfcTSstructs.h	Fri Oct 11 21:22:56 2002
+++ b/drivers/scsi/cpqfcTSstructs.h	Fri Oct 11 21:22:56 2002
@@ -21,7 +21,6 @@
 #define CPQFCTSSTRUCTS_H
 
 #include <linux/timer.h>  // timer declaration in our host data
-#include <linux/tqueue.h> // task queue sched
 #include <asm/atomic.h>
 #include "cpqfcTSioctl.h"
 
diff -Nru a/drivers/scsi/dmx3191d.h b/drivers/scsi/dmx3191d.h
--- a/drivers/scsi/dmx3191d.h	Fri Oct 11 21:22:58 2002
+++ b/drivers/scsi/dmx3191d.h	Fri Oct 11 21:22:58 2002
@@ -27,7 +27,9 @@
 int dmx3191d_proc_info(char *, char **, off_t, int, int, int);
 int dmx3191d_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int dmx3191d_release_resources(struct Scsi_Host *);
-int dmx3191d_reset(Scsi_Cmnd *, unsigned int);
+int dmx3191d_bus_reset(Scsi_Cmnd *);
+int dmx3191d_host_reset(Scsi_Cmnd *);
+int dmx3191d_device_reset(Scsi_Cmnd *);
 
 
 #define DMX3191D {				\
@@ -37,8 +39,10 @@
 	release:	dmx3191d_release_resources,	\
 	info:		dmx3191d_info,			\
 	queuecommand:	dmx3191d_queue_command,		\
-	abort:		dmx3191d_abort,			\
-	reset:		dmx3191d_reset, 		\
+	eh_abort_handler:	dmx3191d_abort,		\
+	eh_bus_reset_handler:	dmx3191d_bus_reset, 	\
+	eh_device_reset_handler:dmx3191d_device_reset, 	\
+	eh_host_reset_handler:	dmx3191d_host_reset, 	\
 	bios_param:	NULL,				\
 	can_queue:	32,				\
         this_id:	7,				\
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/scsi/esp.c	Fri Oct 11 21:23:05 2002
@@ -1362,17 +1362,19 @@
 	for (i = 0; i < 15; i++) {
 		if (esp->targets_present & (1 << i)) {
 			Scsi_Device *SDptr = esp->ehost->host_queue;
+			struct esp_device *esp_dev;
 
 			while ((SDptr->host != esp->ehost) &&
 			       (SDptr->id != i) &&
 			       (SDptr->next))
 				SDptr = SDptr->next;
 
+			esp_dev = SDptr->hostdata;
 			copy_info(&info, "%d\t\t", i);
 			copy_info(&info, "%08lx\t", esp->config3[i]);
-			copy_info(&info, "[%02lx,%02lx]\t\t\t", SDptr->sync_max_offset,
-				  SDptr->sync_min_period);
-			copy_info(&info, "%s\t\t", SDptr->disconnect ? "yes" : "no");
+			copy_info(&info, "[%02lx,%02lx]\t\t\t", esp_dev->sync_max_offset,
+				  esp_dev->sync_min_period);
+			copy_info(&info, "%s\t\t", esp_dev->disconnect ? "yes" : "no");
 			copy_info(&info, "%s\n",
 				  (esp->config3[i] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
 		}
@@ -1533,6 +1535,7 @@
 {
 	Scsi_Cmnd *SCptr;
 	Scsi_Device *SDptr;
+	struct esp_device *esp_dev;
 	volatile u8 *cmdp = esp->esp_command;
 	u8 the_esp_command;
 	int lun, target;
@@ -1552,9 +1555,29 @@
 		panic("esp: esp_exec_cmd and issue queue is NULL");
 
 	SDptr = SCptr->device;
+	esp_dev = SDptr->hostdata;
 	lun = SCptr->lun;
 	target = SCptr->target;
 
+	/*
+	 * We check that esp_dev != NULL.  If it is, we allocate it or bail.
+	 */
+	if (!esp_dev) {
+		esp_dev = kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+		if (!esp_dev) {
+			/* We're SOL.  Print a message and bail */
+			printk(KERN_WARNING "esp: no mem for esp_device %d/%d\n",
+					target, lun);
+			esp->current_SC = NULL;
+			SCptr->result = DID_ERROR << 16;
+			SCptr->done(SCptr);
+			return;
+		}
+		memset(esp_dev, 0, sizeof(struct esp_device));
+		SDptr->hostdata = esp_dev;
+	}
+	}
+
 	esp->snip = 0;
 	esp->msgout_len = 0;
 
@@ -1590,12 +1613,12 @@
 	 * selections should not confuse SCSI-1 we hope.
 	 */
 
-	if (SDptr->sync) {
+	if (esp_dev->sync) {
 		/* this targets sync is known */
 #ifndef __sparc_v9__
 do_sync_known:
 #endif
-		if (SDptr->disconnect)
+		if (esp_dev->disconnect)
 			*cmdp++ = IDENTIFY(1, lun);
 		else
 			*cmdp++ = IDENTIFY(0, lun);
@@ -1607,7 +1630,7 @@
 			the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
 			esp_advance_phase(SCptr, in_slct_norm);
 		}
-	} else if (!(esp->targets_present & (1<<target)) || !(SDptr->disconnect)) {
+	} else if (!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) {
 		/* After the bootup SCSI code sends both the
 		 * TEST_UNIT_READY and INQUIRY commands we want
 		 * to at least attempt allowing the device to
@@ -1615,8 +1638,8 @@
 		 */
 		ESPMISC(("esp: Selecting device for first time. target=%d "
 			 "lun=%d\n", target, SCptr->lun));
-		if (!SDptr->borken && !SDptr->disconnect)
-			SDptr->disconnect = 1;
+		if (!SDptr->borken && !esp_dev->disconnect)
+			esp_dev->disconnect = 1;
 
 		*cmdp++ = IDENTIFY(0, lun);
 		esp->prevmsgout = NOP;
@@ -1624,8 +1647,8 @@
 		the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
 
 		/* Take no chances... */
-		SDptr->sync_max_offset = 0;
-		SDptr->sync_min_period = 0;
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
 	} else {
 		/* Sorry, I have had way too many problems with
 		 * various CDROM devices on ESP. -DaveM
@@ -1644,12 +1667,12 @@
 			 */
 			if(SDptr->type == TYPE_TAPE ||
 			   (SDptr->type != TYPE_ROM && SDptr->removable))
-				SDptr->disconnect = 1;
+				esp_dev->disconnect = 1;
 			else
-				SDptr->disconnect = 0;
-			SDptr->sync_max_offset = 0;
-			SDptr->sync_min_period = 0;
-			SDptr->sync = 1;
+				esp_dev->disconnect = 0;
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync = 1;
 			esp->snip = 0;
 			goto do_sync_known;
 		}
@@ -1660,16 +1683,16 @@
 		 * need to attempt WIDE first, before
 		 * sync nego, as per SCSI 2 standard.
 		 */
-		if (esp->erev == fashme && !SDptr->wide) {
+		if (esp->erev == fashme && !esp_dev->wide) {
 			if (!SDptr->borken &&
 			   SDptr->type != TYPE_ROM &&
 			   SDptr->removable == 0) {
 				build_wide_nego_msg(esp, 16);
-				SDptr->wide = 1;
+				esp_dev->wide = 1;
 				esp->wnip = 1;
 				goto after_nego_msg_built;
 			} else {
-				SDptr->wide = 1;
+				esp_dev->wide = 1;
 				/* Fall through and try sync. */
 			}
 		}
@@ -1692,7 +1715,7 @@
 		} else {
 			build_sync_nego_msg(esp, 0, 0);
 		}
-		SDptr->sync = 1;
+		esp_dev->sync = 1;
 		esp->snip = 1;
 
 after_nego_msg_built:
@@ -1725,7 +1748,7 @@
 		    cdrom_hwbug_wkaround || SDptr->borken) {
 			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
 				 "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
-			SDptr->disconnect = 0;
+			esp_dev->disconnect = 0;
 			*cmdp++ = IDENTIFY(0, lun);
 		} else {
 			*cmdp++ = IDENTIFY(1, lun);
@@ -1752,12 +1775,12 @@
 			    esp->eregs + ESP_BUSID);
 	else
 		sbus_writeb(target & 7, esp->eregs + ESP_BUSID);
-	if (esp->prev_soff != SDptr->sync_max_offset ||
-	    esp->prev_stp  != SDptr->sync_min_period ||
+	if (esp->prev_soff != esp_dev->sync_max_offset ||
+	    esp->prev_stp  != esp_dev->sync_min_period ||
 	    (esp->erev > esp100a &&
 	     esp->prev_cfg3 != esp->config3[target])) {
-		esp->prev_soff = SDptr->sync_max_offset;
-		esp->prev_stp = SDptr->sync_min_period;
+		esp->prev_soff = esp_dev->sync_max_offset;
+		esp->prev_stp = esp_dev->sync_min_period;
 		sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
 		sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
 		if (esp->erev > esp100a) {
@@ -2462,14 +2485,14 @@
  */
 static inline void esp_connect(struct esp *esp, Scsi_Cmnd *sp)
 {
-	Scsi_Device *dp = sp->device;
+	struct esp_device *esp_dev = sp->device->hostdata;
 
-	if (esp->prev_soff  != dp->sync_max_offset ||
-	    esp->prev_stp   != dp->sync_min_period ||
+	if (esp->prev_soff  != esp_dev->sync_max_offset ||
+	    esp->prev_stp   != esp_dev->sync_min_period ||
 	    (esp->erev > esp100a &&
 	     esp->prev_cfg3 != esp->config3[sp->target])) {
-		esp->prev_soff = dp->sync_max_offset;
-		esp->prev_stp = dp->sync_min_period;
+		esp->prev_soff = esp_dev->sync_max_offset;
+		esp->prev_stp = esp_dev->sync_min_period;
 		sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
 		sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
 		if (esp->erev > esp100a) {
@@ -2601,6 +2624,7 @@
 static int esp_do_data_finale(struct esp *esp)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
 	int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
 
 	ESPDATA(("esp_do_data_finale: "));
@@ -2694,14 +2718,14 @@
 
 	/* If we were in synchronous mode, check for peculiarities. */
 	if (esp->erev == fashme) {
-		if (SCptr->device->sync_max_offset) {
+		if (esp_dev->sync_max_offset) {
 			if (SCptr->SCp.phase == in_dataout)
 				esp_cmd(esp, ESP_CMD_FLUSH);
 		} else {
 			esp_cmd(esp, ESP_CMD_FLUSH);
 		}
 	} else {
-		if (SCptr->device->sync_max_offset)
+		if (esp_dev->sync_max_offset)
 			bogus_data = esp100_sync_hwbug(esp, SCptr, fifocnt);
 		else
 			esp_cmd(esp, ESP_CMD_FLUSH);
@@ -2730,7 +2754,7 @@
 		ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, 
 			SCptr->target));
 		SCptr->device->borken = 1;
-		SCptr->device->sync = 0;
+		esp_dev->sync = 0;
 		bytes_sent = 0;
 	}
 
@@ -2815,6 +2839,7 @@
 static int esp_do_freebus(struct esp *esp)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
 	int rval;
 
 	rval = skipahead2(esp, SCptr, in_status, in_msgindone, in_freeing);
@@ -2834,8 +2859,8 @@
 		if (SCptr->SCp.Status != GOOD &&
 		    SCptr->SCp.Status != CONDITION_GOOD &&
 		    ((1<<SCptr->target) & esp->targets_present) &&
-		    SCptr->device->sync &&
-		    SCptr->device->sync_max_offset) {
+		    esp_dev->sync &&
+		    esp_dev->sync_max_offset) {
 			/* SCSI standard says that the synchronous capabilities
 			 * should be renegotiated at this point.  Most likely
 			 * we are about to request sense from this target
@@ -2853,7 +2878,7 @@
 			 * loading up a tape.
 			 */
 			if (esp_should_clear_sync(SCptr) != 0)
-				SCptr->device->sync = 0;
+				esp_dev->sync = 0;
 		}
 		ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
 		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
@@ -3113,7 +3138,7 @@
 static int esp_disconnect_amidst_phases(struct esp *esp)
 {
 	Scsi_Cmnd *sp = esp->current_SC;
-	Scsi_Device *dp = sp->device;
+	struct esp_device *esp_dev = sp->device->hostdata;
 
 	/* This means real problems if we see this
 	 * here.  Unless we were actually trying
@@ -3137,9 +3162,9 @@
 
 	case BUS_DEVICE_RESET:
 		ESPLOG(("device reset successful\n"));
-		dp->sync_max_offset = 0;
-		dp->sync_min_period = 0;
-		dp->sync = 0;
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+		esp_dev->sync = 0;
 		esp_advance_phase(sp, in_resetdev);
 		esp_done(esp, (DID_RESET << 16));
 		break;
@@ -3206,7 +3231,7 @@
 static int esp_select_complete(struct esp *esp)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
-	Scsi_Device *SDptr = SCptr->device;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
 	int cmd_bytes_sent, fcnt;
 
 	if (esp->erev != fashme)
@@ -3241,7 +3266,7 @@
 
 		/* What if the target ignores the sdtr? */
 		if (esp->snip)
-			SDptr->sync = 1;
+			esp_dev->sync = 1;
 
 		/* See how far, if at all, we got in getting
 		 * the information out to the target.
@@ -3333,7 +3358,7 @@
 		if ((esp->erev != fashme) && /* not a Happy Meal and... */
 		    !fcnt && /* Fifo is empty and... */
 		    /* either we are not doing synchronous transfers or... */
-		    (!SDptr->sync_max_offset ||
+		    (!esp_dev->sync_max_offset ||
 		     /* We are not going into data in phase. */
 		     ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
 			esp_cmd(esp, ESP_CMD_FLUSH); /* flush is safe */
@@ -3395,9 +3420,9 @@
 			esp->snip = 0;
 			ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
 				"lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
-			SDptr->sync_max_offset = 0;
-			SDptr->sync_min_period = 0;
-			SDptr->sync = 1; /* so we don't negotiate again */
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync = 1; /* so we don't negotiate again */
 
 			/* Run the command again, this time though we
 			 * won't try to negotiate for synchronous transfers.
@@ -3537,16 +3562,16 @@
 	case MESSAGE_REJECT:
 		ESPMISC(("msg reject, "));
 		if (esp->prevmsgout == EXTENDED_MESSAGE) {
-			Scsi_Device *SDptr = esp->current_SC->device;
+			struct esp_device *esp_dev = esp->current_SC->device->hostdata;
 
 			/* Doesn't look like this target can
 			 * do synchronous or WIDE transfers.
 			 */
 			ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
-			SDptr->sync = 1;
-			SDptr->wide = 1;
-			SDptr->sync_min_period = 0;
-			SDptr->sync_max_offset = 0;
+			esp_dev->sync = 1;
+			esp_dev->wide = 1;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync_max_offset = 0;
 			return 0;
 		} else {
 			ESPMISC(("not sync nego, sending ABORT\n"));
@@ -3562,13 +3587,13 @@
  */
 static int target_with_ants_in_pants(struct esp *esp,
 				     Scsi_Cmnd *SCptr,
-				     Scsi_Device *SDptr)
+				     struct esp_device *esp_dev)
 {
-	if (SDptr->sync || SDptr->borken) {
+	if (esp_dev->sync || SCptr->SDptr->borken) {
 		/* sorry, no can do */
 		ESPSDTR(("forcing to async, "));
 		build_sync_nego_msg(esp, 0, 0);
-		SDptr->sync = 1;
+		esp_dev->sync = 1;
 		esp->snip = 1;
 		ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
 		esp_advance_phase(SCptr, in_the_dark);
@@ -3621,7 +3646,7 @@
 static int check_multibyte_msg(struct esp *esp)
 {
 	Scsi_Cmnd *SCptr = esp->current_SC;
-	Scsi_Device *SDptr = SCptr->device;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
 	u8 regval = 0;
 	int message_out = 0;
 
@@ -3637,7 +3662,7 @@
 			/* Target negotiates first! */
 			ESPSDTR(("target jumps the gun, "));
 			message_out = EXTENDED_MESSAGE; /* we must respond */
-			rval = target_with_ants_in_pants(esp, SCptr, SDptr);
+			rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
 			if (rval)
 				return rval;
 		}
@@ -3684,8 +3709,8 @@
 		if (offset) {
 			u8 bit;
 
-			SDptr->sync_min_period = (regval & 0x1f);
-			SDptr->sync_max_offset = (offset | esp->radelay);
+			esp_dev->sync_min_period = (regval & 0x1f);
+			esp_dev->sync_max_offset = (offset | esp->radelay);
 			if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
 				if ((esp->erev == fas100a) || (esp->erev == fashme))
 					bit = ESP_CONFIG3_FAST;
@@ -3697,7 +3722,7 @@
 					 * control bits are clear.
 					 */
 					if (esp->erev == fashme)
-						SDptr->sync_max_offset &= ~esp->radelay;
+						esp_dev->sync_max_offset &= ~esp->radelay;
 					esp->config3[SCptr->target] |= bit;
 				} else {
 					esp->config3[SCptr->target] &= ~bit;
@@ -3705,23 +3730,23 @@
 				esp->prev_cfg3 = esp->config3[SCptr->target];
 				sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
 			}
-			esp->prev_soff = SDptr->sync_max_offset;
-			esp->prev_stp = SDptr->sync_min_period;
+			esp->prev_soff = esp_dev->sync_max_offset;
+			esp->prev_stp = esp_dev->sync_min_period;
 			sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
 			sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
 			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
-				 SDptr->sync_max_offset,
-				 SDptr->sync_min_period,
+				 esp_dev->sync_max_offset,
+				 esp_dev->sync_min_period,
 				 esp->config3[SCptr->target]));
 
 			esp->snip = 0;
-		} else if (SDptr->sync_max_offset) {
+		} else if (esp_dev->sync_max_offset) {
 			u8 bit;
 
 			/* back to async mode */
 			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
-			SDptr->sync_max_offset = 0;
-			SDptr->sync_min_period = 0;
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
 			esp->prev_soff = 0;
 			esp->prev_stp = 0;
 			sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
@@ -3740,7 +3765,7 @@
 		sync_report(esp);
 
 		ESPSDTR(("chk multibyte msg: sync is known, "));
-		SDptr->sync = 1;
+		esp_dev->sync = 1;
 
 		if (message_out) {
 			ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
@@ -3786,7 +3811,7 @@
 
 			/* Regardless, next try for sync transfers. */
 			build_sync_nego_msg(esp, esp->sync_defp, 15);
-			SDptr->sync = 1;
+			espo_dev->sync = 1;
 			esp->snip = 1;
 			message_out = EXTENDED_MESSAGE;
 		}
@@ -4051,7 +4076,7 @@
 			/* Happy Meal fifo is touchy... */
 			if ((esp->erev != fashme) &&
 			    !fcount(esp) &&
-			    !(esp->current_SC->device->sync_max_offset))
+			    !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
 				esp_cmd(esp, ESP_CMD_FLUSH);
 			break;
 
@@ -4330,11 +4355,13 @@
 	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 }
 
-int esp_revoke(Scsi_Device* SDptr)
+void esp_slave_detach(Scsi_Device* SDptr)
 {
 	struct esp *esp = (struct esp *) SDptr->host->hostdata;
 	esp->targets_present &= ~(1 << SDptr->id);
-	return 0;
+	if (SDptr->hostdata)
+		kfree(SDptr->hostdata);
+	SDptr->hostdata = NULL;
 }
 
 static Scsi_Host_Template driver_template = SCSI_SPARC_ESP;
diff -Nru a/drivers/scsi/esp.h b/drivers/scsi/esp.h
--- a/drivers/scsi/esp.h	Fri Oct 11 21:22:51 2002
+++ b/drivers/scsi/esp.h	Fri Oct 11 21:22:51 2002
@@ -8,6 +8,8 @@
 #ifndef _SPARC_ESP_H
 #define _SPARC_ESP_H
 
+#include <linux/config.h>
+
 /* For dvma controller register definitions. */
 #include <asm/dma.h>
 
@@ -62,6 +64,17 @@
 	espunknown = 0x07
 };
 
+/* We allocate one of these for each scsi device and attach it to
+ * SDptr->hostdata for use in the driver
+ */
+struct esp_device {
+  unsigned char sync_min_period;
+  unsigned char sync_max_offset;
+  unsigned sync:1;
+  unsigned wide:1;
+  unsigned disconnect:1;
+};
+
 /* We get one of these for each ESP probed. */
 struct esp {
 	unsigned long		eregs;		/* ESP controller registers */
@@ -397,14 +410,15 @@
 extern int esp_reset(Scsi_Cmnd *, unsigned int);
 extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
 			 int hostno, int inout);
-extern int esp_revoke(Scsi_Device* SDptr);
+extern void esp_slave_detach(Scsi_Device* SDptr);
 
+#ifdef CONFIG_SPARC64
 #define SCSI_SPARC_ESP {                                        \
 		proc_name:      "esp",				\
 		proc_info:      &esp_proc_info,			\
 		name:           "Sun ESP 100/100a/200",		\
 		detect:         esp_detect,			\
-		revoke:		esp_revoke,			\
+		slave_detach:	esp_slave_detach,		\
 		info:           esp_info,			\
 		command:        esp_command,			\
 		queuecommand:   esp_queue,			\
@@ -417,6 +431,26 @@
 		use_clustering: ENABLE_CLUSTERING,		\
 		highmem_io:	1,				\
 }
+#else
+/* Sparc32's iommu code cannot handle highmem pages yet. */
+#define SCSI_SPARC_ESP {                                        \
+		proc_name:      "esp",				\
+		proc_info:      &esp_proc_info,			\
+		name:           "Sun ESP 100/100a/200",		\
+		detect:         esp_detect,			\
+		slave_detach:	esp_slave_detach,		\
+		info:           esp_info,			\
+		command:        esp_command,			\
+		queuecommand:   esp_queue,			\
+		abort:          esp_abort,			\
+		reset:          esp_reset,			\
+		can_queue:      7,				\
+		this_id:        7,				\
+		sg_tablesize:   SG_ALL,				\
+		cmd_per_lun:    1,				\
+		use_clustering: ENABLE_CLUSTERING,		\
+}
+#endif
 
 /* For our interrupt engine. */
 #define for_each_esp(esp) \
diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
--- a/drivers/scsi/fdomain.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/scsi/fdomain.c	Fri Oct 11 21:22:54 2002
@@ -418,7 +418,7 @@
 static int               FIFO_Size = 0x2000; /* 8k FIFO for
 						pre-tmc18c30 chips */
 
-extern void              do_fdomain_16x0_intr( int irq, void *dev_id,
+static void              do_fdomain_16x0_intr( int irq, void *dev_id,
 					    struct pt_regs * regs );
 
 #ifdef MODULE
@@ -528,16 +528,16 @@
    if (!shpnt) return;		/* This won't ever happen */
 
    if (bios_major < 0 && bios_minor < 0) {
-      printk( "scsi%d: <fdomain> No BIOS; using scsi id %d\n",
-	      shpnt->host_no, shpnt->this_id );
+      printk(KERN_INFO "scsi%d: <fdomain> No BIOS; using scsi id %d\n",
+	      shpnt->host_no, shpnt->this_id);
    } else {
-      printk( "scsi%d: <fdomain> BIOS version ", shpnt->host_no );
+      printk(KERN_INFO "scsi%d: <fdomain> BIOS version ", shpnt->host_no);
 
-      if (bios_major >= 0) printk( "%d.", bios_major );
-      else                 printk( "?." );
+      if (bios_major >= 0) printk("%d.", bios_major);
+      else                 printk("?.");
 
-      if (bios_minor >= 0) printk( "%d", bios_minor );
-      else                 printk( "?." );
+      if (bios_minor >= 0) printk("%d", bios_minor);
+      else                 printk("?.");
    
       printk( " at 0x%lx using scsi id %d\n",
 	      bios_base, shpnt->this_id );
@@ -547,31 +547,28 @@
 				   boards, we will have to modify banner
 				   for additional PCI cards, but for now if
 				   it's PCI it's a TMC-3260 - JTM */
-   printk( "scsi%d: <fdomain> %s chip at 0x%x irq ",
+   printk(KERN_INFO "scsi%d: <fdomain> %s chip at 0x%x irq ",
 	   shpnt->host_no,
-	   chip == tmc1800 ? "TMC-1800"
-	   : (chip == tmc18c50 ? "TMC-18C50"
-	      : (chip == tmc18c30 ?
-		 (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30")
-		 : "Unknown")),
-	   port_base );
+	   chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") : "Unknown")),
+	   port_base);
 
-   if (interrupt_level) printk( "%d", interrupt_level );
-   else                 printk( "<none>" );
+   if (interrupt_level)
+   	printk("%d", interrupt_level);
+   else
+        printk("<none>");
 
    printk( "\n" );
 }
 
-static int __init fdomain_setup( char *str )
+static int __init fdomain_setup(char *str)
 {
 	int ints[4];
 
 	(void)get_options(str, ARRAY_SIZE(ints), ints);
 
 	if (setup_called++ || ints[0] < 2 || ints[0] > 3) {
-		printk( "scsi: <fdomain>"
-		" Usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n" );
-		printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
+		printk(KERN_INFO "scsi: <fdomain> Usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n");
+		printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
 		return 0;
 	}
 
@@ -587,9 +584,9 @@
 __setup("fdomain=", fdomain_setup);
 
 
-static void do_pause( unsigned amount )	/* Pause for amount*10 milliseconds */
+static void do_pause(unsigned amount)	/* Pause for amount*10 milliseconds */
 {
-   mdelay(10*amount);
+	mdelay(10*amount);
 }
 
 inline static void fdomain_make_bus_idle( void )
@@ -672,22 +669,20 @@
 
 static int fdomain_get_irq( int base )
 {
-   int options = inb( base + Configuration1 );
+   int options = inb(base + Configuration1);
 
 #if DEBUG_DETECT
-   printk( "scsi: <fdomain> Options = %x\n", options );
+   printk("scsi: <fdomain> Options = %x\n", options);
 #endif
-   
-				/* Check for board with lowest bios_base --
-				   this isn't valid for the 18c30 or for
-				   boards on the PCI bus, so just assume we
-				   have the right board. */
-
-   if (chip != tmc18c30
-       && !PCI_bus
-       && addresses[ (options & 0xc0) >> 6 ] != bios_base) return 0;
+ 
+   /* Check for board with lowest bios_base --
+      this isn't valid for the 18c30 or for
+      boards on the PCI bus, so just assume we
+      have the right board. */
 
-   return ints[ (options & 0x0e) >> 1 ];
+   if (chip != tmc18c30 && !PCI_bus && addresses[(options & 0xc0) >> 6 ] != bios_base)
+   	return 0;
+   return ints[(options & 0x0e) >> 1];
 }
 
 static int fdomain_isa_detect( int *irq, int *iobase )
@@ -700,7 +695,6 @@
    printk( "scsi: <fdomain> fdomain_isa_detect:" );
 #endif
 
-
    for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) {
 #if DEBUG_DETECT
       printk( " %lx(%lx),", addresses[i], bios_base );
@@ -811,8 +805,6 @@
    unsigned long    pci_base;               /* PCI I/O base address */
    struct pci_dev   *pdev = NULL;
 
-   if (!pci_present()) return 0;
-
 #if DEBUG_DETECT
    /* Tell how to print a list of the known PCI devices from bios32 and
       list vendor and device IDs being used if in debug mode.  */
@@ -824,10 +816,8 @@
 	   PCI_DEVICE_ID_FD_36C70 );
 #endif 
 
-   if ((pdev = pci_find_device(PCI_VENDOR_ID_FD,
-			       PCI_DEVICE_ID_FD_36C70,
-			       pdev)) == NULL)
-     return 0;
+   if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
+		return 0;
    if (pci_enable_device(pdev)) return 0;
        
 #if DEBUG_DETECT
@@ -857,8 +847,7 @@
 #endif
 
    if (!fdomain_is_valid_port( *iobase )) {
-      printk( "scsi: <fdomain>"
-	      " PCI card detected, but driver not loaded (invalid port)\n" );
+      printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" );
       return 0;
    }
 
@@ -872,7 +861,7 @@
 }
 #endif
 
-int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
+static int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
 {
    int              retcode;
    struct Scsi_Host *shpnt;
@@ -939,13 +928,12 @@
    Write_FIFO_port       = port_base + Write_FIFO;
    Write_SCSI_Data_port  = port_base + Write_SCSI_Data;
 
-   fdomain_16x0_reset( NULL, 0 );
+   fdomain_16x0_bus_reset( NULL);
 
    if (fdomain_test_loopback()) {
-      printk( "scsi: <fdomain> Detection failed"
-	      " (loopback test failed at port base 0x%x)\n", port_base );
+      printk(KERN_ERR  "scsi: <fdomain> Detection failed (loopback test failed at port base 0x%x)\n", port_base);
       if (setup_called) {
-	 printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
+	 printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
       }
       return 0;
    }
@@ -963,8 +951,8 @@
       }
    }
 
-				/* Print out a banner here in case we can't
-				   get resources.  */
+/* Print out a banner here in case we can't
+   get resources.  */
 
    shpnt = scsi_register( tpnt, 0 );
    if(shpnt == NULL)
@@ -975,10 +963,9 @@
    shpnt->n_io_port = 0x10;
    print_banner( shpnt );
 
-				/* Log IRQ with kernel */   
+   /* Log IRQ with kernel */   
    if (!interrupt_level) {
-      printk( "scsi: <fdomain>"
-	      " Card Detected, but driver not loaded (no IRQ)\n" );
+      printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" );
       return 0;
    } else {
       /* Register the IRQ with the kernel */
@@ -988,25 +975,23 @@
 
       if (retcode < 0) {
 	 if (retcode == -EINVAL) {
-	    printk( "scsi: <fdomain> IRQ %d is bad!\n", interrupt_level );
-	    printk( "                This shouldn't happen!\n" );
-	    printk( "                Send mail to faith@acm.org\n" );
+	    printk(KERN_ERR "scsi: <fdomain> IRQ %d is bad!\n", interrupt_level );
+	    printk(KERN_ERR "                This shouldn't happen!\n" );
+	    printk(KERN_ERR "                Send mail to faith@acm.org\n" );
 	 } else if (retcode == -EBUSY) {
-	    printk( "scsi: <fdomain> IRQ %d is already in use!\n",
-		    interrupt_level );
-	    printk( "                Please use another IRQ!\n" );
+	    printk(KERN_ERR "scsi: <fdomain> IRQ %d is already in use!\n", interrupt_level );
+	    printk(KERN_ERR "                Please use another IRQ!\n" );
 	 } else {
-	    printk( "scsi: <fdomain> Error getting IRQ %d\n",
-		    interrupt_level );
-	    printk( "                This shouldn't happen!\n" );
-	    printk( "                Send mail to faith@acm.org\n" );
+	    printk(KERN_ERR "scsi: <fdomain> Error getting IRQ %d\n", interrupt_level );
+	    printk(KERN_ERR "                This shouldn't happen!\n" );
+	    printk(KERN_ERR "                Send mail to faith@acm.org\n" );
 	 }
-	 printk( "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
+	 printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
 	 return 0;
       }
    }
 
-				/* Log I/O ports with kernel */
+   /* Log I/O ports with kernel */
    request_region( port_base, 0x10, "fdomain" );
 
 #if DO_DETECT
@@ -1065,7 +1050,7 @@
    return 1;			/* Maximum of one adapter will be detected. */
 }
 
-const char *fdomain_16x0_info( struct Scsi_Host *ignore )
+static const char *fdomain_16x0_info( struct Scsi_Host *ignore )
 {
    static char buffer[128];
    char        *pt;
@@ -1097,7 +1082,7 @@
  * length: If inout==FALSE max number of bytes to be written into the buffer 
  *         else number of bytes in the buffer
  */
-int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
+static int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
 			    int length, int hostno, int inout )
 {
    const char *info = fdomain_16x0_info( NULL );
@@ -1105,7 +1090,7 @@
    int        pos;
    int        begin;
 
-   if (inout) return(-ENOSYS);
+   if (inout) return(-EINVAL);
     
    begin = 0;
    strcpy( buffer, info );
@@ -1200,7 +1185,7 @@
    return 1;
 }
 
-void my_done( int error )
+static void my_done(int error)
 {
    if (in_command) {
       in_command = 0;
@@ -1218,7 +1203,7 @@
 #endif
 }
 
-void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
+static void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs )
 {
    unsigned long flags;
    int      status;
@@ -1376,167 +1361,18 @@
       }
    }
 
-   if (chip == tmc1800
-       && !current_SC->SCp.have_data_in
-       && (current_SC->SCp.sent_command
-	   >= current_SC->cmd_len)) {
-				/* We have to get the FIFO direction
-				   correct, so I've made a table based
-				   on the SCSI Standard of which commands
-				   appear to require a DATA OUT phase.
-				 */
-      /*
-	p. 94: Command for all device types
-	CHANGE DEFINITION            40 DATA OUT
-	COMPARE                      39 DATA OUT
-	COPY                         18 DATA OUT
-	COPY AND VERIFY              3a DATA OUT
-	INQUIRY                      12 
-	LOG SELECT                   4c DATA OUT
-	LOG SENSE                    4d
-	MODE SELECT (6)              15 DATA OUT
-	MODE SELECT (10)             55 DATA OUT
-	MODE SENSE (6)               1a
-	MODE SENSE (10)              5a
-	READ BUFFER                  3c
-	RECEIVE DIAGNOSTIC RESULTS   1c
-	REQUEST SENSE                03
-	SEND DIAGNOSTIC              1d DATA OUT
-	TEST UNIT READY              00
-	WRITE BUFFER                 3b DATA OUT
-
-	p.178: Commands for direct-access devices (not listed on p. 94)
-	FORMAT UNIT                  04 DATA OUT
-	LOCK-UNLOCK CACHE            36
-	PRE-FETCH                    34
-	PREVENT-ALLOW MEDIUM REMOVAL 1e
-	READ (6)/RECEIVE             08
-	READ (10)                    3c
-	READ CAPACITY                25
-	READ DEFECT DATA (10)        37
-	READ LONG                    3e
-	REASSIGN BLOCKS              07 DATA OUT
-	RELEASE                      17
-	RESERVE                      16 DATA OUT
-	REZERO UNIT/REWIND           01
-	SEARCH DATA EQUAL (10)       31 DATA OUT
-	SEARCH DATA HIGH (10)        30 DATA OUT
-	SEARCH DATA LOW (10)         32 DATA OUT
-	SEEK (6)                     0b
-	SEEK (10)                    2b
-	SET LIMITS (10)              33
-	START STOP UNIT              1b
-	SYNCHRONIZE CACHE            35
-	VERIFY (10)                  2f
-	WRITE (6)/PRINT/SEND         0a DATA OUT
-	WRITE (10)/SEND              2a DATA OUT
-	WRITE AND VERIFY (10)        2e DATA OUT
-	WRITE LONG                   3f DATA OUT
-	WRITE SAME                   41 DATA OUT ?
-
-	p. 261: Commands for sequential-access devices (not previously listed)
-	ERASE                        19
-	LOAD UNLOAD                  1b
-	LOCATE                       2b
-	READ BLOCK LIMITS            05
-	READ POSITION                34
-	READ REVERSE                 0f
-	RECOVER BUFFERED DATA        14
-	SPACE                        11
-	WRITE FILEMARKS              10 ?
-
-	p. 298: Commands for printer devices (not previously listed)
-	****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
-	SLEW AND PRINT               0b DATA OUT  -- same as seek
-	STOP PRINT                   1b
-	SYNCHRONIZE BUFFER           10
-
-	p. 315: Commands for processor devices (not previously listed)
-	
-	p. 321: Commands for write-once devices (not previously listed)
-	MEDIUM SCAN                  38
-	READ (12)                    a8
-	SEARCH DATA EQUAL (12)       b1 DATA OUT
-	SEARCH DATA HIGH (12)        b0 DATA OUT
-	SEARCH DATA LOW (12)         b2 DATA OUT
-	SET LIMITS (12)              b3
-	VERIFY (12)                  af
-	WRITE (12)                   aa DATA OUT
-	WRITE AND VERIFY (12)        ae DATA OUT
-
-	p. 332: Commands for CD-ROM devices (not previously listed)
-	PAUSE/RESUME                 4b
-	PLAY AUDIO (10)              45
-	PLAY AUDIO (12)              a5
-	PLAY AUDIO MSF               47
-	PLAY TRACK RELATIVE (10)     49
-	PLAY TRACK RELATIVE (12)     a9
-	READ HEADER                  44
-	READ SUB-CHANNEL             42
-	READ TOC                     43
-
-	p. 370: Commands for scanner devices (not previously listed)
-	GET DATA BUFFER STATUS       34
-	GET WINDOW                   25
-	OBJECT POSITION              31
-	SCAN                         1b
-	SET WINDOW                   24 DATA OUT
-
-	p. 391: Commands for optical memory devices (not listed)
-	ERASE (10)                   2c
-	ERASE (12)                   ac
-	MEDIUM SCAN                  38 DATA OUT
-	READ DEFECT DATA (12)        b7
-	READ GENERATION              29
-	READ UPDATED BLOCK           2d
-	UPDATE BLOCK                 3d DATA OUT
-
-	p. 419: Commands for medium changer devices (not listed)
-	EXCHANGE MEDIUM              46
-	INITIALIZE ELEMENT STATUS    07
-	MOVE MEDIUM                  a5
-	POSITION TO ELEMENT          2b
-	READ ELEMENT STATUS          b8
-	REQUEST VOL. ELEMENT ADDRESS b5
-	SEND VOLUME TAG              b6 DATA OUT
-
-	p. 454: Commands for communications devices (not listed previously)
-	GET MESSAGE (6)              08
-	GET MESSAGE (10)             28
-	GET MESSAGE (12)             a8
-      */
-	
-      switch (current_SC->cmnd[0]) {
-      case CHANGE_DEFINITION: case COMPARE:         case COPY:
-      case COPY_VERIFY:       case LOG_SELECT:      case MODE_SELECT:
-      case MODE_SELECT_10:    case SEND_DIAGNOSTIC: case WRITE_BUFFER:
-
-      case FORMAT_UNIT:       case REASSIGN_BLOCKS: case RESERVE:
-      case SEARCH_EQUAL:      case SEARCH_HIGH:     case SEARCH_LOW:
-      case WRITE_6:           case WRITE_10:        case WRITE_VERIFY:
-      case 0x3f:              case 0x41:
-
-      case 0xb1:              case 0xb0:            case 0xb2:
-      case 0xaa:              case 0xae:
-
-      case 0x24:
-
-      case 0x38:              case 0x3d:
-
-      case 0xb6:
-	 
-      case 0xea:		/* alternate number for WRITE LONG */
-	 
+   if (chip == tmc1800 && !current_SC->SCp.have_data_in
+       && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
+      
+      if(scsi_to_pci_dma_dir(current_SC->sc_data_direction)	== PCI_DMA_TODEVICE)
+      {
 	 current_SC->SCp.have_data_in = -1;
 	 outb( 0xd0 | PARITY_MASK, TMC_Cntl_port );
-	 break;
-
-      case 0x00:
-      default:
-	 
+      }
+      else
+      {
 	 current_SC->SCp.have_data_in = 1;
 	 outb( 0x90 | PARITY_MASK, TMC_Cntl_port );
-	 break;
       }
    }
 
@@ -1565,7 +1401,7 @@
 	    if (current_SC->SCp.buffers_residual) {
 	       --current_SC->SCp.buffers_residual;
 	       ++current_SC->SCp.buffer;
-	       current_SC->SCp.ptr = current_SC->SCp.buffer->address;
+	       current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
 	       current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
 	    } else
 		  break;
@@ -1598,7 +1434,7 @@
 	     && current_SC->SCp.buffers_residual) {
 	    --current_SC->SCp.buffers_residual;
 	    ++current_SC->SCp.buffer;
-	    current_SC->SCp.ptr = current_SC->SCp.buffer->address;
+	    current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
 	    current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
 	 }
       }
@@ -1661,7 +1497,7 @@
    return;
 }
 
-int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+static int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 {
    if (in_command) {
       panic( "scsi: <fdomain> fdomain_16x0_queue() NOT REENTRANT!\n" );
@@ -1684,7 +1520,7 @@
    if (current_SC->use_sg) {
       current_SC->SCp.buffer =
 	    (struct scatterlist *)current_SC->request_buffer;
-      current_SC->SCp.ptr              = current_SC->SCp.buffer->address;
+      current_SC->SCp.ptr              = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
       current_SC->SCp.this_residual    = current_SC->SCp.buffer->length;
       current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
    } else {
@@ -1719,45 +1555,45 @@
 static volatile int internal_done_flag    = 0;
 static volatile int internal_done_errcode = 0;
 
-static void internal_done( Scsi_Cmnd *SCpnt )
+static void internal_done(Scsi_Cmnd *SCpnt)
 {
     internal_done_errcode = SCpnt->result;
     ++internal_done_flag;
 }
 
-int fdomain_16x0_command( Scsi_Cmnd *SCpnt )
+static int fdomain_16x0_command(Scsi_Cmnd *SCpnt)
 {
-    fdomain_16x0_queue( SCpnt, internal_done );
+    fdomain_16x0_queue(SCpnt, internal_done);
 
     while (!internal_done_flag)
-	  ;
+	  cpu_relax();
     internal_done_flag = 0;
     return internal_done_errcode;
 }
 
 /* End of code derived from Tommy Thorn's work. */
 
-void print_info( Scsi_Cmnd *SCpnt )
+static void print_info(Scsi_Cmnd *SCpnt)
 {
    unsigned int imr;
    unsigned int irr;
    unsigned int isr;
 
    if (!SCpnt || !SCpnt->host) {
-      printk( "scsi: <fdomain> Cannot provide detailed information\n" );
+      printk(KERN_WARNING "scsi: <fdomain> Cannot provide detailed information\n");
       return;
    }
    
-   printk( "%s\n", fdomain_16x0_info( SCpnt->host ) );
-   print_banner( SCpnt->host );
+   printk(KERN_INFO "%s\n", fdomain_16x0_info( SCpnt->host ) );
+   print_banner(SCpnt->host);
    switch (SCpnt->SCp.phase) {
-   case in_arbitration: printk( "arbitration " ); break;
-   case in_selection:   printk( "selection " );   break;
-   case in_other:       printk( "other " );       break;
-   default:             printk( "unknown " );     break;
+   case in_arbitration: printk("arbitration"); break;
+   case in_selection:   printk("selection");   break;
+   case in_other:       printk("other");       break;
+   default:             printk("unknown");     break;
    }
 
-   printk( "(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+   printk( " (%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
 	   SCpnt->SCp.phase,
 	   SCpnt->target,
 	   *(unsigned char *)SCpnt->cmnd,
@@ -1807,21 +1643,17 @@
 		 inb( port_base + Configuration2 ) );
 }
 
-int fdomain_16x0_abort( Scsi_Cmnd *SCpnt)
+static int fdomain_16x0_abort( Scsi_Cmnd *SCpnt)
 {
-   unsigned long flags;
 #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
    printk( "scsi: <fdomain> abort " );
 #endif
 
-   save_flags( flags );
-   cli();
    if (!in_command) {
 #if EVERY_ACCESS || ERRORS_ONLY
       printk( " (not in command)\n" );
 #endif
-      restore_flags( flags );
-      return SCSI_ABORT_NOT_RUNNING;
+      return FAILED;
    } else printk( "\n" );
 
 #if DEBUG_ABORT
@@ -1829,52 +1661,39 @@
 #endif
 
    fdomain_make_bus_idle();
-
    current_SC->SCp.phase |= aborted;
-
    current_SC->result = DID_ABORT << 16;
-
-   restore_flags( flags );
    
    /* Aborts are not done well. . . */
-   my_done( DID_ABORT << 16 );
-
-   return SCSI_ABORT_SUCCESS;
+   my_done(DID_ABORT << 16);
+   return SUCCESS;
 }
 
-int fdomain_16x0_reset( Scsi_Cmnd *SCpnt, unsigned int ignored )
+static int fdomain_16x0_bus_reset(Scsi_Cmnd *SCpnt)
 {
-#if DEBUG_RESET
-   static int called_once = 0;
-#endif
-
-#if ERRORS_ONLY
-   if (SCpnt) printk( "scsi: <fdomain> SCSI Bus Reset\n" );
-#endif
-
-#if DEBUG_RESET
-   if (called_once) print_info( current_SC );
-   called_once = 1;
-#endif
-   
    outb( 1, SCSI_Cntl_port );
    do_pause( 2 );
    outb( 0, SCSI_Cntl_port );
    do_pause( 115 );
    outb( 0, SCSI_Mode_Cntl_port );
    outb( PARITY_MASK, TMC_Cntl_port );
+   return SUCCESS;
+}
 
-   /* Unless this is the very first call (i.e., SCPnt == NULL), everything
-      is probably hosed at this point.  We will, however, try to keep
-      things going by informing the high-level code that we need help. */
+static int fdomain_16x0_host_reset(Scsi_Cmnd *SCpnt)
+{
+  return FAILED;
+}
 
-   return SCSI_RESET_WAKEUP;
+static int fdomain_16x0_device_reset(Scsi_Cmnd *SCpnt)
+{
+  return FAILED;
 }
 
 #include "sd.h"
 #include <scsi/scsi_ioctl.h>
 
-int fdomain_16x0_biosparam( Scsi_Disk *disk, struct block_device *bdev, int *info_array )
+static int fdomain_16x0_biosparam(Scsi_Disk *disk, struct block_device *bdev, int *info_array)
 {
    int              drive;
    unsigned char    buf[512 + sizeof (Scsi_Ioctl_Command)];
@@ -2036,7 +1855,7 @@
    return 0;
 }
 
-int fdomain_16x0_release(struct Scsi_Host *shpnt)
+static int fdomain_16x0_release(struct Scsi_Host *shpnt)
 {
 	if (shpnt->irq)
 		free_irq(shpnt->irq, shpnt);
diff -Nru a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
--- a/drivers/scsi/fdomain.h	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/fdomain.h	Fri Oct 11 21:22:55 2002
@@ -25,29 +25,34 @@
 #ifndef _FDOMAIN_H
 #define _FDOMAIN_H
 
-int        fdomain_16x0_detect( Scsi_Host_Template * );
-int        fdomain_16x0_command( Scsi_Cmnd * );
-int        fdomain_16x0_abort( Scsi_Cmnd * );
-const char *fdomain_16x0_info( struct Scsi_Host * );
-int        fdomain_16x0_reset( Scsi_Cmnd *, unsigned int ); 
-int        fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
-int        fdomain_16x0_biosparam( Disk *, struct block_device *, int * );
-int        fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
+static int        fdomain_16x0_detect( Scsi_Host_Template *);
+static int        fdomain_16x0_command( Scsi_Cmnd *);
+static int        fdomain_16x0_abort(Scsi_Cmnd *);
+static const char *fdomain_16x0_info(struct Scsi_Host *);
+static int        fdomain_16x0_bus_reset(Scsi_Cmnd *); 
+static int        fdomain_16x0_host_reset(Scsi_Cmnd *); 
+static int        fdomain_16x0_device_reset(Scsi_Cmnd *); 
+static int        fdomain_16x0_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int        fdomain_16x0_biosparam(Disk *, struct block_device *, int * );
+static int        fdomain_16x0_proc_info(char *buffer, char **start, off_t offset,
 				   int length, int hostno, int inout );
-int        fdomain_16x0_release( struct Scsi_Host *shpnt );
+static int        fdomain_16x0_release(struct Scsi_Host *shpnt);
 
-#define FDOMAIN_16X0 { proc_info:      fdomain_16x0_proc_info,           \
-		       detect:         fdomain_16x0_detect,              \
-		       info:           fdomain_16x0_info,                \
-		       command:        fdomain_16x0_command,             \
-		       queuecommand:   fdomain_16x0_queue,               \
-		       abort:          fdomain_16x0_abort,               \
-		       reset:          fdomain_16x0_reset,               \
-		       bios_param:     fdomain_16x0_biosparam,           \
-		       release:        fdomain_16x0_release,		 \
-		       can_queue:      1, 				 \
-		       this_id:        6, 				 \
-		       sg_tablesize:   64, 				 \
-		       cmd_per_lun:    1, 				 \
-		       use_clustering: DISABLE_CLUSTERING }
+#define FDOMAIN_16X0 { proc_info:      		fdomain_16x0_proc_info,           \
+		       detect:         		fdomain_16x0_detect,              \
+		       info:           		fdomain_16x0_info,                \
+		       command:        		fdomain_16x0_command,             \
+		       queuecommand:   		fdomain_16x0_queue,               \
+		       eh_abort_handler:	fdomain_16x0_abort,               \
+		       eh_bus_reset_handler:	fdomain_16x0_bus_reset,           \
+		       eh_device_reset_handler:	fdomain_16x0_device_reset,        \
+		       eh_host_reset_handler:	fdomain_16x0_host_reset,          \
+		       bios_param:		fdomain_16x0_biosparam,           \
+		       release:			fdomain_16x0_release,		  \
+		       can_queue:		1, 				  \
+		       this_id:  		6, 				  \
+		       sg_tablesize:		64, 				  \
+		       cmd_per_lun:		1, 				  \
+		       use_clustering:		DISABLE_CLUSTERING		  \
+}
 #endif
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/hosts.h	Fri Oct 11 21:22:55 2002
@@ -97,6 +97,10 @@
      */
     int (* detect)(struct SHT *);
 
+    /*
+     * This function is only used by one driver and will be going away
+     * once it switches over to using the slave_detach() function instead.
+     */
     int (*revoke)(Scsi_Device *);
 
     /* Used with loadable modules to unload the host structures.  Note:
@@ -200,11 +204,59 @@
     int (* reset)(Scsi_Cmnd *, unsigned int);
 
     /*
-     * This function is used to select synchronous communications,
-     * which will result in a higher data throughput.  Not implemented
-     * yet.
+     * Once the device has responded to an INQUIRY and we know the device
+     * is online, call into the low level driver with the Scsi_Device *
+     * (so that the low level driver may save it off in a safe location
+     * for later use in calling scsi_adjust_queue_depth() or possibly
+     * other scsi_* functions) and char * to the INQUIRY return data buffer.
+     * This way, low level drivers will no longer have to snoop INQUIRY data
+     * to see if a drive supports PPR message protocol for Ultra160 speed
+     * negotiations or other similar items.  Instead it can simply wait until
+     * the scsi mid layer calls them with the data in hand and then it can
+     * do it's checking of INQUIRY data.  This will happen once for each new
+     * device added on this controller (including once for each lun on
+     * multi-lun devices, so low level drivers should take care to make
+     * sure that if they do tagged queueing on a per physical unit basis
+     * instead of a per logical unit basis that they have the mid layer
+     * allocate tags accordingly).
+     *
+     * Things currently recommended to be handled at this time include:
+     *
+     * 1.  Checking for tagged queueing capability and if able then calling
+     *     scsi_adjust_queue_depth() with the device pointer and the
+     *     suggested new queue depth.
+     * 2.  Checking for things such as SCSI level or DT bit in order to
+     *     determine if PPR message protocols are appropriate on this
+     *     device (or any other scsi INQUIRY data specific things the
+     *     driver wants to know in order to properly handle this device).
+     * 3.  Allocating command structs that the device will need.
+     * 4.  Setting the default timeout on this device (if needed).
+     * 5.  Saving the Scsi_Device pointer so that the low level driver
+     *     will be able to easily call back into scsi_adjust_queue_depth
+     *     again should it be determined that the queue depth for this
+     *     device should be lower or higher than it is initially set to.
+     * 6.  Allocate device data structures as needed that can be attached
+     *     to the Scsi_Device * via SDpnt->host_device_ptr
+     * 7.  Anything else the low level driver might want to do on a device
+     *     specific setup basis...
+     * 8.  Return 0 on success, non-0 on error.  The device will be marked
+     *     as offline on error so that no access will occur.
+     */
+    int (* slave_attach)(Scsi_Device *);
+
+    /*
+     * If we are getting ready to remove a device from the scsi chain then
+     * we call into the low level driver to let them know.  Once a low
+     * level driver has been informed that a drive is going away, the low
+     * level driver *must* remove it's pointer to the Scsi_Device because
+     * it is going to be kfree()'ed shortly.  It is no longer safe to call
+     * any mid layer functions with this Scsi_Device *.  Additionally, the
+     * mid layer will not make any more calls into the low level driver's
+     * queue routine with this device, so it is safe for the device driver
+     * to deallocate all structs/commands/etc that is has allocated
+     * specifically for this device at the time of this call.
      */
-    int (* slave_attach)(int, int);
+    void (* slave_detach)(Scsi_Device *);
 
     /*
      * This function determines the bios parameters for a given
@@ -217,6 +269,8 @@
 
     /*
      * Used to set the queue depth for a specific device.
+     *
+     * Once the slave_attach() function is in full use, this will go away.
      */
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
diff -Nru a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
--- a/drivers/scsi/ibmmca.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/scsi/ibmmca.c	Fri Oct 11 21:22:53 2002
@@ -2384,17 +2384,18 @@
 
 int ibmmca_biosparam (Disk * disk, struct block_device *dev, int *info)
 {
+   int size = disk->capacity;
    info[0] = 64;
    info[1] = 32;
-   info[2] = disk->capacity / (info[0] * info[1]);
+   info[2] = size / (info[0] * info[1]);
    if (info[2] >= 1024) {
       info[0] = 128;
       info[1] = 63;
-      info[2] = disk->capacity / (info[0] * info[1]);
+      info[2] = size / (info[0] * info[1]);
       if (info[2] >= 1024) {
 	 info[0] = 255;
 	 info[1] = 63;
-	 info[2] = disk->capacity / (info[0] * info[1]);
+	 info[2] = size / (info[0] * info[1]);
 	 if (info[2] >= 1024)
 	   info[2] = 1023;
       }
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/scsi/ide-scsi.c	Fri Oct 11 21:23:00 2002
@@ -487,7 +487,7 @@
 /*
  *	idescsi_do_request is our request handling function.
  */
-static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
 {
 #if IDESCSI_DEBUG_LOG
 	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c
--- a/drivers/scsi/imm.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/scsi/imm.c	Fri Oct 11 21:23:05 2002
@@ -27,8 +27,10 @@
 #include <linux/blk.h>
 #include <asm/io.h>
 #include <linux/parport.h>
+#include <linux/workqueue.h>
 #include "sd.h"
 #include "hosts.h"
+
 typedef struct {
     struct pardevice *dev;	/* Parport device entry         */
     int base;			/* Actual port address          */
@@ -1117,11 +1119,11 @@
 {
     ip[0] = 0x40;
     ip[1] = 0x20;
-    ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+    ip[2] = ((unsigned long)disk->capacity + 1) / (ip[0] * ip[1]);
     if (ip[2] > 1024) {
 	ip[0] = 0xff;
 	ip[1] = 0x3f;
-	ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+	ip[2] = ((unsigned long)disk->capacity + 1) / (ip[0] * ip[1]);
     }
     return 0;
 }
diff -Nru a/drivers/scsi/imm.h b/drivers/scsi/imm.h
--- a/drivers/scsi/imm.h	Fri Oct 11 21:22:50 2002
+++ b/drivers/scsi/imm.h	Fri Oct 11 21:22:50 2002
@@ -71,7 +71,6 @@
 #include  <linux/stddef.h>
 #include  <linux/module.h>
 #include  <linux/kernel.h>
-#include  <linux/tqueue.h>
 #include  <linux/ioport.h>
 #include  <linux/delay.h>
 #include  <linux/proc_fs.h>
diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
--- a/drivers/scsi/in2000.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/scsi/in2000.c	Fri Oct 11 21:23:02 2002
@@ -317,13 +317,15 @@
 
 static void in2000_execute(struct Scsi_Host *instance);
 
-int in2000_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int in2000_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
+struct Scsi_Host *instance;
 struct IN2000_hostdata *hostdata;
 Scsi_Cmnd *tmp;
 unsigned long flags;
 
-   hostdata = (struct IN2000_hostdata *)cmd->host->hostdata;
+   instance = cmd->host;
+   hostdata = (struct IN2000_hostdata *)instance->hostdata;
 
 DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld(",cmd->target,cmd->cmnd[0],cmd->pid))
 
@@ -355,7 +357,7 @@
    if (cmd->use_sg) {
       cmd->SCp.buffer = (struct scatterlist *)cmd->buffer;
       cmd->SCp.buffers_residual = cmd->use_sg - 1;
-      cmd->SCp.ptr = (char *)cmd->SCp.buffer->address;
+      cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+cmd->SCp.buffer->offset;
       cmd->SCp.this_residual = cmd->SCp.buffer->length;
       }
    else {
@@ -391,9 +393,7 @@
  * queue and calling in2000_execute().
  */
 
-   save_flags(flags);
-   cli();
-
+   spin_lock_irqsave(instance->host_lock, flags);
    /*
     * Add the cmd to the end of 'input_Q'. Note that REQUEST_SENSE
     * commands are added to the head of the queue so that the desired
@@ -418,8 +418,7 @@
    in2000_execute(cmd->host);
 
 DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
-
-   restore_flags(flags);
+   spin_unlock_irqrestore(instance->host_lock, flags);
    return 0;
 }
 
@@ -762,7 +761,7 @@
       ++cmd->SCp.buffer;
       --cmd->SCp.buffers_residual;
       cmd->SCp.this_residual = cmd->SCp.buffer->length;
-      cmd->SCp.ptr = cmd->SCp.buffer->address;
+      cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
       }
 
 /* Set up hardware registers */
@@ -855,7 +854,7 @@
 
 /* Get the spin_lock and disable further ints, for SMP */
 
-   CLISPIN_LOCK(instance, flags);
+   spin_lock_irqsave(instance->host_lock, flags);
 
 #ifdef PROC_STATISTICS
    hostdata->int_cnt++;
@@ -993,7 +992,7 @@
       write1_io(0, IO_LED_OFF);
 
 /* release the SMP spin_lock and restore irq state */
-      CLISPIN_UNLOCK(instance, flags);
+      spin_unlock_irqrestore(instance->host_lock, flags);
       return;
       }
 
@@ -1011,7 +1010,7 @@
       write1_io(0, IO_LED_OFF);
 
 /* release the SMP spin_lock and restore irq state */
-      CLISPIN_UNLOCK(instance, flags);
+      spin_unlock_irqrestore(instance->host_lock, flags);
       return;
       }
 
@@ -1433,7 +1432,7 @@
             hostdata->state = S_UNCONNECTED;
 
 /* release the SMP spin_lock and restore irq state */
-            CLISPIN_UNLOCK(instance, flags);
+            spin_unlock_irqrestore(instance->host_lock, flags);
             return;
             }
 DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
@@ -1609,7 +1608,7 @@
 DB(DB_INTR,printk("} "))
 
 /* release the SMP spin_lock and restore irq state */
-   CLISPIN_UNLOCK(instance, flags);
+   spin_unlock_irqrestore(instance->host_lock, flags);
 
 }
 
@@ -1619,11 +1618,14 @@
 #define RESET_CARD_AND_BUS 1
 #define B_FLAG 0x80
 
+/*
+ *	Caller must hold instance lock!
+ */
+ 
 static int reset_hardware(struct Scsi_Host *instance, int type)
 {
 struct IN2000_hostdata *hostdata;
 int qt,x;
-unsigned long flags;
 
    hostdata = (struct IN2000_hostdata *)instance->hostdata;
 
@@ -1638,16 +1640,16 @@
    write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
    write_3393(hostdata,WD_SYNCHRONOUS_TRANSFER,
               calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF));
-   save_flags(flags);
-   cli();
+
    write1_io(0,IO_FIFO_WRITE);            /* clear fifo counter */
    write1_io(0,IO_FIFO_READ);             /* start fifo out in read mode */
    write_3393(hostdata,WD_COMMAND, WD_CMD_RESET);
+   /* FIXME: timeout ?? */
    while (!(READ_AUX_STAT() & ASR_INT))
-      ;                                   /* wait for RESET to complete */
+      cpu_relax();                           /* wait for RESET to complete */
 
    x = read_3393(hostdata,WD_SCSI_STATUS);   /* clear interrupt */
-   restore_flags(flags);
+
    write_3393(hostdata,WD_QUEUE_TAG,0xa5);   /* any random number */
    qt = read_3393(hostdata,WD_QUEUE_TAG);
    if (qt == 0xa5) {
@@ -1662,7 +1664,7 @@
 
 
 
-int in2000_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int in2000_bus_reset(Scsi_Cmnd *cmd)
 {
 unsigned long flags;
 struct Scsi_Host *instance;
@@ -1672,10 +1674,9 @@
    instance = cmd->host;
    hostdata = (struct IN2000_hostdata *)instance->hostdata;
 
-   printk("scsi%d: Reset. ", instance->host_no);
-   save_flags(flags);
-   cli();
+   printk(KERN_WARNING "scsi%d: Reset. ", instance->host_no);
 
+   spin_lock_irqsave(instance->host_lock, flags);
    /* do scsi-reset here */
 
    reset_hardware(instance, RESET_CARD_AND_BUS);
@@ -1694,13 +1695,22 @@
    hostdata->outgoing_len = 0;
 
    cmd->result = DID_RESET << 16;
-   restore_flags(flags);
-   return 0;
+   spin_unlock_irqrestore(instance->host_lock, flags);
+   return SUCCESS;
 }
 
+static int in2000_host_reset(Scsi_Cmnd *cmd)
+{
+	return FAILED;
+}
 
+static int in2000_device_reset(Scsi_Cmnd *cmd)
+{
+	return FAILED;
+}
 
-int in2000_abort (Scsi_Cmnd *cmd)
+
+static int in2000_abort (Scsi_Cmnd *cmd)
 {
 struct Scsi_Host *instance;
 struct IN2000_hostdata *hostdata;
@@ -1709,13 +1719,10 @@
 uchar sr, asr;
 unsigned long timeout;
 
-   save_flags (flags);
-   cli();
-
    instance = cmd->host;
    hostdata = (struct IN2000_hostdata *)instance->hostdata;
 
-   printk ("scsi%d: Abort-", instance->host_no);
+   printk(KERN_DEBUG "scsi%d: Abort-", instance->host_no);
    printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ",
             READ_AUX_STAT(),read_3393_count(hostdata),cmd->SCp.this_residual,cmd->SCp.buffers_residual,
             cmd->SCp.have_data_in,read1_io(IO_FIFO_COUNT));
@@ -1725,6 +1732,7 @@
  *     from the inout_Q.
  */
 
+   spin_lock_irqsave(instance->host_lock, flags);
    tmp = (Scsi_Cmnd *)hostdata->input_Q;
    prev = 0;
    while (tmp) {
@@ -1733,11 +1741,11 @@
             prev->host_scribble = cmd->host_scribble;
          cmd->host_scribble = NULL;
          cmd->result = DID_ABORT << 16;
-         printk("scsi%d: Abort - removing command %ld from input_Q. ",
+         printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ",
            instance->host_no, cmd->pid);
          cmd->scsi_done(cmd);
-         restore_flags(flags);
-         return SCSI_ABORT_SUCCESS;
+         spin_unlock_irqrestore(instance->host_lock, flags);
+         return SUCCESS;
          }
       prev = tmp;
       tmp = (Scsi_Cmnd *)tmp->host_scribble;
@@ -1756,7 +1764,7 @@
 
    if (hostdata->connected == cmd) {
 
-      printk("scsi%d: Aborting connected command %ld - ",
+      printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ",
               instance->host_no, cmd->pid);
 
       printk("sending wd33c93 ABORT command - ");
@@ -1800,7 +1808,6 @@
 
       in2000_execute (instance);
 
-      restore_flags(flags);
       return SCSI_ABORT_SUCCESS;
       }
 
@@ -1813,9 +1820,9 @@
    for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp;
          tmp=(Scsi_Cmnd *)tmp->host_scribble)
       if (cmd == tmp) {
-         restore_flags(flags);
-         printk("Sending ABORT_SNOOZE. ");
-         return SCSI_ABORT_SNOOZE;
+	 spin_unlock_irqrestore(instance->host_lock, flags);
+	 printk(KERN_DEBUG "scsi%d: unable to abort disconnected command.\n", instance->host_no);
+         return FAILED;
          }
 
 /*
@@ -1830,10 +1837,10 @@
 
    in2000_execute (instance);
 
-   restore_flags(flags);
+   spin_unlock_irqrestore(instance->host_lock, flags);
    printk("scsi%d: warning : SCSI command probably completed successfully"
       "         before abortion. ", instance->host_no);
-   return SCSI_ABORT_NOT_RUNNING;
+   return SUCCESS;
 }
 
 
@@ -1845,7 +1852,7 @@
 static char setup_used[MAX_SETUP_ARGS];
 static int done_setup = 0;
 
-void __init in2000_setup (char *str, int *ints)
+static void __init in2000_setup (char *str, int *ints)
 {
 int i;
 char *p1,*p2;
@@ -1931,7 +1938,7 @@
    };
 
 
-int __init in2000_detect(Scsi_Host_Template * tpnt)
+static int __init in2000_detect(Scsi_Host_Template * tpnt)
 {
 struct Scsi_Host *instance;
 struct IN2000_hostdata *hostdata;
@@ -2115,7 +2122,11 @@
 #endif
 
 
+      /* FIXME: not strictly needed I think but the called code expects
+         to be locked */
+      spin_lock_irqsave(instance->host_lock, flags);
       x = reset_hardware(instance,(hostdata->args & A_NO_SCSI_RESET)?RESET_CARD:RESET_CARD_AND_BUS);
+      spin_unlock_irqrestore(instance->host_lock, flags);
 
       hostdata->microcode = read_3393(hostdata,WD_CDB_1);
       if (x & 0x01) {
@@ -2158,7 +2169,7 @@
  *       supposed to do...
  */
 
-int in2000_biosparam(Disk *disk, struct block_device *dev, int *iinfo)
+static int in2000_biosparam(Disk *disk, struct block_device *dev, int *iinfo)
 {
 int size;
 
@@ -2174,23 +2185,23 @@
    if (iinfo[2] > 1024) {
       iinfo[0] = 64;
       iinfo[1] = 63;
-      iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
+      iinfo[2] = (unsigned long)disk->capacity / (iinfo[0] * iinfo[1]);
       }
    if (iinfo[2] > 1024) {
       iinfo[0] = 128;
       iinfo[1] = 63;
-      iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
+      iinfo[2] = (unsigned long)disk->capacity / (iinfo[0] * iinfo[1]);
       }
    if (iinfo[2] > 1024) {
       iinfo[0] = 255;
       iinfo[1] = 63;
-      iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
+      iinfo[2] = (unsigned long)disk->capacity / (iinfo[0] * iinfo[1]);
       }
     return 0;
 }
 
 
-int in2000_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
+static int in2000_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
 {
 
 #ifdef PROC_INTERFACE
@@ -2260,8 +2271,7 @@
       return len;
       }
 
-   save_flags(flags);
-   cli();
+   spin_lock_irqsave(instance->host_lock, flags);
    bp = buf;
    *bp = '\0';
    if (hd->proc & PR_VERSION) {
@@ -2340,7 +2350,7 @@
       ;  /* insert your own custom function here */
       }
    strcat(bp,"\n");
-   restore_flags(flags);
+   spin_unlock_irqrestore(instance->host_lock, flags);
    *start = buf;
    if (stop) {
       stop = 0;
diff -Nru a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
--- a/drivers/scsi/in2000.h	Fri Oct 11 21:22:50 2002
+++ b/drivers/scsi/in2000.h	Fri Oct 11 21:22:50 2002
@@ -397,13 +397,15 @@
 # define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(host->host_lock, \
 							   flags)
 
-int in2000_detect(Scsi_Host_Template *) in2000__INIT;
-int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int in2000_abort(Scsi_Cmnd *);
-void in2000_setup(char *, int *) in2000__INIT;
-int in2000_proc_info(char *, char **, off_t, int, int, int);
-int in2000_biosparam(struct scsi_disk *, struct block_device *, int *);
-int in2000_reset(Scsi_Cmnd *, unsigned int);
+static int in2000_detect(Scsi_Host_Template *) in2000__INIT;
+static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int in2000_abort(Scsi_Cmnd *);
+static void in2000_setup(char *, int *) in2000__INIT;
+static int in2000_proc_info(char *, char **, off_t, int, int, int);
+static int in2000_biosparam(struct scsi_disk *, struct block_device *, int *);
+static int in2000_host_reset(Scsi_Cmnd *);
+static int in2000_bus_reset(Scsi_Cmnd *);
+static int in2000_device_reset(Scsi_Cmnd *);
 
 
 #define IN2000_CAN_Q    16
@@ -411,19 +413,21 @@
 #define IN2000_CPL      2
 #define IN2000_HOST_ID  7
 
-#define IN2000 {  proc_name:       "in2000",		/* name of /proc/scsi directory entry */ \
-                  proc_info:       in2000_proc_info,    /* pointer to proc info function */ \
-                  name:            "Always IN2000",     /* device name */ \
-                  detect:          in2000_detect,       /* returns number of in2000's found */ \
-                  queuecommand:    in2000_queuecommand, /* queue scsi command, don't wait */ \
-                  abort:           in2000_abort,        /* abort current command */ \
-                  reset:           in2000_reset,        /* reset scsi bus */ \
-                  bios_param:      in2000_biosparam,    /* figures out BIOS parameters for lilo, etc */ \
-                  can_queue:       IN2000_CAN_Q,        /* max commands we can queue up */ \
-                  this_id:         IN2000_HOST_ID,      /* host-adapter scsi id */ \
-                  sg_tablesize:    IN2000_SG,           /* scatter-gather table size */ \
-                  cmd_per_lun:     IN2000_CPL,          /* commands per lun */ \
-                  use_clustering:  DISABLE_CLUSTERING,  /* ENABLE_CLUSTERING may speed things up */ \
+#define IN2000 {  proc_name:       		"in2000",	     /* name of /proc/scsi directory entry */ \
+                  proc_info:       		in2000_proc_info,    /* pointer to proc info function */ \
+                  name:            		"Always IN2000",     /* device name */ \
+                  detect:          		in2000_detect,       /* returns number of in2000's found */ \
+                  queuecommand:    		in2000_queuecommand, /* queue scsi command, don't wait */ \
+                  eh_abort_handler:		in2000_abort,        /* abort current command */ \
+                  eh_bus_reset_handler:		in2000_bus_reset,    /* reset scsi bus */ \
+                  eh_device_reset_handler:	in2000_device_reset, /* reset scsi device */ \
+                  eh_host_reset_handler:	in2000_host_reset,   /* reset scsi hba */ \
+                  bios_param:      		in2000_biosparam,    /* figures out BIOS parameters for lilo, etc */ \
+                  can_queue:       		IN2000_CAN_Q,        /* max commands we can queue up */ \
+                  this_id:         		IN2000_HOST_ID,      /* host-adapter scsi id */ \
+                  sg_tablesize:    		IN2000_SG,           /* scatter-gather table size */ \
+                  cmd_per_lun:     		IN2000_CPL,          /* commands per lun */ \
+                  use_clustering:  		DISABLE_CLUSTERING,  /* ENABLE_CLUSTERING may speed things up */ \
                 }
 
 #endif /* IN2000_H */
diff -Nru a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c
--- a/drivers/scsi/ini9100u.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/ini9100u.c	Fri Oct 11 21:22:55 2002
@@ -594,16 +594,16 @@
 	if (pTcb->TCS_DrvHead) {
 		info_array[0] = pTcb->TCS_DrvHead;
 		info_array[1] = pTcb->TCS_DrvSector;
-		info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+		info_array[2] = (unsigned long)disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
 	} else {
 		if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
 			info_array[0] = 255;
 			info_array[1] = 63;
-			info_array[2] = disk->capacity / 255 / 63;
+			info_array[2] = (unsigned long)disk->capacity / 255 / 63;
 		} else {
 			info_array[0] = 64;
 			info_array[1] = 32;
-			info_array[2] = disk->capacity >> 11;
+			info_array[2] = (unsigned long)disk->capacity >> 11;
 		}
 	}
 
diff -Nru a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c
--- a/drivers/scsi/inia100.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/inia100.c	Fri Oct 11 21:22:55 2002
@@ -664,12 +664,12 @@
 	if (pTcb->TCS_DrvHead) {
 		info_array[0] = pTcb->TCS_DrvHead;
 		info_array[1] = pTcb->TCS_DrvSector;
-		info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+		info_array[2] = (unsigned long)disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
 	} else {
 		if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
 			info_array[0] = 255;
 			info_array[1] = 63;
-			info_array[2] = disk->capacity / 255 / 63;
+			info_array[2] = (unsigned long)disk->capacity / 255 / 63;
 		} else {
 			info_array[0] = 64;
 			info_array[1] = 32;
diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/scsi/ips.c	Fri Oct 11 21:22:50 2002
@@ -1,11 +1,12 @@
 /*****************************************************************************/
-/* ips.c -- driver for the IBM ServeRAID controller                          */
+/* ips.c -- driver for the Adaptec / IBM ServeRAID controller                */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
 /*             Jack Hammer, Adaptec, Inc.                                    */
 /*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
-/* Copyright (C) 2000 IBM Corporation                                        */
+/* Copyright (C) 2000 IBM Corporation                                        */ 
+/* Copyright (C) 2002 Adaptec, Inc.                                          */ 
 /*                                                                           */
 /* 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      */
@@ -42,7 +43,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions about this driver should be mailed to:          */
-/*      ipslinux@us.ibm.com          	                                      */
+/*      ipslinux@adaptec.com        	                                     */
 /*                                                                           */
 /* For system support issues, contact your local IBM Customer support.       */
 /* Directions to find IBM Customer Support for each country can be found at: */
@@ -66,9 +67,8 @@
 /* 0.99.05  - Fix an oops when we get certain passthru commands              */
 /* 1.00.00  - Initial Public Release                                         */
 /*            Functionally equivalent to 0.99.05                             */
-/* 3.60.00  - Bump max commands to 128 for use with ServeRAID firmware 3.60  */
-/*          - Change version to 3.60 to coincide with ServeRAID release      */
-/*            numbering.                                                     */
+/* 3.60.00  - Bump max commands to 128 for use with firmware 3.60            */
+/*          - Change version to 3.60 to coincide with release numbering.     */
 /* 3.60.01  - Remove bogus error check in passthru routine                   */
 /* 3.60.02  - Make DCDB direction based on lookup table                      */
 /*          - Only allow one DCDB command to a SCSI ID at a time             */
@@ -76,7 +76,7 @@
 /* 4.00.01  - Add support for First Failure Data Capture                     */
 /* 4.00.02  - Fix problem with PT DCDB with no buffer                        */
 /* 4.00.03  - Add alternative passthru interface                             */
-/*          - Add ability to flash ServeRAID BIOS                            */
+/*          - Add ability to flash BIOS                                      */
 /* 4.00.04  - Rename structures/constants to be prefixed with IPS_           */
 /* 4.00.05  - Remove wish_block from init routine                            */
 /*          - Use linux/spinlock.h instead of asm/spinlock.h for kernels     */
@@ -158,13 +158,10 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/reboot.h>
-#include <linux/tqueue.h>
 #include <linux/interrupt.h>
 
 #include <linux/blk.h>
@@ -223,7 +220,7 @@
                                              dma_addr_t *dmahandle) {
        void * ptr = kmalloc(size, GFP_ATOMIC); 
        if(ptr){     
-          *dmahandle = VIRT_TO_BUS(ptr);
+          *dmahandle = (uint32_t)virt_to_bus(ptr);
        }
        return ptr;
     }
@@ -232,10 +229,10 @@
     
     #define pci_map_sg(a,b,n,z)       (n)
     #define pci_unmap_sg(a,b,c,d)     
-    #define pci_map_single(a,b,c,d)   (VIRT_TO_BUS(b))
+    #define pci_map_single(a,b,c,d)   ((uint32_t)virt_to_bus(b))
     #define pci_unmap_single(a,b,c,d) 
     #ifndef sg_dma_address
-      #define sg_dma_address(x)         (VIRT_TO_BUS((x)->address))
+      #define sg_dma_address(x)         ((uint32_t)virt_to_bus((x)->address))
       #define sg_dma_len(x)             ((x)->length)
     #endif
     #define pci_unregister_driver(x)
@@ -243,18 +240,16 @@
 
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,5,0)
     #define IPS_SG_ADDRESS(sg)       ((sg)->address)
-    #define IPS_LOCK_IRQ(lock)       spin_lock_irq(&io_request_lock)
-    #define IPS_UNLOCK_IRQ(lock)     spin_unlock_irq(&io_request_lock)
     #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
     #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
+    #ifndef __devexit_p
+        #define __devexit_p(x) x
+    #endif
 #else
     #define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
                                      page_address((sg)->page)+(sg)->offset : 0)
-    #define IPS_LOCK_IRQ(lock)       spin_lock_irq(lock)
-    #define IPS_UNLOCK_IRQ(lock)     spin_unlock_irq(lock)
-    #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(lock,flags)
-    #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(lock,flags)
-
+    #define IPS_LOCK_SAVE(lock,flags) spin_lock(lock)
+    #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock(lock)
 #endif
 
 #define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
@@ -438,6 +433,7 @@
 int ips_eh_reset(Scsi_Cmnd *);
 int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
 int ips_biosparam(Disk *, struct block_device *, int *);
+int ips_slave_attach(Scsi_Device *);
 const char * ips_info(struct Scsi_Host *);
 void do_ipsintr(int, void *, struct pt_regs *);
 static int ips_hainit(ips_ha_t *);
@@ -486,7 +482,7 @@
 static void ips_free_flash_copperhead(ips_ha_t *ha);
 static void ips_get_bios_version(ips_ha_t *, int);
 static void ips_identify_controller(ips_ha_t *);
-static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+//static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
 static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
 static void ips_enable_int_copperhead(ips_ha_t *);
 static void ips_enable_int_copperhead_memio(ips_ha_t *);
@@ -533,6 +529,7 @@
 static int copy_info(IPS_INFOSTR *, char *, ...);
 static int ips_get_version_info(ips_ha_t *ha, IPS_VERSION_DATA *Buffer, int intr );
 static void ips_version_check(ips_ha_t *ha, int intr);
+static int ips_abort_init(ips_ha_t *ha, struct Scsi_Host *sh, int index);
 static int ips_init_phase2( int index );
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
@@ -963,14 +960,6 @@
          ha = IPS_HA(sh);
          memset(ha, 0, sizeof(ips_ha_t));
 
-         /* Initialize spin lock */
-         spin_lock_init(&ha->scb_lock);
-         spin_lock_init(&ha->copp_lock);
-         spin_lock_init(&ha->ips_lock);
-         spin_lock_init(&ha->copp_waitlist.lock);
-         spin_lock_init(&ha->scb_waitlist.lock);
-         spin_lock_init(&ha->scb_activelist.lock);
-
          ips_sh[ips_next_controller] = sh;
          ips_ha[ips_next_controller] = ha;
          ips_num_controllers++;
@@ -1099,7 +1088,7 @@
          sh->n_io_port = io_addr ? 255 : 0;
          sh->unique_id = (io_addr) ? io_addr : mem_addr;
          sh->irq = irq;
-         sh->select_queue_depths = ips_select_queue_depth;
+         //sh->select_queue_depths = ips_select_queue_depth;
          sh->sg_tablesize = sh->hostt->sg_tablesize;
          sh->can_queue = sh->hostt->can_queue;
          sh->cmd_per_lun = sh->hostt->cmd_per_lun;
@@ -1417,12 +1406,13 @@
 /* Routine Description:                                                     */
 /*                                                                          */
 /*   Abort a command (using the new error code stuff)                       */
-/*                                                                          */
+/* Note: this routine is called under the io_request_lock                   */
 /****************************************************************************/
 int
 ips_eh_abort(Scsi_Cmnd *SC) {
    ips_ha_t         *ha;
    ips_copp_wait_item_t *item;
+   int ret;
 
    METHOD_TRACE("ips_eh_abort", 1);
 
@@ -1444,36 +1434,25 @@
       return (FAILED);
    }
 
-   if (test_and_set_bit(IPS_IN_ABORT, &ha->flags))
-      return (FAILED);
-
    /* See if the command is on the copp queue */
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
    item = ha->copp_waitlist.head;
    while ((item) && (item->scsi_cmd != SC))
       item = item->next;
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
 
    if (item) {
       /* Found it */
       ips_removeq_copp(&ha->copp_waitlist, item);
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (SUCCESS);
-   }
+      ret = (SUCCESS);
 
    /* See if the command is on the wait queue */
-   if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
+   } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
       /* command not sent yet */
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (SUCCESS);
+      ret = (SUCCESS);
    } else {
       /* command must have already been sent */
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (FAILED);
+      ret = (FAILED);
    }
+   return ret;
 }
 
 /****************************************************************************/
@@ -1494,7 +1473,6 @@
    ips_ha_t             *ha;
    ips_scb_t            *scb;
    ips_copp_wait_item_t *item;
-   unsigned long         cpu_flags;
 
    METHOD_TRACE("ips_eh_reset", 1);
 
@@ -1519,36 +1497,27 @@
    if (!ha->active)
       return (FAILED);
 
-   if (test_and_set_bit(IPS_IN_RESET, &ha->flags))
-      return (FAILED);
-
    /* See if the command is on the copp queue */
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
    item = ha->copp_waitlist.head;
    while ((item) && (item->scsi_cmd != SC))
       item = item->next;
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
 
    if (item) {
       /* Found it */
       ips_removeq_copp(&ha->copp_waitlist, item);
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (SUCCESS);
    }
 
    /* See if the command is on the wait queue */
    if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
       /* command not sent yet */
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (SUCCESS);
    }
 
    /* An explanation for the casual observer:                              */
    /* Part of the function of a RAID controller is automatic error         */
    /* detection and recovery.  As such, the only problem that physically   */
-   /* resetting a ServeRAID adapter will ever fix is when, for some reason,*/
+   /* resetting an adapter will ever fix is when, for some reason,         */
    /* the driver is not successfully communicating with the adapter.       */
    /* Therefore, we will attempt to flush this adapter.  If that succeeds, */
    /* then there's no real purpose in a physical reset. This will complete */
@@ -1575,13 +1544,12 @@
       ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
       if (ret == IPS_SUCCESS) {
          printk(KERN_NOTICE "(%s%d) Reset Request - Flushed Cache\n", ips_name, ha->host_num);
-         clear_bit(IPS_IN_RESET, &ha->flags);
          return (SUCCESS);
          }
    }
 
    /* Either we can't communicate with the adapter or it's an IOCTL request */
-   /* from a ServeRAID utility.  A physical reset is needed at this point.  */
+   /* from a utility.  A physical reset is needed at this point.            */
 
    ha->ioctl_reset = 0;             /* Reset the IOCTL Requested Reset Flag */
 
@@ -1620,8 +1588,6 @@
       }
 
       ha->active = FALSE;
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (FAILED);
    }
 
@@ -1652,8 +1618,6 @@
       }
 
       ha->active = FALSE;
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (FAILED);
    }
 
@@ -1662,10 +1626,8 @@
       struct timeval tv;
 
       do_gettimeofday(&tv);
-      IPS_HA_LOCK(cpu_flags);
       ha->last_ffdc = tv.tv_sec;
       ha->reset_count++;
-      IPS_HA_UNLOCK(cpu_flags);
       ips_ffdc_reset(ha, IPS_INTR_IORL);
    }
 
@@ -1684,25 +1646,11 @@
       ha->dcdb_active[i-1] = 0;
 
    /* Reset the number of active IOCTLs */
-   IPS_HA_LOCK(cpu_flags);
    ha->num_ioctl = 0;
-   IPS_HA_UNLOCK(cpu_flags);
-
-   clear_bit(IPS_IN_RESET, &ha->flags);
 
-   if (!test_bit(IPS_IN_INTR, &ha->flags)) {
-      /*
-       * Only execute the next command when
-       * we are not being called from the
-       * interrupt handler.  The interrupt
-       * handler wants to do this and since
-       * interrupts are turned off here....
-       */
-      ips_next(ha, IPS_INTR_IORL);
-   }
+   ips_next(ha, IPS_INTR_IORL);
 
    return (SUCCESS);
-
 #endif /* NO_IPS_RESET */
 
 }
@@ -1722,7 +1670,6 @@
 int
 ips_queue(Scsi_Cmnd *SC, void (*done) (Scsi_Cmnd *)) {
    ips_ha_t         *ha;
-   unsigned long     cpu_flags;
    ips_passthru_t   *pt;                                             
 
    METHOD_TRACE("ips_queue", 1);
@@ -1736,28 +1683,17 @@
       return (DID_ERROR);
 
    if (ips_is_passthru(SC)) {
-      IPS_QUEUE_LOCK(&ha->copp_waitlist);
       if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
-         IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-         SC->result = DID_BUS_BUSY << 16;
-         done(SC);
-
-         return (0);
-      } else {
-         IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-      }
-   } else {
-      IPS_QUEUE_LOCK(&ha->scb_waitlist);
-      if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
-         IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
          SC->result = DID_BUS_BUSY << 16;
          done(SC);
 
          return (0);
-      } else {
-         IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
       }
+   } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
+      SC->result = DID_BUS_BUSY << 16;
+      done(SC);
 
+      return (0);
    }
 
    SC->scsi_done = done;
@@ -1811,27 +1747,15 @@
       }
 
       scratch->scsi_cmd = SC;
-      sema_init(&ha->ioctl_sem, 0);
-      scratch->sem = &ha->ioctl_sem;
       scratch->next = NULL;
 
       ips_putq_copp_tail(&ha->copp_waitlist, scratch);
    }
-   else
+   else {
       ips_putq_wait_tail(&ha->scb_waitlist, SC);
-
-   if(ha->scb_waitlist.count + ha->scb_activelist.count > 32)
-         mod_timer(&SC->eh_timeout, jiffies + 120 * HZ);
-
-   IPS_HA_LOCK(cpu_flags);
-   if ((!test_bit(IPS_IN_INTR, &ha->flags)) &&
-       (!test_bit(IPS_IN_ABORT, &ha->flags)) &&
-       (!test_bit(IPS_IN_RESET, &ha->flags))) {
-      IPS_HA_UNLOCK(cpu_flags);
-      ips_next(ha, IPS_INTR_IORL);
-   } else {
-      IPS_HA_UNLOCK(cpu_flags);
    }
+
+   ips_next(ha, IPS_INTR_IORL);
    
    /* If We were using the CD Boot Flash Buffer, Restore the Old Values */
    if ( ips_FlashData == ha->ioctl_data ) {                               
@@ -1883,7 +1807,7 @@
       sectors = IPS_COMP_SECTORS;
    }
 
-   cylinders = disk->capacity / (heads * sectors);
+   cylinders = (unsigned long)disk->capacity / (heads * sectors);
 
    DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
              heads, sectors, cylinders);
@@ -1904,7 +1828,7 @@
 /*   Select queue depths for the devices on the contoller                   */
 /*                                                                          */
 /****************************************************************************/
-static void
+/*static void
 ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) {
    Scsi_Device *device;
    ips_ha_t    *ha;
@@ -1937,6 +1861,30 @@
       }
    }
 }
+*/
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_slave_attach                                           */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Set queue depths on devices once scan is complete                      */
+/*                                                                          */
+/****************************************************************************/
+int
+ips_slave_attach(Scsi_Device *SDptr)
+{
+   ips_ha_t    *ha;
+   int          min;
+
+   ha = IPS_HA(SDptr->host);
+   min = ha->max_cmds / 4;
+   if (min < 8)
+      min = ha->max_cmds - 1;
+   scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+   return 0;
+}
 
 /****************************************************************************/
 /*                                                                          */
@@ -1961,20 +1909,13 @@
    host = ips_sh[ha->host_num];
    IPS_LOCK_SAVE(host->host_lock, cpu_flags);
 
-   if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) {
-      IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
-      return ;
-   }
-
    if (!ha->active) {
-      clear_bit(IPS_IN_INTR, &ha->flags);
       IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
       return;
    }
 
    (*ha->func.intr)(ha);
 
-   clear_bit(IPS_IN_INTR, &ha->flags);
    IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 
    /* start the next command */
@@ -1998,7 +1939,6 @@
    ips_scb_t        *scb;
    IPS_STATUS        cstatus;
    int               intrstatus;
-   unsigned long     cpu_flags;
 
    METHOD_TRACE("ips_intr", 2);
 
@@ -2008,15 +1948,12 @@
    if (!ha->active)
       return;
 
-   IPS_HA_LOCK(cpu_flags);
-
    intrstatus = (*ha->func.isintr)(ha);
 
    if (!intrstatus) {
       /*
        * Unexpected/Shared interrupt
        */
-      IPS_HA_UNLOCK(cpu_flags);
 
       return;
    }
@@ -2043,12 +1980,8 @@
        * use the callback function to finish things up
        * NOTE: interrupts are OFF for this
        */
-      IPS_HA_UNLOCK(cpu_flags);
       (*scb->callback) (ha, scb);
-      IPS_HA_LOCK(cpu_flags);
    } /* end while */
-
-   IPS_HA_UNLOCK(cpu_flags);
 }
 
 /****************************************************************************/
@@ -2068,7 +2001,6 @@
    ips_scb_t        *scb;
    IPS_STATUS        cstatus;
    int               intrstatus;
-   unsigned long     cpu_flags;
 
    METHOD_TRACE("ips_intr_morpheus", 2);
 
@@ -2078,15 +2010,12 @@
    if (!ha->active)
       return;
 
-   IPS_HA_LOCK(cpu_flags);
-
    intrstatus = (*ha->func.isintr)(ha);
 
    if (!intrstatus) {
       /*
        * Unexpected/Shared interrupt
        */
-      IPS_HA_UNLOCK(cpu_flags);
 
       return;
    }
@@ -2119,12 +2048,8 @@
        * use the callback function to finish things up
        * NOTE: interrupts are OFF for this
        */
-      IPS_HA_UNLOCK(cpu_flags);
       (*scb->callback) (ha, scb);
-      IPS_HA_LOCK(cpu_flags);
    } /* end while */
-
-   IPS_HA_UNLOCK(cpu_flags);
 }
 
 /****************************************************************************/
@@ -3236,8 +3161,7 @@
    Scsi_Cmnd            *q;
    ips_copp_wait_item_t *item;
    int                   ret;
-   unsigned long         cpu_flags;
-   unsigned long         cpu_flags2 = 0;
+   unsigned long         cpu_flags = 0;
    struct Scsi_Host *host;
    METHOD_TRACE("ips_next", 1);
 
@@ -3248,27 +3172,20 @@
     * Block access to the queue function so
     * this command won't time out
     */
-   if (intr == IPS_INTR_ON) 
-       IPS_LOCK_SAVE(host->host_lock, cpu_flags2);
+   if(intr == IPS_INTR_ON)
+      IPS_LOCK_SAVE(host->host_lock, cpu_flags);
    
    if ((ha->subsys->param[3] & 0x300000)  && ( ha->scb_activelist.count == 0 )) {
       struct timeval tv;
 
       do_gettimeofday(&tv);
 
-      IPS_HA_LOCK(cpu_flags);
       if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
          ha->last_ffdc = tv.tv_sec;
-         IPS_HA_UNLOCK(cpu_flags);
          ips_ffdc_time(ha);
-      } else {
-         IPS_HA_UNLOCK(cpu_flags);
       }
    }
 
-   if (intr == IPS_INTR_ON)
-       IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags2);
-
    /*
     * Send passthru commands
     * These have priority over normal I/O
@@ -3276,22 +3193,21 @@
     * since we limit the number that can be active
     * on the card at any one time
     */
-   IPS_HA_LOCK(cpu_flags);
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
    while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
           (ha->copp_waitlist.head) &&
           (scb = ips_getscb(ha))) {
 
-      IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
       item = ips_removeq_copp_head(&ha->copp_waitlist);
       ha->num_ioctl++;
-      IPS_HA_UNLOCK(cpu_flags);
+      if(intr == IPS_INTR_ON)
+         IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
       scb->scsi_cmd = item->scsi_cmd;
-      scb->sem = item->sem;
       kfree(item);
 
       ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
 
+      if(intr == IPS_INTR_ON)
+         IPS_LOCK_SAVE(host->host_lock, cpu_flags);
       switch (ret) {
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
@@ -3314,8 +3230,6 @@
       } /* end case */
 
       if (ret != IPS_SUCCESS) {
-         IPS_HA_LOCK(cpu_flags);
-         IPS_QUEUE_LOCK(&ha->copp_waitlist);
          ha->num_ioctl--;
          continue;
      }
@@ -3342,20 +3256,14 @@
          break;
       } /* end case */
 
-      IPS_HA_LOCK(cpu_flags);
-      IPS_QUEUE_LOCK(&ha->copp_waitlist);
    }
 
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-   IPS_HA_UNLOCK(cpu_flags);
 
    /*
     * Send "Normal" I/O commands
     */
-   IPS_HA_LOCK(cpu_flags);
-   IPS_QUEUE_LOCK(&ha->scb_waitlist);
+    
    p = ha->scb_waitlist.head;
-   IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
    while ((p) && (scb = ips_getscb(ha))) {
       if ((p->channel > 0) && (ha->dcdb_active[p->channel-1] & (1 << p->target))) {
          ips_freescb(ha, scb);
@@ -3365,10 +3273,9 @@
 
       q = p;
       SC = ips_removeq_wait(&ha->scb_waitlist, q);
-      if (SC == NULL)                    /* Should never happen, but good to check anyway */
-         continue;
 
-      IPS_HA_UNLOCK(cpu_flags);          /* Unlock HA after command is taken off queue */
+      if(intr == IPS_INTR_ON)
+         IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); /* Unlock HA after command is taken off queue */
 
       SC->result = DID_OK;
       SC->host_scribble = NULL;
@@ -3476,13 +3383,15 @@
          scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
          scb->dcdb.transfer_length = 0;
       }
-
+      if(intr == IPS_INTR_ON)
+         IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+      
       ret = ips_send_cmd(ha, scb);
 
-      if (ret == IPS_SUCCESS)
-         ips_putq_scb_head(&ha->scb_activelist, scb);
-
       switch(ret) {
+      case IPS_SUCCESS:
+         ips_putq_scb_head(&ha->scb_activelist, scb);
+         break;
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
             scb->scsi_cmd->result = DID_ERROR << 16;
@@ -3509,10 +3418,10 @@
 
       p = (Scsi_Cmnd *) p->host_scribble;
 
-      IPS_HA_LOCK(cpu_flags);
    } /* end while */
 
-   IPS_HA_UNLOCK(cpu_flags);
+   if(intr == IPS_INTR_ON)
+      IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 }
 
 /****************************************************************************/
@@ -3523,7 +3432,7 @@
 /*                                                                          */
 /*   Add an item to the head of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3533,8 +3442,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->q_next = queue->head;
    queue->head = item;
 
@@ -3542,8 +3449,6 @@
       queue->tail = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3554,7 +3459,7 @@
 /*                                                                          */
 /*   Add an item to the tail of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3564,8 +3469,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->q_next = NULL;
 
    if (queue->tail)
@@ -3577,8 +3480,6 @@
       queue->head = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3589,7 +3490,7 @@
 /*                                                                          */
 /*   Remove the head of the queue                                           */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_scb_t *
@@ -3598,13 +3499,9 @@
 
    METHOD_TRACE("ips_removeq_scb_head", 1);
 
-   IPS_QUEUE_LOCK(queue);
-
    item = queue->head;
 
    if (!item) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (NULL);
    }
 
@@ -3616,8 +3513,6 @@
 
    queue->count--;
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (item);
 }
 
@@ -3629,7 +3524,7 @@
 /*                                                                          */
 /*   Remove an item from a queue                                            */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_scb_t *
@@ -3641,11 +3536,7 @@
    if (!item)
       return (NULL);
 
-   IPS_QUEUE_LOCK(queue);
-
    if (item == queue->head) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (ips_removeq_scb_head(queue));
    }
 
@@ -3664,13 +3555,9 @@
       item->q_next = NULL;
       queue->count--;
 
-      IPS_QUEUE_UNLOCK(queue);
-
       return (item);
    }
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (NULL);
 }
 
@@ -3682,7 +3569,7 @@
 /*                                                                          */
 /*   Add an item to the head of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3692,8 +3579,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->host_scribble = (char *) queue->head;
    queue->head = item;
 
@@ -3701,8 +3586,6 @@
       queue->tail = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3713,7 +3596,7 @@
 /*                                                                          */
 /*   Add an item to the tail of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3723,8 +3606,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->host_scribble = NULL;
 
    if (queue->tail)
@@ -3736,8 +3617,6 @@
       queue->head = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3748,7 +3627,7 @@
 /*                                                                          */
 /*   Remove the head of the queue                                           */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline Scsi_Cmnd *
@@ -3757,13 +3636,9 @@
 
    METHOD_TRACE("ips_removeq_wait_head", 1);
 
-   IPS_QUEUE_LOCK(queue);
-
    item = queue->head;
 
    if (!item) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (NULL);
    }
 
@@ -3775,8 +3650,6 @@
 
    queue->count--;
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (item);
 }
 
@@ -3788,7 +3661,7 @@
 /*                                                                          */
 /*   Remove an item from a queue                                            */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline Scsi_Cmnd *
@@ -3800,11 +3673,7 @@
    if (!item)
       return (NULL);
 
-   IPS_QUEUE_LOCK(queue);
-
    if (item == queue->head) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (ips_removeq_wait_head(queue));
    }
 
@@ -3823,13 +3692,9 @@
       item->host_scribble = NULL;
       queue->count--;
 
-      IPS_QUEUE_UNLOCK(queue);
-
       return (item);
    }
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (NULL);
 }
 
@@ -3841,7 +3706,7 @@
 /*                                                                          */
 /*   Add an item to the head of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3851,8 +3716,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->next = queue->head;
    queue->head = item;
 
@@ -3860,8 +3723,6 @@
       queue->tail = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3872,7 +3733,7 @@
 /*                                                                          */
 /*   Add an item to the tail of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3882,8 +3743,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->next = NULL;
 
    if (queue->tail)
@@ -3895,8 +3754,6 @@
       queue->head = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3907,7 +3764,7 @@
 /*                                                                          */
 /*   Remove the head of the queue                                           */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_copp_wait_item_t *
@@ -3916,13 +3773,9 @@
 
    METHOD_TRACE("ips_removeq_copp_head", 1);
 
-   IPS_QUEUE_LOCK(queue);
-
    item = queue->head;
 
    if (!item) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (NULL);
    }
 
@@ -3934,8 +3787,6 @@
 
    queue->count--;
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (item);
 }
 
@@ -3947,7 +3798,7 @@
 /*                                                                          */
 /*   Remove an item from a queue                                            */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_copp_wait_item_t *
@@ -3959,11 +3810,7 @@
    if (!item)
       return (NULL);
 
-   IPS_QUEUE_LOCK(queue);
-
    if (item == queue->head) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (ips_removeq_copp_head(queue));
    }
 
@@ -3982,13 +3829,9 @@
       item->next = NULL;
       queue->count--;
 
-      IPS_QUEUE_UNLOCK(queue);
-
       return (item);
    }
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (NULL);
 }
 
@@ -4052,12 +3895,11 @@
 /* Routine Description:                                                     */
 /*                                                                          */
 /*   Do housekeeping on completed commands                                  */
-/*                                                                          */
+/*  ASSUMED to be called form within the request lock                       */
 /****************************************************************************/
 static void
 ips_done(ips_ha_t *ha, ips_scb_t *scb) {
    int ret;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_done", 1);
 
@@ -4066,9 +3908,7 @@
 
    if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
       ips_cleanup_passthru(ha, scb);
-      IPS_HA_LOCK(cpu_flags);
       ha->num_ioctl--;
-      IPS_HA_UNLOCK(cpu_flags);
    } else {
       /*
        * Check to see if this command had too much
@@ -4227,9 +4067,7 @@
    } /* end if passthru */
 
    if (scb->bus) {
-      IPS_HA_LOCK(cpu_flags);
       ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
-      IPS_HA_UNLOCK(cpu_flags);
    }
 
    scb->scsi_cmd->scsi_done(scb->scsi_cmd);
@@ -4337,7 +4175,7 @@
                 (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)) {
                tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb;
                memcpy(scb->scsi_cmd->sense_buffer, tapeDCDB->sense_info,
-                      sizeof(tapeDCDB->sense_info));
+                      sizeof(scb->scsi_cmd->sense_buffer));
             } else {
                memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
                       sizeof(scb->scsi_cmd->sense_buffer));
@@ -4409,6 +4247,7 @@
    char     *sp;
    int       device_error;
    IPS_DCDB_TABLE_TAPE *tapeDCDB;
+   int       TimeOut;
 
    METHOD_TRACE("ips_send_cmd", 1);
 
@@ -4479,8 +4318,10 @@
             scb->cmd.logical_info.reserved = 0;
             scb->cmd.logical_info.reserved2 = 0;
             scb->data_len = sizeof(ha->adapt->logical_drive_info);
-            scb->data_busaddr = ha->adapt->hw_status_start + sizeof(IPS_ADAPTER)
-                                - sizeof(IPS_LD_INFO);
+            scb->data_busaddr = pci_map_single(ha->pcidev,
+                                               &ha->adapt->logical_drive_info,
+                                               scb->data_len, IPS_DMA_DIR(scb));
+            scb->flags |= IPS_SCB_MAP_SINGLE;
             scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
             ret = IPS_SUCCESS;
          }
@@ -4587,8 +4428,10 @@
          scb->cmd.logical_info.reserved2 = 0;
          scb->cmd.logical_info.reserved3 = 0;
          scb->data_len = sizeof(ha->adapt->logical_drive_info);
-         scb->data_busaddr = ha->adapt->hw_status_start + sizeof(IPS_ADAPTER)
-                             - sizeof(IPS_LD_INFO);
+         scb->data_busaddr = pci_map_single(ha->pcidev,
+                                            &ha->adapt->logical_drive_info,
+                                            scb->data_len, IPS_DMA_DIR(scb));
+         scb->flags |= IPS_SCB_MAP_SINGLE;
          scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
          ret = IPS_SUCCESS;
          break;
@@ -4643,11 +4486,13 @@
       ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id);
       scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
       scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
-                                          (unsigned long)&scb->dcdb -
-                                          (unsigned long)scb);
+                                               (unsigned long)&scb->dcdb -
+                                               (unsigned long)scb);
       scb->cmd.dcdb.reserved = 0;
       scb->cmd.dcdb.reserved2 = 0;
-      scb->cmd.dcdb.reserved3 = 0;
+      scb->cmd.dcdb.reserved3 = 0;   
+
+      TimeOut = scb->scsi_cmd->timeout_per_command;
 
       if (ha->subsys->param[4] & 0x00100000) {          /* If NEW Tape DCDB is Supported */
          if (!scb->sg_len)
@@ -4658,47 +4503,52 @@
          tapeDCDB = (IPS_DCDB_TABLE_TAPE *) &scb->dcdb; /* Use Same Data Area as Old DCDB Struct */
          tapeDCDB->device_address = ((scb->bus - 1) << 4) | scb->target_id;
          tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+         tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;   /* Always Turn OFF 64K Size Flag */
 
-         if (scb->timeout) {
-           if (scb->timeout <= 10)
-               tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;
-            else if (scb->timeout <= 60)
-               tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;
-            else
-               tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
+         if (TimeOut) {
+            if (TimeOut < ( 10 * HZ ))                  
+                tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;     /* TimeOut is 10 Seconds */
+            else if (TimeOut < (60 * HZ)) 
+                tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;     /* TimeOut is 60 Seconds */
+            else if (TimeOut < (1200 * HZ)) 
+                tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;    /* TimeOut is 20 Minutes */
          }
 
-         if (!(tapeDCDB->cmd_attribute & IPS_TIMEOUT20M))
-            tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
-
-         tapeDCDB->sense_length = sizeof(tapeDCDB->sense_info);
+         tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
+         tapeDCDB->reserved_for_LUN = 0;
          tapeDCDB->transfer_length = scb->data_len;
          tapeDCDB->buffer_pointer = cpu_to_le32(scb->data_busaddr);
          tapeDCDB->sg_count = scb->sg_len;
-         tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
+         tapeDCDB->sense_length = sizeof(tapeDCDB->sense_info);
+         tapeDCDB->scsi_status = 0;
+         tapeDCDB->reserved = 0;
          memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
       } else {
          scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
          scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
 
-         if (scb->timeout) {
-           if (scb->timeout <= 10)
-               scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
-            else if (scb->timeout <= 60)
-               scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
-            else
-               scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+         if (TimeOut) {
+            if (TimeOut < (10 * HZ))                  
+                scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;     /* TimeOut is 10 Seconds */
+            else if (TimeOut < (60 * HZ)) 
+                scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;     /* TimeOut is 60 Seconds */
+            else if (TimeOut < (1200 * HZ)) 
+                scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;    /* TimeOut is 20 Minutes */
          }
-
-         if (!(scb->dcdb.cmd_attribute & IPS_TIMEOUT20M))
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
-
-         scb->dcdb.sense_length = sizeof(scb->dcdb.sense_info);
+         
          scb->dcdb.transfer_length = scb->data_len;
+         if ( scb->dcdb.cmd_attribute & IPS_TRANSFER64K ) 
+             scb->dcdb.transfer_length = 0;
          scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-         scb->dcdb.sg_count = scb->sg_len;
          scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
+         scb->dcdb.sense_length = sizeof(scb->dcdb.sense_info);
+         scb->dcdb.sg_count = scb->sg_len;
+         scb->dcdb.reserved = 0;
          memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+         scb->dcdb.scsi_status = 0;
+         scb->dcdb.reserved2[0] = 0;
+         scb->dcdb.reserved2[1] = 0;
+         scb->dcdb.reserved2[2] = 0;
       }
    }
 
@@ -4712,7 +4562,7 @@
 /* Routine Description:                                                     */
 /*                                                                          */
 /*   Check the status of commands to logical drives                         */
-/*                                                                          */
+/*   Assumed to be called with the HA lock                                  */
 /****************************************************************************/
 static void
 ips_chkstatus(ips_ha_t *ha, IPS_STATUS *pstatus) {
@@ -5241,13 +5091,10 @@
 static ips_scb_t *
 ips_getscb(ips_ha_t *ha) {
    ips_scb_t     *scb;
-   unsigned long  cpu_flags;
 
    METHOD_TRACE("ips_getscb", 1);
 
-   IPS_SCB_LOCK(cpu_flags);
    if ((scb = ha->scb_freelist) == NULL) {
-      IPS_SCB_UNLOCK(cpu_flags);
 
       return (NULL);
    }
@@ -5255,8 +5102,6 @@
    ha->scb_freelist = scb->q_next;
    scb->q_next = NULL;
 
-   IPS_SCB_UNLOCK(cpu_flags);
-
    ips_init_scb(ha, scb);
 
    return (scb);
@@ -5275,7 +5120,6 @@
 /****************************************************************************/
 static void
 ips_freescb(ips_ha_t *ha, ips_scb_t *scb) {
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_freescb", 1);
    if(scb->flags & IPS_SCB_MAP_SG)
@@ -5288,10 +5132,8 @@
 
    /* check to make sure this is not our "special" scb */
    if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
-      IPS_SCB_LOCK(cpu_flags);
       scb->q_next = ha->scb_freelist;
       ha->scb_freelist = scb;
-      IPS_SCB_UNLOCK(cpu_flags);
    }
 }
 
@@ -5703,15 +5545,12 @@
 static int
 ips_reset_copperhead(ips_ha_t *ha) {
    int reset_counter;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_reset_copperhead", 1);
 
    DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
              ips_name, ha->host_num, ha->io_addr, ha->irq);
 
-   IPS_HA_LOCK(cpu_flags);
-
    reset_counter = 0;
 
    while (reset_counter < 2) {
@@ -5730,14 +5569,11 @@
       if ((*ha->func.init)(ha))
          break;
       else if (reset_counter >= 2) {
-         IPS_HA_UNLOCK(cpu_flags);
 
          return (0);
       }
    }
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (1);
 }
 
@@ -5753,15 +5589,12 @@
 static int
 ips_reset_copperhead_memio(ips_ha_t *ha) {
    int reset_counter;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_reset_copperhead_memio", 1);
 
    DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
              ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-   IPS_HA_LOCK(cpu_flags);
-
    reset_counter = 0;
 
    while (reset_counter < 2) {
@@ -5780,14 +5613,11 @@
       if ((*ha->func.init)(ha))
          break;
       else if (reset_counter >= 2) {
-         IPS_HA_UNLOCK(cpu_flags);
 
          return (0);
       }
    }
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (1);
 }
 
@@ -5804,15 +5634,12 @@
 ips_reset_morpheus(ips_ha_t *ha) {
    int           reset_counter;
    uint8_t       junk;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_reset_morpheus", 1);
 
    DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
              ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-   IPS_HA_LOCK(cpu_flags);
-
    reset_counter = 0;
 
    while (reset_counter < 2) {
@@ -5829,14 +5656,11 @@
       if ((*ha->func.init)(ha))
          break;
       else if (reset_counter >= 2) {
-         IPS_HA_UNLOCK(cpu_flags);
 
          return (0);
       }
    }
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (1);
 }
 
@@ -5981,7 +5805,6 @@
 ips_issue_copperhead(ips_ha_t *ha, ips_scb_t *scb) {
    uint32_t TimeOut;
    uint32_t val;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_copperhead", 1);
 
@@ -6001,8 +5824,6 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    TimeOut = 0;
 
    while ((val = le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
@@ -6017,8 +5838,6 @@
          printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
                 ips_name, ha->host_num);
 
-         IPS_HA_UNLOCK(cpu_flags);
-
          return (IPS_FAILURE);
       } /* end if */
    } /* end while */
@@ -6026,8 +5845,6 @@
    outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);
    outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -6044,7 +5861,6 @@
 ips_issue_copperhead_memio(ips_ha_t *ha, ips_scb_t *scb) {
    uint32_t      TimeOut;
    uint32_t      val;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_copperhead_memio", 1);
 
@@ -6064,8 +5880,6 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    TimeOut = 0;
 
    while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
@@ -6080,8 +5894,6 @@
          printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
                 ips_name, ha->host_num);
 
-         IPS_HA_UNLOCK(cpu_flags);
-
          return (IPS_FAILURE);
       } /* end if */
    } /* end while */
@@ -6089,8 +5901,6 @@
    writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
    writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -6105,7 +5915,6 @@
 /****************************************************************************/
 static int
 ips_issue_i2o(ips_ha_t *ha, ips_scb_t *scb) {
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_i2o", 1);
 
@@ -6125,12 +5934,8 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -6145,7 +5950,6 @@
 /****************************************************************************/
 static int
 ips_issue_i2o_memio(ips_ha_t *ha, ips_scb_t *scb) {
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_i2o_memio", 1);
 
@@ -6165,12 +5969,8 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -6307,12 +6107,7 @@
           * until after we finish.
           */
 
-         while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
-            udelay(1000);
-
          (*ha->func.intr)(ha);
-
-         clear_bit(IPS_IN_INTR, &ha->flags);
       } 
 
       /* This looks like a very evil loop, but it only does this during start-up */
@@ -7395,6 +7190,14 @@
 #include "scsi_module.c"
 #endif
 
+static int ips_abort_init(ips_ha_t *ha, struct Scsi_Host *sh, int index){
+   ha->active = 0;
+   ips_free(ha);
+   scsi_unregister(sh);
+   ips_ha[index] = 0;
+   ips_sh[index] = 0;
+   return -1;
+}
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 
@@ -7569,14 +7372,6 @@
     ha = IPS_HA(sh);
     memset(ha, 0, sizeof(ips_ha_t));
     
-    /* Initialize spin lock */
-    spin_lock_init(&ha->scb_lock);
-    spin_lock_init(&ha->copp_lock);
-    spin_lock_init(&ha->ips_lock);
-    spin_lock_init(&ha->copp_waitlist.lock);
-    spin_lock_init(&ha->scb_waitlist.lock);
-    spin_lock_init(&ha->scb_activelist.lock);
-
     ips_sh[index] = sh;
     ips_ha[index] = ha;
     ha->active = 1;
@@ -7585,24 +7380,14 @@
 
     if (!ha->enq) {
        printk(KERN_WARNING "Unable to allocate host inquiry structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     ha->adapt = pci_alloc_consistent(ha->pcidev, sizeof(IPS_ADAPTER) +
                                      sizeof(IPS_IO_CMD), &dma_address);
     if (!ha->adapt) {
        printk(KERN_WARNING "Unable to allocate host adapt & dummy structures\n");
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
     ha->adapt->hw_status_start = dma_address;
     ha->dummy = (void *)(ha->adapt + 1);
@@ -7611,36 +7396,21 @@
 
     if (!ha->conf) {
        printk(KERN_WARNING "Unable to allocate host conf structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL);
 
     if (!ha->nvram) {
        printk(KERN_WARNING "Unable to allocate host NVRAM structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL);
 
     if (!ha->subsys) {
        printk(KERN_WARNING "Unable to allocate host subsystem structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     for (count = PAGE_SIZE, ha->ioctl_order = 0;
@@ -7662,7 +7432,7 @@
     sh->n_io_port = io_addr ? 255 : 0;
     sh->unique_id = (io_addr) ? io_addr : mem_addr;
     sh->irq = irq;
-    sh->select_queue_depths = ips_select_queue_depth;
+    //sh->select_queue_depths = ips_select_queue_depth;
     sh->sg_tablesize = sh->hostt->sg_tablesize;
     sh->can_queue = sh->hostt->can_queue;
     sh->cmd_per_lun = sh->hostt->cmd_per_lun;
@@ -7749,24 +7519,14 @@
            * Initialization failed
            */
           printk(KERN_WARNING "Unable to initialize controller\n" );
-          ha->active = 0;
-          ips_free(ha);
-          scsi_unregister(sh);
-          ips_ha[index] = 0;
-          ips_sh[index] = 0;
-          return -1;
+          return ips_abort_init(ha, sh, index);
        }
     }
 
     /* Install the interrupt handler */
      if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
        printk(KERN_WARNING "Unable to install interrupt handler\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     /*
@@ -7775,13 +7535,8 @@
     ha->max_cmds = 1;
     if (!ips_allocatescbs(ha)) {
        printk(KERN_WARNING "Unable to allocate a CCB\n" );
-       ha->active = 0;
        free_irq(ha->irq, ha);
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     *indexPtr = index;
@@ -7817,13 +7572,8 @@
 
     if (!ips_hainit(ha)) {
        printk(KERN_WARNING "Unable to initialize controller\n" );
-       ha->active = 0;
-       ips_free(ha);
        free_irq(ha->irq, ha);
-       scsi_unregister(sh);
-       ips_ha[index] = NULL;
-       ips_sh[index] = NULL;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
     /* Free the temporary SCB */
     ips_deallocatescbs(ha, 1);
@@ -7831,13 +7581,8 @@
     /* allocate CCBs */
     if (!ips_allocatescbs(ha)) {
        printk(KERN_WARNING "Unable to allocate CCBs\n" );
-       ha->active = 0;
-       ips_free(ha);
        free_irq(ha->irq, ha);
-       scsi_unregister(sh);
-       ips_ha[index] = NULL;
-       ips_sh[index] = NULL;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     /* finish setting values */
diff -Nru a/drivers/scsi/ips.h b/drivers/scsi/ips.h
--- a/drivers/scsi/ips.h	Fri Oct 11 21:22:54 2002
+++ b/drivers/scsi/ips.h	Fri Oct 11 21:22:54 2002
@@ -1,9 +1,12 @@
 /*****************************************************************************/
-/* ips.h -- driver for the IBM ServeRAID controller                          */
+/* ips.h -- driver for the Adaptec / IBM ServeRAID controller                */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
+/*             Jack Hammer, Adaptec, Inc.                                    */
+/*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
 /* Copyright (C) 1999 IBM Corporation                                        */
+/* Copyright (C) 2003 Adaptec, Inc.                                          */ 
 /*                                                                           */
 /* 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      */
@@ -40,7 +43,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions should be mailed to:                            */
-/*      ipslinux@us.ibm.com                                                  */
+/*      ipslinux@adaptec.com                                                 */
 /*                                                                           */
 /*****************************************************************************/
 
@@ -57,6 +60,7 @@
    extern int ips_eh_reset(Scsi_Cmnd *);
    extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
    extern int ips_biosparam(Disk *, struct block_device *, int *);
+   extern int ips_slave_attach(Scsi_Device *);
    extern const char * ips_info(struct Scsi_Host *);
    extern void do_ips(int, void *, struct pt_regs *);
 
@@ -84,33 +88,11 @@
                                          ((IPS_IS_TROMBONE(ha) || IPS_IS_CLARINET(ha)) && \
                                           (ips_force_memio))) ? 1 : 0)
 
-   #ifndef VIRT_TO_BUS
-      #define VIRT_TO_BUS(x)           (uint32_t) virt_to_bus((void *) x)
-   #endif
-
    #ifndef MDELAY
       #define MDELAY mdelay
    #endif
-
-   #ifndef verify_area_20
-      #define verify_area_20(t,a,sz)   (0) /* success */
-   #endif
-
-   #ifndef DECLARE_MUTEX_LOCKED
-      #define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED;
-   #endif
    
    /*
-    * Lock macros
-    */
-   #define IPS_SCB_LOCK(cpu_flags)      spin_lock_irqsave(&ha->scb_lock, cpu_flags)
-   #define IPS_SCB_UNLOCK(cpu_flags)    spin_unlock_irqrestore(&ha->scb_lock, cpu_flags)
-   #define IPS_QUEUE_LOCK(queue)        spin_lock_irqsave(&(queue)->lock, (queue)->cpu_flags)
-   #define IPS_QUEUE_UNLOCK(queue)      spin_unlock_irqrestore(&(queue)->lock, (queue)->cpu_flags)
-   #define IPS_HA_LOCK(cpu_flags)       spin_lock_irqsave(&ha->ips_lock, cpu_flags)
-   #define IPS_HA_UNLOCK(cpu_flags)     spin_unlock_irqrestore(&ha->ips_lock, cpu_flags)
-
-   /*
     * Adapter address map equates
     */
    #define IPS_REG_HISR                 0x08    /* Host Interrupt Status Reg   */
@@ -500,7 +482,8 @@
     eh_host_reset_handler : ips_eh_reset, \
     abort : NULL,                         \
     reset : NULL,                         \
-    slave_attach : NULL,                  \
+    slave_attach : ips_slave_attach,      \
+    slave_detach : NULL,                  \
     bios_param : ips_biosparam,           \
     can_queue : 0,                        \
     this_id: -1,                          \
@@ -1063,8 +1046,6 @@
    struct ips_scb *head;
    struct ips_scb *tail;
    int             count;
-   unsigned long   cpu_flags;
-   spinlock_t      lock;
 } ips_scb_queue_t;
 
 /*
@@ -1074,13 +1055,10 @@
    Scsi_Cmnd      *head;
    Scsi_Cmnd      *tail;
    int             count;
-   unsigned long   cpu_flags;
-   spinlock_t      lock;
 } ips_wait_queue_t;
 
 typedef struct ips_copp_wait_item {
    Scsi_Cmnd                 *scsi_cmd;
-   struct semaphore          *sem;
    struct ips_copp_wait_item *next;
 } ips_copp_wait_item_t;
 
@@ -1088,8 +1066,6 @@
    struct ips_copp_wait_item *head;
    struct ips_copp_wait_item *tail;
    int                        count;
-   unsigned long              cpu_flags;
-   spinlock_t                 lock;
 } ips_copp_queue_t;
 
 /* forward decl for host structure */
@@ -1138,7 +1114,6 @@
    char              *ioctl_data;         /* IOCTL data area            */
    uint32_t           ioctl_datasize;     /* IOCTL data size            */
    uint32_t           cmd_in_progress;    /* Current command in progress*/
-   unsigned long      flags;              /* HA flags                   */
    uint8_t            waitflag;           /* are we waiting for cmd     */
    uint8_t            active;
    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
@@ -1158,11 +1133,6 @@
    char              *ioremap_ptr;        /* ioremapped memory pointer  */
    ips_hw_func_t      func;               /* hw function pointers       */
    struct pci_dev    *pcidev;             /* PCI device handle          */
-   spinlock_t         scb_lock;
-   spinlock_t         copp_lock;
-   spinlock_t         ips_lock;
-   struct semaphore   ioctl_sem;          /* Semaphore for new IOCTL's  */
-   struct semaphore   flash_ioctl_sem;    /* Semaphore for Flashing     */
    char              *flash_data;         /* Save Area for flash data   */
    u8                 flash_order;        /* Save Area for flash size order  */
    u32                flash_datasize;   /* Save Area for flash data size */
@@ -1195,7 +1165,6 @@
    Scsi_Cmnd        *scsi_cmd;
    struct ips_scb   *q_next;
    ips_scb_callback  callback;
-   struct semaphore *sem;
    uint32_t          sg_busaddr;
    int               sg_count;
 } ips_scb_t;
diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
--- a/drivers/scsi/megaraid.c	Fri Oct 11 21:22:50 2002
+++ b/drivers/scsi/megaraid.c	Fri Oct 11 21:22:50 2002
@@ -4236,13 +4236,13 @@
 			/* Default heads (64) & sectors (32) */
 			heads = 64;
 			sectors = 32;
-			cylinders = disk->capacity / (heads * sectors);
+			cylinders = (unsigned long)disk->capacity / (heads * sectors);
 
 			/* Handle extended translation size for logical drives > 1Gb */
 			if (disk->capacity >= 0x200000) {
 				heads = 255;
 				sectors = 63;
-				cylinders = disk->capacity / (heads * sectors);
+				cylinders = (unsigned long)disk->capacity / (heads * sectors);
 			}
 
 			/* return result */
@@ -4260,13 +4260,13 @@
 		/* Default heads (64) & sectors (32) */
 		heads = 64;
 		sectors = 32;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = disk->capacity >> 11;
 
 		/* Handle extended translation size for logical drives > 1Gb */
 		if (disk->capacity >= 0x200000) {
 			heads = 255;
 			sectors = 63;
-			cylinders = disk->capacity / (heads * sectors);
+			cylinders = (unsigned long)disk->capacity / (heads * sectors);
 		}
 
 		/* return result */
diff -Nru a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
--- a/drivers/scsi/pas16.h	Fri Oct 11 21:23:02 2002
+++ b/drivers/scsi/pas16.h	Fri Oct 11 21:23:02 2002
@@ -118,7 +118,9 @@
 int pas16_biosparam(Disk *, struct block_device *, int*);
 int pas16_detect(Scsi_Host_Template *);
 int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int pas16_reset(Scsi_Cmnd *, unsigned int);
+int pas16_bus_reset(Scsi_Cmnd *);
+int pas16_host_reset(Scsi_Cmnd *);
+int pas16_device_reset(Scsi_Cmnd *);
 int pas16_proc_info (char *buffer ,char **start, off_t offset,
 		     int length, int hostno, int inout);
 
@@ -144,8 +146,10 @@
 	name:           "Pro Audio Spectrum-16 SCSI", 	\
 	detect:         pas16_detect, 			\
 	queuecommand:   pas16_queue_command,		\
-	abort:          pas16_abort,			\
-	reset:          pas16_reset,			\
+	eh_abort_handler: pas16_abort,			\
+	eh_bus_reset_handler: pas16_bus_reset,		\
+	eh_device_reset_handler: pas16_device_reset,	\
+	eh_host_reset_handler: pas16_host_reset,	\
 	bios_param:     pas16_biosparam, 		\
 	can_queue:      CAN_QUEUE,			\
 	this_id:        7,				\
@@ -186,7 +190,9 @@
 #define do_NCR5380_intr do_pas16_intr
 #define NCR5380_queue_command pas16_queue_command
 #define NCR5380_abort pas16_abort
-#define NCR5380_reset pas16_reset
+#define NCR5380_device_reset pas16_device_reset
+#define NCR5380_bus_reset pas16_bus_reset
+#define NCR5380_host_reset pas16_host_reset
 #define NCR5380_proc_info pas16_proc_info
 
 /* 15 14 12 10 7 5 3 
diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
--- a/drivers/scsi/ppa.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/scsi/ppa.c	Fri Oct 11 21:22:51 2002
@@ -18,6 +18,7 @@
 #include <linux/blk.h>
 #include <asm/io.h>
 #include <linux/parport.h>
+#include <linux/workqueue.h>
 #include "sd.h"
 #include "hosts.h"
 int ppa_release(struct Scsi_Host *);
@@ -42,7 +43,7 @@
 	mode:		PPA_AUTODETECT,	\
 	host:		-1,		\
 	cur_cmd:	NULL,		\
-	ppa_tq:		{ routine: ppa_interrupt },	\
+	ppa_tq:		{ func: ppa_interrupt },	\
 	jstart:		0,		\
 	recon_tmo:      PPA_RECON_TMO,	\
 	failed:		0,		\
@@ -800,7 +801,6 @@
     }
     if (ppa_engine(tmp, cmd)) {
 	tmp->ppa_tq.data = (void *) tmp;
-	tmp->ppa_tq.sync = 0;
 	schedule_delayed_work(&tmp->ppa_tq, 1);
 	return;
     }
@@ -985,7 +985,6 @@
     ppa_pb_claim(host_no);
 
     ppa_hosts[host_no].ppa_tq.data = ppa_hosts + host_no;
-    ppa_hosts[host_no].ppa_tq.sync = 0;
     schedule_work(&ppa_hosts[host_no].ppa_tq);
 
     return 0;
@@ -1001,11 +1000,11 @@
 {
     ip[0] = 0x40;
     ip[1] = 0x20;
-    ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+    ip[2] = ((unsigned long)disk->capacity + 1) / (ip[0] * ip[1]);
     if (ip[2] > 1024) {
 	ip[0] = 0xff;
 	ip[1] = 0x3f;
-	ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+	ip[2] = ((unsigned long)disk->capacity + 1) / (ip[0] * ip[1]);
 	if (ip[2] > 1023)
 	    ip[2] = 1023;
     }
diff -Nru a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
--- a/drivers/scsi/ppa.h	Fri Oct 11 21:23:03 2002
+++ b/drivers/scsi/ppa.h	Fri Oct 11 21:23:03 2002
@@ -78,7 +78,6 @@
 #include  <linux/stddef.h>
 #include  <linux/module.h>
 #include  <linux/kernel.h>
-#include  <linux/tqueue.h>
 #include  <linux/ioport.h>
 #include  <linux/delay.h>
 #include  <linux/proc_fs.h>
diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/scsi/qla1280.c	Fri Oct 11 21:23:05 2002
@@ -671,7 +671,7 @@
 			free_page((unsigned long)qla1280_buffer);
 			qla1280_buffer_size = 0;
 		}
-		qla1280_buffer = (char *)get_free_page(GFP_KERNEL);
+		qla1280_buffer = (char *)get_zeroed_page(GFP_KERNEL);
 	}
 	if (qla1280_buffer == NULL) {
 		size = sprintf(buffer, "qla1280 - kmalloc error at line %d\n",
@@ -1705,11 +1705,11 @@
 
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (unsigned long)disk->capacity / (heads * sectors);
 	if (cylinders > 1024) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (unsigned long)disk->capacity / (heads * sectors);
 		/* if (cylinders > 1023)
 		   cylinders = 1023; */
 	}
diff -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
--- a/drivers/scsi/qlogicfas.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/scsi/qlogicfas.c	Fri Oct 11 21:23:05 2002
@@ -656,11 +656,11 @@
 /* This should mimic the DOS Qlogic driver's behavior exactly */
 	ip[0] = 0x40;
 	ip[1] = 0x20;
-	ip[2] = disk->capacity / (ip[0] * ip[1]);
+	ip[2] = (unsigned long)disk->capacity / (ip[0] * ip[1]);
 	if (ip[2] > 1024) {
 		ip[0] = 0xff;
 		ip[1] = 0x3f;
-		ip[2] = disk->capacity / (ip[0] * ip[1]);
+		ip[2] = (unsigned long)disk->capacity / (ip[0] * ip[1]);
 #if 0
 		if (ip[2] > 1023)
 			ip[2] = 1023;
diff -Nru a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
--- a/drivers/scsi/qlogicpti.h	Fri Oct 11 21:22:54 2002
+++ b/drivers/scsi/qlogicpti.h	Fri Oct 11 21:22:54 2002
@@ -6,6 +6,8 @@
 #ifndef _QLOGICPTI_H
 #define _QLOGICPTI_H
 
+#include <linux/config.h>
+
 /* Qlogic/SBUS controller registers. */
 #define SBUS_CFG1	0x006UL
 #define SBUS_CTRL	0x008UL
@@ -512,6 +514,7 @@
 #define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
 #define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
 
+#ifdef CONFIG_SPARC64
 #define QLOGICPTI {						   \
 	detect:		qlogicpti_detect,			   \
 	release:	qlogicpti_release,			   \
@@ -526,6 +529,22 @@
 	use_clustering:	ENABLE_CLUSTERING,			   \
 	highmem_io:	1,			   		   \
 }
+#else
+/* Sparc32's iommu code cannot handle highmem pages yet. */
+#define QLOGICPTI {						   \
+	detect:		qlogicpti_detect,			   \
+	release:	qlogicpti_release,			   \
+	info:		qlogicpti_info,				   \
+	queuecommand:	qlogicpti_queuecommand_slow,		   \
+	abort:		qlogicpti_abort,			   \
+	reset:		qlogicpti_reset,			   \
+	can_queue:	QLOGICPTI_REQ_QUEUE_LEN,		   \
+	this_id:	7,					   \
+	sg_tablesize:	QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN), \
+	cmd_per_lun:	1,					   \
+	use_clustering:	ENABLE_CLUSTERING,			   \
+}
+#endif
 
 /* For our interrupt engine. */
 #define for_each_qlogicpti(qp) \
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/scsi/scsi.c	Fri Oct 11 21:22:58 2002
@@ -551,6 +551,7 @@
 {
 	unsigned long flags;
         Scsi_Device * SDpnt;
+	int alloc_cmd = 0;
 
 	spin_lock_irqsave(&device_request_lock, flags);
 
@@ -567,6 +568,25 @@
 				   atomic_read(&SCpnt->host->host_active),
 				   SCpnt->host->host_failed));
 
+	if(SDpnt->queue_depth > SDpnt->new_queue_depth) {
+		Scsi_Cmnd *prev, *next;
+		/*
+		 * Release the command block and decrement the queue
+		 * depth.
+		 */
+		for(prev = NULL, next = SDpnt->device_queue;
+				next != SCpnt;
+				prev = next, next = next->next) ;
+		if(prev == NULL)
+			SDpnt->device_queue = next->next;
+		else
+			prev->next = next->next;
+		kfree((char *)SCpnt);
+		SDpnt->queue_depth--;
+	} else if(SDpnt->queue_depth < SDpnt->new_queue_depth) {
+		alloc_cmd = 1;
+		SDpnt->queue_depth++;
+	}
 	spin_unlock_irqrestore(&device_request_lock, flags);
 
         /*
@@ -575,6 +595,48 @@
          * they wake up.  
          */
 	wake_up(&SDpnt->scpnt_wait);
+
+	/*
+	 * We are happy to release command blocks in the scope of the
+	 * device_request_lock since that's nice and quick, but allocation
+	 * can take more time so do it outside that scope instead.
+	 */
+	if(alloc_cmd) {
+		Scsi_Cmnd *newSCpnt;
+
+		newSCpnt = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC |
+				(SDpnt->host->unchecked_isa_dma ?
+				 GFP_DMA : 0));
+		if(newSCpnt) {
+			memset(newSCpnt, 0, sizeof(Scsi_Cmnd));
+			newSCpnt->host = SDpnt->host;
+			newSCpnt->device = SDpnt;
+			newSCpnt->target = SDpnt->id;
+			newSCpnt->lun = SDpnt->lun;
+			newSCpnt->channel = SDpnt->channel;
+			newSCpnt->request = NULL;
+			newSCpnt->use_sg = 0;
+			newSCpnt->old_use_sg = 0;
+			newSCpnt->old_cmd_len = 0;
+			newSCpnt->underflow = 0;
+			newSCpnt->old_underflow = 0;
+			newSCpnt->transfersize = 0;
+			newSCpnt->resid = 0;
+			newSCpnt->serial_number = 0;
+			newSCpnt->serial_number_at_timeout = 0;
+			newSCpnt->host_scribble = NULL;
+			newSCpnt->state = SCSI_STATE_UNUSED;
+			newSCpnt->owner = SCSI_OWNER_NOBODY;
+			spin_lock_irqsave(&device_request_lock, flags);
+			newSCpnt->next = SDpnt->device_queue;
+			SDpnt->device_queue = newSCpnt;
+			spin_unlock_irqrestore(&device_request_lock, flags);
+		} else {
+			spin_lock_irqsave(&device_request_lock, flags);
+			SDpnt->queue_depth--;
+			spin_unlock_irqrestore(&device_request_lock, flags);
+		}
+	}
 }
 
 /*
@@ -1447,8 +1509,8 @@
 		SDpnt->device_queue = SCnext = SCpnt->next;
 		kfree((char *) SCpnt);
 	}
-	SDpnt->has_cmdblocks = 0;
 	SDpnt->queue_depth = 0;
+	SDpnt->new_queue_depth = 0;
 	spin_unlock_irqrestore(&device_request_lock, flags);
 }
 
@@ -1463,63 +1525,144 @@
  *
  * Lock status: No locking assumed or required.
  *
- * Notes:
+ * Notes:	We really only allocate one command here.  We will allocate
+ *		more commands as needed once the device goes into real use.
  */
 void scsi_build_commandblocks(Scsi_Device * SDpnt)
 {
 	unsigned long flags;
-	struct Scsi_Host *host = SDpnt->host;
-	int j;
 	Scsi_Cmnd *SCpnt;
 
+	if (SDpnt->queue_depth != 0)
+		return;
+		
+	SCpnt = (Scsi_Cmnd *) kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC |
+			(SDpnt->host->unchecked_isa_dma ? GFP_DMA : 0));
+	if (NULL == SCpnt) {
+		/*
+		 * Since we don't currently have *any* command blocks on this
+		 * device, go ahead and try an atomic allocation...
+		 */
+		SCpnt = (Scsi_Cmnd *) kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC |
+			(SDpnt->host->unchecked_isa_dma ? GFP_DMA : 0));
+		if (NULL == SCpnt)
+			return;	/* Oops, we aren't going anywhere for now */
+	}
+
+	memset(SCpnt, 0, sizeof(Scsi_Cmnd));
+	SCpnt->host = SDpnt->host;
+	SCpnt->device = SDpnt;
+	SCpnt->target = SDpnt->id;
+	SCpnt->lun = SDpnt->lun;
+	SCpnt->channel = SDpnt->channel;
+	SCpnt->request = NULL;
+	SCpnt->use_sg = 0;
+	SCpnt->old_use_sg = 0;
+	SCpnt->old_cmd_len = 0;
+	SCpnt->underflow = 0;
+	SCpnt->old_underflow = 0;
+	SCpnt->transfersize = 0;
+	SCpnt->resid = 0;
+	SCpnt->serial_number = 0;
+	SCpnt->serial_number_at_timeout = 0;
+	SCpnt->host_scribble = NULL;
+	SCpnt->state = SCSI_STATE_UNUSED;
+	SCpnt->owner = SCSI_OWNER_NOBODY;
 	spin_lock_irqsave(&device_request_lock, flags);
+	if(SDpnt->new_queue_depth == 0)
+		SDpnt->new_queue_depth = 1;
+	SDpnt->queue_depth++;
+	SCpnt->next = SDpnt->device_queue;
+	SDpnt->device_queue = SCpnt;
+	spin_unlock_irqrestore(&device_request_lock, flags);
+}
 
-	if (SDpnt->queue_depth == 0)
-	{
-		SDpnt->queue_depth = host->cmd_per_lun;
-		if (SDpnt->queue_depth == 0)
-			SDpnt->queue_depth = 1; /* live to fight another day */
-	}
-	SDpnt->device_queue = NULL;
-
-	for (j = 0; j < SDpnt->queue_depth; j++) {
-		SCpnt = (Scsi_Cmnd *)
-		    kmalloc(sizeof(Scsi_Cmnd),
-				     GFP_ATOMIC |
-				(host->unchecked_isa_dma ? GFP_DMA : 0));
-		if (NULL == SCpnt)
-			break;	/* If not, the next line will oops ... */
-		memset(SCpnt, 0, sizeof(Scsi_Cmnd));
-		SCpnt->host = host;
-		SCpnt->device = SDpnt;
-		SCpnt->target = SDpnt->id;
-		SCpnt->lun = SDpnt->lun;
-		SCpnt->channel = SDpnt->channel;
-		SCpnt->request = NULL;
-		SCpnt->use_sg = 0;
-		SCpnt->old_use_sg = 0;
-		SCpnt->old_cmd_len = 0;
-		SCpnt->underflow = 0;
-		SCpnt->old_underflow = 0;
-		SCpnt->transfersize = 0;
-		SCpnt->resid = 0;
-		SCpnt->serial_number = 0;
-		SCpnt->serial_number_at_timeout = 0;
-		SCpnt->host_scribble = NULL;
-		SCpnt->next = SDpnt->device_queue;
-		SDpnt->device_queue = SCpnt;
-		SCpnt->state = SCSI_STATE_UNUSED;
-		SCpnt->owner = SCSI_OWNER_NOBODY;
-	}
-	if (j < SDpnt->queue_depth) {	/* low on space (D.Gilbert 990424) */
-		printk(KERN_WARNING "scsi_build_commandblocks: want=%d, space for=%d blocks\n",
-		       SDpnt->queue_depth, j);
-		SDpnt->queue_depth = j;
-		SDpnt->has_cmdblocks = (0 != j);
-	} else {
-		SDpnt->has_cmdblocks = 1;
+/*
+ * Function:	scsi_adjust_queue_depth()
+ *
+ * Purpose:	Allow low level drivers to tell us to change the queue depth
+ * 		on a specific SCSI device
+ *
+ * Arguments:	SDpnt	- SCSI Device in question
+ * 		tagged	- Do we use tagged queueing (non-0) or do we treat
+ * 			  this device as an untagged device (0)
+ * 		tags	- Number of tags allowed if tagged queueing enabled,
+ * 			  or number of commands the low level driver can
+ * 			  queue up in non-tagged mode (as per cmd_per_lun).
+ *
+ * Returns:	Nothing
+ *
+ * Lock Status:	None held on entry
+ *
+ * Notes:	Low level drivers may call this at any time and we will do
+ * 		the right thing depending on whether or not the device is
+ * 		currently active and whether or not it even has the
+ * 		command blocks built yet.
+ *
+ * 		If cmdblocks != 0 then we are a live device.  We just set the
+ * 		new_queue_depth variable and when the scsi completion handler
+ * 		notices that queue_depth != new_queue_depth it will work to
+ *		rectify the situation.  If new_queue_depth is less than current
+ *		queue_depth, then it will free the completed command instead of
+ *		putting it back on the free list and dec queue_depth.  Otherwise
+ *		it will try to allocate a new command block for the device and
+ *		put it on the free list along with the command that is being
+ *		completed.  Obviously, if the device isn't doing anything then
+ *		neither is this code, so it will bring the devices queue depth
+ *		back into line when the device is actually being used.  This
+ *		keeps us from needing to fire off a kernel thread or some such
+ *		nonsense (this routine can be called from interrupt code, so
+ *		handling allocations here would be tricky and risky, making
+ *		a kernel thread a much safer way to go if we wanted to handle
+ *		the work immediately instead of letting it get done a little
+ *		at a time in the completion handler).
+ */
+void scsi_adjust_queue_depth(Scsi_Device *SDpnt, int tagged, int tags)
+{
+	unsigned long flags;
+
+	/*
+	 * refuse to set tagged depth to an unworkable size
+	 */
+	if(tags <= 0)
+		return;
+	/*
+	 * Limit max queue depth on a single lun to 256 for now.  Remember,
+	 * we allocate a struct scsi_command for each of these and keep it
+	 * around forever.  Too deep of a depth just wastes memory.
+	 */
+	if(tags > 256)
+		return;
+
+	spin_lock_irqsave(&device_request_lock, flags);
+	SDpnt->new_queue_depth = tags;
+	switch(tagged) {
+		case MSG_ORDERED_TAG:
+			SDpnt->ordered_tags = 1;
+			SDpnt->simple_tags = 1;
+			break;
+		case MSG_SIMPLE_TAG:
+			SDpnt->ordered_tags = 0;
+			SDpnt->simple_tags = 1;
+			break;
+		default:
+			printk(KERN_WARNING "(scsi%d:%d:%d:%d) "
+				"scsi_adjust_queue_depth, bad queue type, "
+				"disabled\n", SDpnt->host->host_no,
+				SDpnt->channel, SDpnt->id, SDpnt->lun); 
+		case 0:
+			SDpnt->ordered_tags = SDpnt->simple_tags = 0;
+			if(SDpnt->host->cmd_per_lun)
+				SDpnt->new_queue_depth = SDpnt->host->cmd_per_lun;
+			else
+				SDpnt->new_queue_depth = 1;
+			break;
 	}
 	spin_unlock_irqrestore(&device_request_lock, flags);
+	if(SDpnt->queue_depth == 0)
+	{
+		scsi_build_commandblocks(SDpnt);
+	}
 }
 
 void __init scsi_host_no_insert(char *str, int n)
@@ -1758,13 +1901,6 @@
 			goto out;	/* We do not yet support unplugging */
 
 		scan_scsis(HBA_ptr, 1, channel, id, lun);
-
-		/* FIXME (DB) This assumes that the queue_depth routines can be used
-		   in this context as well, while they were all designed to be
-		   called only once after the detect routine. (DB) */
-		/* queue_depth routine moved to inside scan_scsis(,1,,,) so
-		   it is called before build_commandblocks() */
-
 		err = length;
 		goto out;
 	}
@@ -1826,6 +1962,8 @@
 			 */
                         if (HBA_ptr->hostt->revoke)
                                 HBA_ptr->hostt->revoke(scd);
+			if (HBA_ptr->hostt->slave_detach)
+				(*HBA_ptr->hostt->slave_detach) (scd);
 			devfs_unregister (scd->de);
 			scsi_release_commandblocks(scd);
 
@@ -1963,9 +2101,6 @@
 				/* first register parent with driverfs */
 				device_register(&shpnt->host_driverfs_dev);
 				scan_scsis(shpnt, 0, 0, 0, 0);
-				if (shpnt->select_queue_depths != NULL) {
-					(shpnt->select_queue_depths) (shpnt, shpnt->host_queue);
-				}
 			}
 		}
 
@@ -1985,7 +2120,7 @@
 							(*sdtpnt->attach) (SDpnt);
 					if (SDpnt->attached) {
 						scsi_build_commandblocks(SDpnt);
-						if (0 == SDpnt->has_cmdblocks)
+						if (SDpnt->queue_depth == 0)
 							out_of_space = 1;
 					}
 				}
@@ -2116,6 +2251,8 @@
 				printk(KERN_ERR "Attached usage count = %d\n", SDpnt->attached);
 				goto err_out;
 			}
+			if (shpnt->hostt->slave_detach)
+				(*shpnt->hostt->slave_detach) (SDpnt);
 			devfs_unregister (SDpnt->de);
 			put_device(&SDpnt->sdev_driverfs_dev);
 		}
@@ -2272,10 +2409,10 @@
 			 * If this driver attached to the device, and don't have any
 			 * command blocks for this device, allocate some.
 			 */
-			if (SDpnt->attached && SDpnt->has_cmdblocks == 0) {
+			if (SDpnt->attached && SDpnt->queue_depth == 0) {
 				SDpnt->online = TRUE;
 				scsi_build_commandblocks(SDpnt);
-				if (0 == SDpnt->has_cmdblocks)
+				if (SDpnt->queue_depth == 0)
 					out_of_space = 1;
 			}
 		}
@@ -2325,6 +2462,8 @@
 				 * Nobody is using this device any more.  Free all of the
 				 * command structures.
 				 */
+				if (shpnt->hostt->slave_detach)
+					(*shpnt->hostt->slave_detach) (SDpnt);
 				scsi_release_commandblocks(SDpnt);
 			}
 		}
@@ -2399,16 +2538,16 @@
 		for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
 			for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
 				/*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
-				printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
+				printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
 				       i++,
 
 				       SCpnt->host->host_no,
 				       SCpnt->channel,
-				       SCpnt->target,
-				       SCpnt->lun,
+                                       SCpnt->target,
+                                       SCpnt->lun,
 
-				       kdevname(SCpnt->request->rq_dev),
-				       SCpnt->request->sector,
+                                       kdevname(SCpnt->request->rq_dev),
+                                       (unsigned long long)SCpnt->request->sector,
 				       SCpnt->request->nr_sectors,
 				       (long)SCpnt->request->current_nr_sectors,
 				       SCpnt->request->rq_status,
@@ -2678,9 +2817,13 @@
         SDpnt->host = SHpnt;
         SDpnt->id = SHpnt->this_id;
         SDpnt->type = -1;
-        SDpnt->queue_depth = 1;
+	SDpnt->new_queue_depth = 1;
         
 	scsi_build_commandblocks(SDpnt);
+	if(SDpnt->queue_depth == 0) {
+		kfree(SDpnt);
+		return NULL;
+	}
 
 	scsi_initialize_queue(SDpnt, SHpnt);
 
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/scsi.h	Fri Oct 11 21:22:55 2002
@@ -481,6 +481,7 @@
 extern void scsi_bottom_half_handler(void);
 extern void scsi_release_commandblocks(Scsi_Device * SDpnt);
 extern void scsi_build_commandblocks(Scsi_Device * SDpnt);
+extern void scsi_adjust_queue_depth(Scsi_Device *, int, int);
 extern void scsi_done(Scsi_Cmnd * SCpnt);
 extern void scsi_finish_command(Scsi_Cmnd *);
 extern int scsi_retry_command(Scsi_Cmnd *);
@@ -563,6 +564,8 @@
 	volatile unsigned short device_busy;	/* commands actually active on low-level */
 	Scsi_Cmnd *device_queue;	/* queue of SCSI Command structures */
         Scsi_Cmnd *current_cmnd;	/* currently active command */
+	unsigned short queue_depth;	/* How deep of a queue we have */
+	unsigned short new_queue_depth; /* How deep of a queue we want */
 
 	unsigned int id, lun, channel;
 
@@ -584,26 +587,28 @@
 	char * model;		/* ... after scan; point to static string */
 	char * rev;		/* ... "nullnullnullnull" before scan */
 	unsigned char current_tag;	/* current tag */
-	unsigned char sync_min_period;	/* Not less than this period */
-	unsigned char sync_max_offset;	/* Not greater than this offset */
-	unsigned char queue_depth;	/* How deep a queue to use */
+//	unsigned char sync_min_period;	/* Not less than this period */
+//	unsigned char sync_max_offset;	/* Not greater than this offset */
 
 	unsigned online:1;
 	unsigned writeable:1;
 	unsigned removable:1;
 	unsigned random:1;
-	unsigned has_cmdblocks:1;
 	unsigned changed:1;	/* Data invalid due to media change */
 	unsigned busy:1;	/* Used to prevent races */
 	unsigned lockable:1;	/* Able to prevent media removal */
 	unsigned borken:1;	/* Tell the Seagate driver to be 
 				 * painfully slow on this device */
-	unsigned tagged_supported:1;	/* Supports SCSI-II tagged queuing */
-	unsigned tagged_queue:1;	/* SCSI-II tagged queuing enabled */
-	unsigned disconnect:1;	/* can disconnect */
+//	unsigned disconnect:1;	/* can disconnect */
 	unsigned soft_reset:1;	/* Uses soft reset option */
-	unsigned sync:1;	/* Negotiate for sync transfers */
-	unsigned wide:1;	/* Negotiate for WIDE transfers */
+	unsigned sdtr:1;	/* Device supports SDTR messages */
+	unsigned wdtr:1;	/* Device supports WDTR messages */
+	unsigned ppr:1;		/* Device supports PPR messages */
+	unsigned tagged_supported:1;	/* Supports SCSI-II tagged queuing */
+	unsigned tagged_queue:1;/* This is going away!!!!  Look at simple_tags
+				   instead!!!  Please fix your driver now!! */
+	unsigned simple_tags:1;	/* simple queue tag messages are enabled */
+	unsigned ordered_tags:1;/* ordered queue tag messages are enabled */
 	unsigned single_lun:1;	/* Indicates we should only allow I/O to
 				 * one of the luns for the device at a 
 				 * time. */
@@ -615,6 +620,8 @@
 	unsigned remap:1;	/* support remapping  */
 	unsigned starved:1;	/* unable to process commands because
 				   host busy */
+//	unsigned sync:1;	/* Sync transfer state, managed by host */
+//	unsigned wide:1;	/* WIDE transfer state, managed by host */
 
 	unsigned int device_blocked;	/* Device returned QUEUE_FULL. */
 
diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
--- a/drivers/scsi/scsi_ioctl.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/scsi/scsi_ioctl.c	Fri Oct 11 21:23:04 2002
@@ -424,6 +424,14 @@
 		return 0;
 	case SCSI_IOCTL_GET_BUS_NUMBER:
 		return put_user(dev->host->host_no, (int *) arg);
+	/*
+	 * The next two ioctls either need to go or need to be changed to
+	 * pass tagged queueing changes through the low level drivers.
+	 * Simply enabling or disabling tagged queueing without the knowledge
+	 * of the low level driver is a *BAD* thing.
+	 *
+	 * Oct. 10, 2002 - Doug Ledford <dledford@redhat.com>
+	 */
 	case SCSI_IOCTL_TAGGED_ENABLE:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/scsi/scsi_scan.c	Fri Oct 11 21:23:03 2002
@@ -1409,6 +1409,14 @@
 	sdev->lockable = sdev->removable;
 	sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
 
+	if (sdev->scsi_level >= SCSI_3 || (sdev->inquiry_len > 56 &&
+		inq_result[56] & 0x04))
+		sdev->ppr = 1;
+	if (inq_result[7] & 0x60)
+		sdev->wdtr = 1;
+	if (inq_result[7] & 0x10)
+		sdev->sdtr = 1;
+
 	/*
 	 * XXX maybe move the identifier and driverfs/devfs setup to a new
 	 * function, and call them after this function is called.
@@ -1469,6 +1477,15 @@
 		if (sdt->detect)
 			sdev->attached += (*sdt->detect) (sdev);
 
+	if (sdev->host->hostt->slave_attach != NULL) {
+		if (sdev->host->hostt->slave_attach(sdev) != 0) {
+			printk(KERN_INFO "%s: scsi_add_lun: failed low level driver attach, setting device offline", devname);
+			sdev->online = FALSE;
+		}
+	} else if(sdev->host->cmd_per_lun) {
+		scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+	}
+
 	if (sdevnew != NULL)
 		*sdevnew = sdev;
 
@@ -1513,9 +1530,9 @@
 	 * XXX maybe change scsi_release_commandblocks to not reset
 	 * queue_depth to 0.
 	 */
-	sdevscan->queue_depth = 1;
+	sdevscan->new_queue_depth = 1;
 	scsi_build_commandblocks(sdevscan);
-	if (sdevscan->has_cmdblocks == 0)
+	if (sdevscan->queue_depth == 0)
 		goto alloc_failed;
 
 	sreq = scsi_allocate_request(sdevscan);
@@ -1589,7 +1606,7 @@
 		kfree(scsi_result);
 	if (sreq != NULL)
 		scsi_release_request(sreq);
-	if (sdevscan->has_cmdblocks != 0)
+	if (sdevscan->queue_depth != 0)
 		scsi_release_commandblocks(sdevscan);
 	return SCSI_SCAN_NO_RESPONSE;
 }
@@ -1743,9 +1760,9 @@
 	if (sdevscan->scsi_level < SCSI_3)
 		return 1;
 
-	sdevscan->queue_depth = 1;
+	sdevscan->new_queue_depth = 1;
 	scsi_build_commandblocks(sdevscan);
-	if (sdevscan->has_cmdblocks == 0) {
+	if (sdevscan->queue_depth == 0) {
 		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
 		/*
 		 * We are out of memory, don't try scanning any further.
@@ -2003,21 +2020,6 @@
 	scsi_free_sdev(sdevscan);
 	if (res == SCSI_SCAN_LUN_PRESENT) {
 		BUG_ON(sdev == NULL);
-		/*
-		 * FIXME calling select_queue_depths is wrong for adapters
-		 * that modify queue depths of all scsi devices - the
-		 * adapter might change a queue depth (not for this sdev),
-		 * but the mid-layer will not change the queue depth. This
-		 * does not cause an oops, but queue_depth will not match
-		 * the actual queue depth used.
-		 *
-		 * Perhaps use a default queue depth, and allow them to be
-		 * modified at boot/insmod time, and/or via sysctl/ioctl/proc;
-		 * plus have dynamic queue depth adjustment like the
-		 * aic7xxx driver.
-		 */
-		if (shost->select_queue_depths != NULL)
-			(shost->select_queue_depths) (shost, shost->host_queue);
 
 		for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
 			if (sdt->init && sdt->dev_noticed)
@@ -2028,7 +2030,7 @@
 				(*sdt->attach) (sdev);
 				if (sdev->attached) {
 					scsi_build_commandblocks(sdev);
-					if (sdev->has_cmdblocks == 0)
+					if (sdev->queue_depth == 0)
 						printk(ALLOC_FAILURE_MSG,
 						       __FUNCTION__);
 				}
diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
--- a/drivers/scsi/scsi_syms.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/scsi/scsi_syms.c	Fri Oct 11 21:22:58 2002
@@ -66,6 +66,7 @@
 EXPORT_SYMBOL(scsi_report_bus_reset);
 EXPORT_SYMBOL(scsi_block_requests);
 EXPORT_SYMBOL(scsi_unblock_requests);
+EXPORT_SYMBOL(scsi_adjust_queue_depth);
 
 EXPORT_SYMBOL(scsi_get_host_dev);
 EXPORT_SYMBOL(scsi_free_host_dev);
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/scsi/sd.c	Fri Oct 11 21:23:02 2002
@@ -47,7 +47,6 @@
 #include <linux/smp.h>
 
 #include <asm/uaccess.h>
-#include <asm/system.h>
 #include <asm/io.h>
 
 #define MAJOR_NR SCSI_DISK0_MAJOR
@@ -300,7 +299,8 @@
  **/
 static int sd_init_command(Scsi_Cmnd * SCpnt)
 {
-	int dsk_nr, part_nr, block, this_count;
+	int dsk_nr, part_nr, this_count;
+	sector_t block;
 	Scsi_Device *sdp;
 #if CONFIG_SCSI_LOGGING
 	char nbuff[6];
@@ -317,8 +317,8 @@
 	block = SCpnt->request->sector;
 	this_count = SCpnt->request_bufflen >> 9;
 
-	SCSI_LOG_HLQUEUE(1, printk("sd_command_init: dsk_nr=%d, block=%d, "
-			    "count=%d\n", dsk_nr, block, this_count));
+	SCSI_LOG_HLQUEUE(1, printk("sd_command_init: dsk_nr=%d, block=%llu, "
+			    "count=%d\n", dsk_nr, (unsigned long long)block, this_count));
 
 	sdp = SCpnt->device;
 	/* >>>>> the "(part_nr & 0xf)" excludes 15th partition, why?? */
@@ -341,8 +341,8 @@
 		return 0;
 	}
 	SCSI_LOG_HLQUEUE(2, sd_dskname(dsk_nr, nbuff));
-	SCSI_LOG_HLQUEUE(2, printk("%s : [part_nr=%d], block=%d\n",
-				   nbuff, part_nr, block));
+	SCSI_LOG_HLQUEUE(2, printk("%s : [part_nr=%d], block=%llu\n",
+				   nbuff, part_nr, (unsigned long long)block));
 
 	/*
 	 * If we have a 1K hardware sectorsize, prevent access to single
@@ -605,8 +605,8 @@
 	int result = SCpnt->result;
 	int this_count = SCpnt->bufflen >> 9;
 	int good_sectors = (result == 0 ? this_count : 0);
-	int block_sectors = 1;
-	long error_sector;
+	sector_t block_sectors = 1;
+	sector_t error_sector;
 #if CONFIG_SCSI_LOGGING
 	char nbuff[6];
 
@@ -629,7 +629,7 @@
 
 	/* An error occurred */
 	if (driver_byte(result) != 0 && 	/* An error occured */
-	    SCpnt->sense_buffer[0] != 0xF0) {	/* Sense data is valid */
+	    SCpnt->sense_buffer[0] == 0xF0) {	/* Sense data is valid */
 		switch (SCpnt->sense_buffer[2]) {
 		case MEDIUM_ERROR:
 			error_sector = (SCpnt->sense_buffer[3] << 24) |
@@ -1009,7 +1009,7 @@
 		    SRpnt->sr_sense_buffer[2] == NOT_READY)
 			sdp->changed = 1;
 
-		/* Either no media are present but the drive didnt tell us,
+		/* Either no media are present but the drive didn't tell us,
 		   or they are present but the read capacity command fails */
 		/* sdkp->media_present = 0; -- not always correct */
 		sdkp->capacity = 0x200000; /* 1 GB - random */
@@ -1017,7 +1017,7 @@
 		return;
 	}
 
-	sdkp->capacity = 1 + ((buffer[0] << 24) |
+	sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) |
 			      (buffer[1] << 16) |
 			      (buffer[2] << 8) |
 			      buffer[3]);
@@ -1053,24 +1053,31 @@
 		 * Jacques Gelinas (Jacques@solucorp.qc.ca)
 		 */
 		int hard_sector = sector_size;
-		int sz = sdkp->capacity * (hard_sector/256);
+		sector_t sz = sdkp->capacity * (hard_sector/256);
 		request_queue_t *queue = &sdp->request_queue;
+		sector_t mb;
 
 		blk_queue_hardsect_size(queue, hard_sector);
+		/* avoid 64-bit division on 32-bit platforms */
+		mb = sz >> 1;
+		sector_div(sz, 1250);
+		mb -= sz - 974;
+		sector_div(mb, 1950);
+
 		printk(KERN_NOTICE "SCSI device %s: "
-		       "%d %d-byte hdwr sectors (%d MB)\n",
-		       diskname, sdkp->capacity,
-		       hard_sector, (sz/2 - sz/1250 + 974)/1950);
+		       "%llu %d-byte hdwr sectors (%llu MB)\n",
+		       diskname, (unsigned long long)sdkp->capacity,
+		       hard_sector, (unsigned long long)mb);
 	}
 
 	/* Rescale capacity to 512-byte units */
 	if (sector_size == 4096)
 		sdkp->capacity <<= 3;
-	if (sector_size == 2048)
+	else if (sector_size == 2048)
 		sdkp->capacity <<= 2;
-	if (sector_size == 1024)
+	else if (sector_size == 1024)
 		sdkp->capacity <<= 1;
-	if (sector_size == 256)
+	else if (sector_size == 256)
 		sdkp->capacity >>= 1;
 
 	sdkp->device->sector_size = sector_size;
diff -Nru a/drivers/scsi/sd.h b/drivers/scsi/sd.h
--- a/drivers/scsi/sd.h	Fri Oct 11 21:23:00 2002
+++ b/drivers/scsi/sd.h	Fri Oct 11 21:23:00 2002
@@ -21,7 +21,7 @@
 #endif
 
 typedef struct scsi_disk {
-	unsigned capacity;		/* size in 512-byte sectors */
+	sector_t capacity;		/* size in 512-byte sectors */
 	Scsi_Device *device;
 	unsigned char media_present;
 	unsigned char write_prot;
diff -Nru a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
--- a/drivers/scsi/seagate.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/scsi/seagate.c	Fri Oct 11 21:22:57 2002
@@ -265,16 +265,14 @@
 #define WRITE_CONTROL(d) { isa_writeb((d), st0x_cr_sr); }
 #define WRITE_DATA(d) { isa_writeb((d), st0x_dr); }
 
-void
-st0x_setup (char *str, int *ints)
+static void st0x_setup (char *str, int *ints)
 {
 	controller_type = SEAGATE;
 	base_address = ints[1];
 	irq = ints[2];
 }
 
-void
-tmc8xx_setup (char *str, int *ints)
+static void tmc8xx_setup (char *str, int *ints)
 {
 	controller_type = FD;
 	base_address = ints[1];
@@ -389,8 +387,14 @@
 {
 	register int count = 0, start = jiffies + 1, stop = start + 25;
 
-	while (time_before (jiffies, start)) ;
-	for (; time_before (jiffies, stop); ++count) ;
+	/* FIXME: There may be a better approach, this is a straight port for
+	   now */
+	preempt_disable();
+	while (time_before (jiffies, start))
+		cpu_relax();
+	for (; time_before (jiffies, stop); ++count)
+		cpu_relax();
+	preempt_enable();
 
 /*
  * Ok, we now have a count for .25 seconds.  Convert to a
@@ -406,8 +410,9 @@
 {
 	register int count;
 
-	for (count = borken_calibration; count && (STATUS & STAT_REQ);
-	     --count) ;
+	for (count = borken_calibration; count && (STATUS & STAT_REQ); --count)
+		cpu_relax();
+	     	
 #if (DEBUG & DEBUG_BORKEN)
 	if (count)
 		printk ("scsi%d : borken timeout\n", hostno);
@@ -431,7 +436,7 @@
 
 	tpnt->proc_name = "seagate";
 /*
- *    First, we try for the manual override.
+ *	First, we try for the manual override.
  */
 	DANY ("Autodetecting ST0x / TMC-8xx\n");
 
@@ -462,14 +467,9 @@
  * space for the on-board RAM instead.
  */
 
-		for (i = 0;
-		     i < (sizeof (seagate_bases) / sizeof (unsigned int)); ++i)
-
+		for (i = 0; i < (sizeof (seagate_bases) / sizeof (unsigned int)); ++i)
 			for (j = 0; !base_address && j < NUM_SIGNATURES; ++j)
-				if (isa_check_signature
-				    (seagate_bases[i] + signatures[j].offset,
-				     signatures[j].signature,
-				     signatures[j].length)) {
+				if (isa_check_signature(seagate_bases[i] + signatures[j].offset, signatures[j].signature, signatures[j].length)) {
 					base_address = seagate_bases[i];
 					controller_type = signatures[j].type;
 				}
@@ -480,40 +480,36 @@
 	tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;
 
 	if (!base_address) {
-		DANY ("ST0x / TMC-8xx not detected.\n");
+		printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n");
 		return 0;
 	}
 
-	st0x_cr_sr =
-	    base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);
+	st0x_cr_sr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);
 	st0x_dr = st0x_cr_sr + 0x200;
 
-	DANY ("%s detected. Base address = %x, cr = %x, dr = %x\n",
+	DANY("%s detected. Base address = %x, cr = %x, dr = %x\n",
 	      tpnt->name, base_address, st0x_cr_sr, st0x_dr);
 
-/*
- *	At all times, we will use IRQ 5.  Should also check for IRQ3 if we
- *      loose our first interrupt.
- */
+	/*
+	 *	At all times, we will use IRQ 5.  Should also check for IRQ3
+	 *	if we loose our first interrupt.
+	 */
 	instance = scsi_register (tpnt, 0);
 	if (instance == NULL)
 		return 0;
 
 	hostno = instance->host_no;
-	if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT,
-			 (controller_type == SEAGATE) ? "seagate" : "tmc-8xx",
-			 instance)) {
-		printk ("scsi%d : unable to allocate IRQ%d\n", hostno, irq);
+	if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
+		printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
 		return 0;
 	}
 	instance->irq = irq;
 	instance->io_port = base_address;
 #ifdef SLOW_RATE
-	printk (KERN_INFO "Calibrating borken timer... ");
-	borken_init ();
-	printk (" %d cycles per transfer\n", borken_calibration);
+	printk(KERN_INFO "Calibrating borken timer... ");
+	borken_init();
+	printk(" %d cycles per transfer\n", borken_calibration);
 #endif
-
 	printk (KERN_INFO "This is one second... ");
 	{
 		int clock;
@@ -559,12 +555,11 @@
 	return 1;
 }
 
-const char *
-seagate_st0x_info (struct Scsi_Host *shpnt)
+static const char *seagate_st0x_info (struct Scsi_Host *shpnt)
 {
 	static char buffer[64];
 
-	sprintf (buffer, "%s at irq %d, address 0x%05X",
+	snprintf(buffer, 64, "%s at irq %d, address 0x%05X",
 		 (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
 		 irq, base_address);
 	return buffer;
@@ -640,36 +635,29 @@
 	int temp;
 	Scsi_Cmnd *SCtmp;
 
-	DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n",
-		 hostno);
+	DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
 
 	if (!should_reconnect)
-		printk ("scsi%d: unexpected interrupt.\n", hostno);
+		printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno);
 	else {
 		should_reconnect = 0;
 
-		DPRINTK (PHASE_RESELECT, "scsi%d : internal_command("
-			 "%d, %08x, %08x, RECONNECT_NOW\n", hostno,
-			 current_target, current_data, current_bufflen);
-
-		temp =
-		    internal_command (current_target, current_lun, current_cmnd,
-				      current_data, current_bufflen,
-				      RECONNECT_NOW);
+		DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", 
+			hostno, current_target, current_data, current_bufflen);
 
-		if (msg_byte (temp) != DISCONNECT) {
+		temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW);
+
+		if (msg_byte(temp) != DISCONNECT) {
 			if (done_fn) {
-				DPRINTK (PHASE_RESELECT,
-					 "scsi%d : done_fn(%d,%08x)", hostno,
-					 hostno, temp);
+				DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp);
 				if (!SCint)
 					panic ("SCint == NULL in seagate");
 				SCtmp = SCint;
 				SCint = NULL;
 				SCtmp->result = temp;
-				done_fn (SCtmp);
+				done_fn(SCtmp);
 			} else
-				printk ("done_fn() not defined.\n");
+				printk(KERN_ERR "done_fn() not defined.\n");
 		}
 	}
 }
@@ -687,7 +675,7 @@
 
 static int recursion_depth = 0;
 
-int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	int result, reconnect;
 	Scsi_Cmnd *SCtmp;
@@ -696,53 +684,49 @@
 	done_fn = done;
 	current_target = SCpnt->target;
 	current_lun = SCpnt->lun;
-	(const void *) current_cmnd = SCpnt->cmnd;
+	current_cmnd = SCpnt->cmnd;
 	current_data = (unsigned char *) SCpnt->request_buffer;
 	current_bufflen = SCpnt->request_bufflen;
 	SCint = SCpnt;
 	if (recursion_depth)
-		return 0;
+		return 1;
 	recursion_depth++;
 	do {
 #ifdef LINKED
-/*
- * Set linked command bit in control field of SCSI command.
- */
+		/*
+		 * Set linked command bit in control field of SCSI command.
+		 */
 
 		current_cmnd[SCpnt->cmd_len] |= 0x01;
 		if (linked_connected) {
-			DPRINTK (DEBUG_LINKED,
-				 "scsi%d : using linked commands, current I_T_L nexus is ",
-				 hostno);
-			if ((linked_target == current_target)
-			    && (linked_lun == current_lun)) {
-				DPRINTK (DEBUG_LINKED, "correct\n");
+			DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno);
+			if (linked_target == current_target && linked_lun == current_lun) 
+			{
+				DPRINTK(DEBUG_LINKED, "correct\n");
 				reconnect = LINKED_RIGHT;
 			} else {
-				DPRINTK (DEBUG_LINKED, "incorrect\n");
+				DPRINTK(DEBUG_LINKED, "incorrect\n");
 				reconnect = LINKED_WRONG;
 			}
 		} else
 #endif				/* LINKED */
 			reconnect = CAN_RECONNECT;
 
-		result =
-		    internal_command (SCint->target, SCint->lun, SCint->cmnd,
-				      SCint->request_buffer,
-				      SCint->request_bufflen, reconnect);
-		if (msg_byte (result) == DISCONNECT)
+		result = internal_command(SCint->target, SCint->lun, SCint->cmnd,
+				      SCint->request_buffer, SCint->request_bufflen, reconnect);
+		if (msg_byte(result) == DISCONNECT)
 			break;
 		SCtmp = SCint;
 		SCint = NULL;
 		SCtmp->result = result;
-		done_fn (SCtmp);
+		done_fn(SCtmp);
 	}
 	while (SCint);
 	recursion_depth--;
 	return 0;
 }
 
-int seagate_st0x_command (Scsi_Cmnd * SCpnt)
+static int seagate_st0x_command(Scsi_Cmnd * SCpnt)
 {
 	return internal_command (SCpnt->target, SCpnt->lun, SCpnt->cmnd,
 				 SCpnt->request_buffer, SCpnt->request_bufflen,
@@ -755,17 +739,12 @@
 	unsigned char *data = NULL;
 	struct scatterlist *buffer = NULL;
 	int clock, temp, nobuffs = 0, done = 0, len = 0;
-	unsigned long flags;
-
 #ifdef DEBUG
 	int transfered = 0, phase = 0, newphase;
 #endif
-
 	register unsigned char status_read;
 	unsigned char tmp_data, tmp_control, status = 0, message = 0;
-
 	unsigned transfersize = 0, underflow = 0;
-
 #ifdef SLOW_RATE
 	int borken = (int) SCint->device->borken;	/* Does the current target require
 							   Very Slow I/O ?  */
@@ -775,84 +754,76 @@
 	st0x_aborted = 0;
 
 #if (DEBUG & PRINT_COMMAND)
-	printk ("scsi%d : target = %d, command = ", hostno, target);
-	print_command ((unsigned char *) cmnd);
+	printk("scsi%d : target = %d, command = ", hostno, target);
+	print_command((unsigned char *) cmnd);
 #endif
 
 #if (DEBUG & PHASE_RESELECT)
 	switch (reselect) {
 	case RECONNECT_NOW:
-		printk ("scsi%d : reconnecting\n", hostno);
+		printk("scsi%d : reconnecting\n", hostno);
 		break;
 #ifdef LINKED
 	case LINKED_RIGHT:
-		printk ("scsi%d : connected, can reconnect\n", hostno);
+		printk("scsi%d : connected, can reconnect\n", hostno);
 		break;
 	case LINKED_WRONG:
-		printk ("scsi%d : connected to wrong target, can reconnect\n",
+		printk("scsi%d : connected to wrong target, can reconnect\n",
 			hostno);
 		break;
 #endif
 	case CAN_RECONNECT:
-		printk ("scsi%d : allowed to reconnect\n", hostno);
+		printk("scsi%d : allowed to reconnect\n", hostno);
 		break;
 	default:
-		printk ("scsi%d : not allowed to reconnect\n", hostno);
+		printk("scsi%d : not allowed to reconnect\n", hostno);
 	}
 #endif
 
 	if (target == (controller_type == SEAGATE ? 7 : 6))
 		return DID_BAD_TARGET;
 
-/*
- *	We work it differently depending on if this is is "the first time,"
- *      or a reconnect.  If this is a reselect phase, then SEL will
- *      be asserted, and we must skip selection / arbitration phases.
- */
+	/*
+	 *	We work it differently depending on if this is is "the first time,"
+	 *      or a reconnect.  If this is a reselect phase, then SEL will
+	 *      be asserted, and we must skip selection / arbitration phases.
+	 */
 
 	switch (reselect) {
 	case RECONNECT_NOW:
 		DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno);
-
-/*
- *	At this point, we should find the logical or of our ID and the original
- *      target's ID on the BUS, with BSY, SEL, and I/O signals asserted.
- *
- *      After ARBITRATION phase is completed, only SEL, BSY, and the
- *      target ID are asserted.  A valid initiator ID is not on the bus
- *      until IO is asserted, so we must wait for that.
- */
+		/*
+		 *	At this point, we should find the logical or of our ID
+		 *	and the original target's ID on the BUS, with BSY, SEL,
+		 *	and I/O signals asserted.
+		 *
+		 *      After ARBITRATION phase is completed, only SEL, BSY,
+		 *	and the target ID are asserted.  A valid initiator ID
+		 *	is not on the bus until IO is asserted, so we must wait
+		 *	for that.
+		 */
 		ULOOP (100 * 1000) {
 			temp = STATUS;
 			if ((temp & STAT_IO) && !(temp & STAT_BSY))
 				break;
-
 			if (TIMEOUT) {
-				DPRINTK (PHASE_RESELECT,
-					 "scsi%d : RESELECT timed out while waiting for IO .\n",
-					 hostno);
+				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno);
 				return (DID_BAD_INTR << 16);
 			}
 		}
 
-/*
- *	After I/O is asserted by the target, we can read our ID and its
- *      ID off of the BUS.
- */
+		/*
+		 *	After I/O is asserted by the target, we can read our ID
+		 *	and its ID off of the BUS.
+		 */
 
-		if (!
-		    ((temp =
-		      DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) {
-			DPRINTK (PHASE_RESELECT,
-				 "scsi%d : detected reconnect request to different target.\n"
-				 "\tData bus = %d\n", hostno, temp);
+		if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) {
+			DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp);
 			return (DID_BAD_INTR << 16);
 		}
 
 		if (!(temp & (1 << current_target))) {
-			printk
-			    ("scsi%d : Unexpected reselect interrupt.  Data bus = %d\n",
-			     hostno, temp);
+			printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt.  Data bus = %d\n", hostno, temp);
 			return (DID_BAD_INTR << 16);
 		}
 
@@ -862,10 +833,11 @@
 		len = current_bufflen;	/* WDE add */
 		nobuffs = current_nobuffs;
 
-/*
- *	We have determined that we have been selected.  At this point,
- *      we must respond to the reselection by asserting BSY ourselves
- */
+		/*
+		 *	We have determined that we have been selected.  At this
+		 *	point, we must respond to the reselection by asserting
+		 *	BSY ourselves
+		 */
 
 #if 1
 		WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
@@ -873,93 +845,80 @@
 		WRITE_CONTROL (BASE_CMD | CMD_BSY);
 #endif
 
-/*
- *	The target will drop SEL, and raise BSY, at which time we must drop
- *      BSY.
- */
+		/*
+		 *	The target will drop SEL, and raise BSY, at which time
+		 *	we must drop BSY.
+		 */
 
 		ULOOP (100 * 1000) {
 			if (!(STATUS & STAT_SEL))
 				break;
 			if (TIMEOUT) {
 				WRITE_CONTROL (BASE_CMD | CMD_INTR);
-				DPRINTK (PHASE_RESELECT,
-					 "scsi%d : RESELECT timed out while waiting for SEL.\n",
-					 hostno);
+				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno);
 				return (DID_BAD_INTR << 16);
 			}
 		}
-
 		WRITE_CONTROL (BASE_CMD);
-
-/*
- *	At this point, we have connected with the target and can get
- *      on with our lives.
- */
+		/*
+		 *	At this point, we have connected with the target
+		 *	and can get on with our lives.
+		 */
 		break;
 	case CAN_RECONNECT:
-
 #ifdef LINKED
-/*
- * This is a bletcherous hack, just as bad as the Unix #! interpreter stuff.
- * If it turns out we are using the wrong I_T_L nexus, the easiest way to deal
- * with it is to go into our INFORMATION TRANSFER PHASE code, send a ABORT
- * message on MESSAGE OUT phase, and then loop back to here.
- */
-
-	      connect_loop:
-
-#endif
-
-		DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n",
-			 hostno);
-
-/*
- *    BUS FREE PHASE
- *
- *      On entry, we make sure that the BUS is in a BUS FREE
- *      phase, by insuring that both BSY and SEL are low for
- *      at least one bus settle delay.  Several reads help
- *      eliminate wire glitch.
- */
+		/*
+		 * This is a bletcherous hack, just as bad as the Unix #!
+		 * interpreter stuff. If it turns out we are using the wrong
+		 * I_T_L nexus, the easiest way to deal with it is to go into
+		 *  our INFORMATION TRANSFER PHASE code, send a ABORT
+		 * message on MESSAGE OUT phase, and then loop back to here.
+		 */
+connect_loop:
+#endif
+		DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno);
+
+		/*
+		 *    BUS FREE PHASE
+		 *
+		 *      On entry, we make sure that the BUS is in a BUS FREE
+		 *      phase, by insuring that both BSY and SEL are low for
+		 *      at least one bus settle delay.  Several reads help
+		 *      eliminate wire glitch.
+		 */
 
 #ifndef ARBITRATE
 #error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock.
 		clock = jiffies + ST0X_BUS_FREE_DELAY;
 
-		while (((STATUS | STATUS | STATUS) &
-			(STAT_BSY | STAT_SEL)) &&
-		       (!st0x_aborted) && time_before (jiffies, clock)) ;
+		while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock))
+			cpu_relax();
 
 		if (time_after (jiffies, clock))
 			return retcode (DID_BUS_BUSY);
 		else if (st0x_aborted)
 			return retcode (st0x_aborted);
 #endif
-
-		DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n",
-			 hostno);
+		DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno);
 
 		clock = jiffies + ST0X_SELECTION_DELAY;
 
-/*
- * Arbitration/selection procedure :
- * 1.  Disable drivers
- * 2.  Write HOST adapter address bit
- * 3.  Set start arbitration.
- * 4.  We get either ARBITRATION COMPLETE or SELECT at this
- *     point.
- * 5.  OR our ID and targets on bus.
- * 6.  Enable SCSI drivers and asserted SEL and ATTN
- */
+		/*
+		 * Arbitration/selection procedure :
+		 * 1.  Disable drivers
+		 * 2.  Write HOST adapter address bit
+		 * 3.  Set start arbitration.
+		 * 4.  We get either ARBITRATION COMPLETE or SELECT at this
+		 *     point.
+		 * 5.  OR our ID and targets on bus.
+		 * 6.  Enable SCSI drivers and asserted SEL and ATTN
+		 */
 
 #ifdef ARBITRATE
-		save_flags (flags);
-		cli ();
-		WRITE_CONTROL (0);
-		WRITE_DATA ((controller_type == SEAGATE) ? 0x80 : 0x40);
-		WRITE_CONTROL (CMD_START_ARB);
-		restore_flags (flags);
+		/* FIXME: verify host lock is always held here */
+		WRITE_CONTROL(0);
+		WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40);
+		WRITE_CONTROL(CMD_START_ARB);
 
 		ULOOP (ST0X_SELECTION_DELAY * 10000) {
 			status_read = STATUS;
@@ -968,40 +927,31 @@
 			if (st0x_aborted)	/* FIXME: What? We are going to do something even after abort? */
 				break;
 			if (TIMEOUT || (status_read & STAT_SEL)) {
-				printk
-				    ("scsi%d : arbitration lost or timeout.\n",
-				     hostno);
+				printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno);
 				WRITE_CONTROL (BASE_CMD);
 				return retcode (DID_NO_CONNECT);
 			}
 		}
-
-		DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n",
-			 hostno);
+		DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno);
 #endif
 
-/*
- *    When the SCSI device decides that we're gawking at it, it will
- *    respond by asserting BUSY on the bus.
- *
- *    Note : the Seagate ST-01/02 product manual says that we should
- *    twiddle the DATA register before the control register.    However,
- *    this does not work reliably so we do it the other way around.
- *
- *    Probably could be a problem with arbitration too, we really should
- *    try this with a SCSI protocol or logic analyzer to see what is
- *    going on.
- */
-		tmp_data =
-		    (unsigned char) ((1 << target) |
-				     (controller_type ==
-				      SEAGATE ? 0x80 : 0x40));
-		tmp_control =
-		    BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN
-							    : 0);
+		/*
+		 *    When the SCSI device decides that we're gawking at it, 
+		 *    it will respond by asserting BUSY on the bus.
+		 *
+		 *    Note : the Seagate ST-01/02 product manual says that we
+		 *    should twiddle the DATA register before the control
+		 *    register. However, this does not work reliably so we do
+		 *    it the other way around.
+		 *
+		 *    Probably could be a problem with arbitration too, we
+		 *    really should try this with a SCSI protocol or logic 
+		 *    analyzer to see what is going on.
+		 */
+		tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
+		tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0);
 
-		save_flags (flags);
-		cli ();
+		/* FIXME: verify host lock is always held here */
 #ifdef OLDCNTDATASCEME
 #ifdef SWAPCNTDATA
 		WRITE_CONTROL (tmp_control);
@@ -1018,22 +968,20 @@
 		WRITE_CONTROL (tmp_control);	/* -- pavel@ucw.cz   */
 #endif
 
-		restore_flags (flags);
-
 		ULOOP (250 * 1000) {
 			if (st0x_aborted) {
-/*
- *	If we have been aborted, and we have a command in progress, IE the
- *      target still has BSY asserted, then we will reset the bus, and
- *      notify the midlevel driver to expect sense.
- */
+				/*
+				 *	If we have been aborted, and we have a
+				 *	command in progress, IE the target 
+				 *	still has BSY asserted, then we will
+				 *	reset the bus, and notify the midlevel
+				 *	driver to expect sense.
+				 */
 
 				WRITE_CONTROL (BASE_CMD);
 				if (STATUS & STAT_BSY) {
-					printk
-					    ("scsi%d : BST asserted after we've been aborted.\n",
-					     hostno);
-					seagate_st0x_reset (NULL, 0);
+					printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno);
+					seagate_st0x_bus_reset(NULL);
 					return retcode (DID_RESET);
 				}
 				return retcode (st0x_aborted);
@@ -1041,26 +989,20 @@
 			if (STATUS & STAT_BSY)
 				break;
 			if (TIMEOUT) {
-				DPRINTK (PHASE_SELECTION,
-					 "scsi%d : NO CONNECT with target %d, stat = %x \n",
-					 hostno, target, STATUS);
+				DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS);
 				return retcode (DID_NO_CONNECT);
 			}
 		}
 
-/* Establish current pointers.  Take into account scatter / gather */
+		/* Establish current pointers.  Take into account scatter / gather */
 
 		if ((nobuffs = SCint->use_sg)) {
 #if (DEBUG & DEBUG_SG)
 			{
 				int i;
-
-				printk
-				    ("scsi%d : scatter gather requested, using %d buffers.\n",
-				     hostno, nobuffs);
+				printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs);
 				for (i = 0; i < nobuffs; ++i)
-					printk
-					    ("scsi%d : buffer %d address = %p length = %d\n",
+					printk("scsi%d : buffer %d address = %p length = %d\n",
 					     hostno, i,
 					     page_address(buffer[i].page) + buffer[i].offset,
 					     buffer[i].length);
@@ -1069,11 +1011,9 @@
 
 			buffer = (struct scatterlist *) SCint->buffer;
 			len = buffer->length;
-			data = (unsigned char *) buffer->address;
+			data = page_address(buffer->page) + buffer->offset;
 		} else {
-			DPRINTK (DEBUG_SG,
-				 "scsi%d : scatter gather not requested.\n",
-				 hostno);
+			DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
 			buffer = NULL;
 			len = SCint->request_bufflen;
 			data = (unsigned char *) SCint->request_buffer;
@@ -1091,38 +1031,34 @@
 #endif
 	}			/* end of switch(reselect) */
 
-/*
- *    There are several conditions under which we wish to send a message :
- *      1.  When we are allowing disconnect / reconnect, and need to establish
- *          the I_T_L nexus via an IDENTIFY with the DiscPriv bit set.
- *
- *      2.  When we are doing linked commands, are have the wrong I_T_L nexus
- *          established and want to send an ABORT message.
- */
+	/*
+	 *    There are several conditions under which we wish to send a message :
+	 *      1.  When we are allowing disconnect / reconnect, and need to
+	 *	establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit
+	 *	set.
+	 *
+	 *      2.  When we are doing linked commands, are have the wrong I_T_L
+	 *	nexus established and want to send an ABORT message.
+	 */
 
-/* GCC does not like an ifdef inside a macro, so do it the hard way. */
+	/* GCC does not like an ifdef inside a macro, so do it the hard way. */
 #ifdef LINKED
-	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE |
-		       (((reselect == CAN_RECONNECT)
-			 || (reselect == LINKED_WRONG)
-			)? CMD_ATTN : 0));
+	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0));
 #else
-	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE |
-		       (((reselect == CAN_RECONNECT)
-			)? CMD_ATTN : 0));
+	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0));
 #endif
 
-/*
- *    INFORMATION TRANSFER PHASE
- *
- *      The nasty looking read / write inline assembler loops we use for
- *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
- *      the 'C' versions - since we're moving 1024 bytes of data, this
- *      really adds up.
- *
- *      SJT: The nasty-looking assembler is gone, so it's slower.
- *
- */
+	/*
+	 *    INFORMATION TRANSFER PHASE
+	 *
+	 *      The nasty looking read / write inline assembler loops we use for
+	 *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
+	 *      the 'C' versions - since we're moving 1024 bytes of data, this
+	 *      really adds up.
+	 *
+	 *      SJT: The nasty-looking assembler is gone, so it's slower.
+	 *
+	 */
 
 	DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno);
 
@@ -1130,72 +1066,63 @@
 	transfersize = SCint->transfersize;
 	underflow = SCint->underflow;
 
-/*
- *	Now, we poll the device for status information,
- *      and handle any requests it makes.  Note that since we are unsure of
- *      how much data will be flowing across the system, etc and cannot
- *      make reasonable timeouts, that we will instead have the midlevel
- *      driver handle any timeouts that occur in this phase.
- */
+	/*
+	 *	Now, we poll the device for status information,
+	 *      and handle any requests it makes.  Note that since we are unsure
+	 *	of how much data will be flowing across the system, etc and
+	 *	cannot make reasonable timeouts, that we will instead have the
+	 *	midlevel driver handle any timeouts that occur in this phase.
+	 */
 
 	while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) {
 #ifdef PARITY
 		if (status_read & STAT_PARITY) {
-			printk ("scsi%d : got parity error\n", hostno);
+			printk(KERN_ERR "scsi%d : got parity error\n", hostno);
 			st0x_aborted = DID_PARITY;
 		}
 #endif
-
 		if (status_read & STAT_REQ) {
 #if ((DEBUG & PHASE_ETC) == PHASE_ETC)
 			if ((newphase = (status_read & REQ_MASK)) != phase) {
 				phase = newphase;
 				switch (phase) {
 				case REQ_DATAOUT:
-					printk ("scsi%d : phase = DATA OUT\n",
-						hostno);
+					printk ("scsi%d : phase = DATA OUT\n", hostno);
 					break;
 				case REQ_DATAIN:
-					printk ("scsi%d : phase = DATA IN\n",
-						hostno);
+					printk ("scsi%d : phase = DATA IN\n", hostno);
 					break;
 				case REQ_CMDOUT:
 					printk
-					    ("scsi%d : phase = COMMAND OUT\n",
-					     hostno);
+					    ("scsi%d : phase = COMMAND OUT\n", hostno);
 					break;
 				case REQ_STATIN:
-					printk ("scsi%d : phase = STATUS IN\n",
-						hostno);
+					printk ("scsi%d : phase = STATUS IN\n",	hostno);
 					break;
 				case REQ_MSGOUT:
 					printk
-					    ("scsi%d : phase = MESSAGE OUT\n",
-					     hostno);
+					    ("scsi%d : phase = MESSAGE OUT\n", hostno);
 					break;
 				case REQ_MSGIN:
-					printk ("scsi%d : phase = MESSAGE IN\n",
-						hostno);
+					printk ("scsi%d : phase = MESSAGE IN\n", hostno);
 					break;
 				default:
-					printk ("scsi%d : phase = UNKNOWN\n",
-						hostno);
+					printk ("scsi%d : phase = UNKNOWN\n", hostno);
 					st0x_aborted = DID_ERROR;
 				}
 			}
 #endif
 			switch (status_read & REQ_MASK) {
 			case REQ_DATAOUT:
-/*
- * If we are in fast mode, then we simply splat the data out
- * in word-sized chunks as fast as we can.
- */
+				/*
+				 * If we are in fast mode, then we simply splat
+				 * the data out in word-sized chunks as fast as
+				 * we can.
+				 */
 
 				if (!len) {
 #if 0
-					printk
-					    ("scsi%d: underflow to target %d lun %d \n",
-					     hostno, target, lun);
+					printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun);
 					st0x_aborted = DID_ERROR;
 					fast = 0;
 #endif
@@ -1216,7 +1143,7 @@
 						 SCint->transfersize, len,
 						 data);
 
-/* SJT: Start. Fast Write */
+			/* SJT: Start. Fast Write */
 #ifdef SEAGATE_USE_ASM
 					__asm__ ("cld\n\t"
 #ifdef FAST32
@@ -1241,14 +1168,11 @@
 #else				/* SEAGATE_USE_ASM */
 					{
 #ifdef FAST32
-						unsigned int *iop =
-						    phys_to_virt (st0x_dr);
-						const unsigned int *dp =
-						    (unsigned int *) data;
+						unsigned int *iop = phys_to_virt (st0x_dr);
+						const unsigned int *dp =(unsigned int *) data;
 						int xferlen = transfersize >> 2;
 #else
-						unsigned char *iop =
-						    phys_to_virt (st0x_dr);
+						unsigned char *iop = phys_to_virt (st0x_dr);
 						const unsigned char *dp = data;
 						int xferlen = transfersize;
 #endif
@@ -1259,14 +1183,13 @@
 /* SJT: End */
 					len -= transfersize;
 					data += transfersize;
-					DPRINTK (DEBUG_FAST,
-						 "scsi%d : FAST transfer complete len = %d data = %08x\n",
-						 hostno, len, data);
+					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
 				} else {
-/*
- *    We loop as long as we are in a data out phase, there is data to send,
- *      and BSY is still active.
- */
+					/*
+					 *    We loop as long as we are in a 
+					 *    data out phase, there is data to
+					 *    send, and BSY is still active.
+					 */
 
 /* SJT: Start. Slow Write. */
 #ifdef SEAGATE_USE_ASM
@@ -1335,8 +1258,7 @@
 					--nobuffs;
 					++buffer;
 					len = buffer->length;
-					data =
-					    (unsigned char *) buffer->address;
+					data = page_address(buffer->page) + buffer->offset;
 					DPRINTK (DEBUG_SG,
 						 "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
 						 hostno, len, data);
@@ -1349,13 +1271,9 @@
 #if (DEBUG & (PHASE_DATAIN))
 					transfered += len;
 #endif
-					for (;
-					     len
-					     && (STATUS & (REQ_MASK | STAT_REQ))
-					     == (REQ_DATAIN | STAT_REQ);
-					     --len) {
+					for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) {
 						*data++ = DATA;
-						borken_wait ();
+						borken_wait();
 					}
 #if (DEBUG & (PHASE_DATAIN))
 					transfered -= len;
@@ -1421,19 +1339,15 @@
 					len -= transfersize;
 					data += transfersize;
 #if (DEBUG & PHASE_DATAIN)
-					printk ("scsi%d: transfered += %d\n",
-						hostno, transfersize);
+					printk ("scsi%d: transfered += %d\n", hostno, transfersize);
 					transfered += transfersize;
 #endif
 
-					DPRINTK (DEBUG_FAST,
-						 "scsi%d : FAST transfer complete len = %d data = %08x\n",
-						 hostno, len, data);
+					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
 				} else {
 
 #if (DEBUG & PHASE_DATAIN)
-					printk ("scsi%d: transfered += %d\n",
-						hostno, len);
+					printk ("scsi%d: transfered += %d\n", hostno, len);
 					transfered += len;	/* Assume we'll transfer it all, then
 								   subtract what we *didn't* transfer */
 #endif
@@ -1508,8 +1422,7 @@
 #endif				/* SEAGATE_USE_ASM */
 /* SJT: End. */
 #if (DEBUG & PHASE_DATAIN)
-					printk ("scsi%d: transfered -= %d\n",
-						hostno, len);
+					printk ("scsi%d: transfered -= %d\n", hostno, len);
 					transfered -= len;	/* Since we assumed all of Len got  *
 								   transfered, correct our mistake */
 #endif
@@ -1519,26 +1432,17 @@
 					--nobuffs;
 					++buffer;
 					len = buffer->length;
-					data =
-					    (unsigned char *) buffer->address;
-					DPRINTK (DEBUG_SG,
-						 "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
-						 hostno, len, data);
+					data = page_address(buffer->page) + buffer->offset;
+					DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
 				}
-
 				break;
 
 			case REQ_CMDOUT:
 				while (((status_read = STATUS) & STAT_BSY) &&
 				       ((status_read & REQ_MASK) == REQ_CMDOUT))
 					if (status_read & STAT_REQ) {
-						WRITE_DATA (*
-							    (const unsigned char
-							     *) cmnd);
-						cmnd =
-						    1 +
-						    (const unsigned char *)
-						    cmnd;
+						WRITE_DATA (*(const unsigned char *) cmnd);
+						cmnd = 1 + (const unsigned char *)cmnd;
 #ifdef SLOW_RATE
 						if (borken)
 							borken_wait ();
@@ -1551,23 +1455,21 @@
 				break;
 
 			case REQ_MSGOUT:
-/*
- *	We can only have sent a MSG OUT if we requested to do this
- *      by raising ATTN.  So, we must drop ATTN.
- */
-
+				/*
+				 *	We can only have sent a MSG OUT if we
+				 *	requested to do this by raising ATTN.
+				 *	So, we must drop ATTN.
+				 */
 				WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);
-/*
- *	If we are reconnecting, then we must send an IDENTIFY message in
- *      response  to MSGOUT.
- */
+				/*
+				 *	If we are reconnecting, then we must 
+				 *	send an IDENTIFY message in response
+				 *	to MSGOUT.
+				 */
 				switch (reselect) {
 				case CAN_RECONNECT:
 					WRITE_DATA (IDENTIFY (1, lun));
-
-					DPRINTK (PHASE_RESELECT | PHASE_MSGOUT,
-						 "scsi%d : sent IDENTIFY message.\n",
-						 hostno);
+					DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno);
 					break;
 #ifdef LINKED
 				case LINKED_WRONG:
@@ -1575,23 +1477,19 @@
 					linked_connected = 0;
 					reselect = CAN_RECONNECT;
 					goto connect_loop;
-					DPRINTK (PHASE_MSGOUT | DEBUG_LINKED,
-						 "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n",
-						 hostno);
-#endif				/* LINKED */
+					DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);
+#endif					/* LINKED */
 					DPRINTK (DEBUG_LINKED, "correct\n");
 				default:
 					WRITE_DATA (NOP);
-					printk
-					    ("scsi%d : target %d requested MSGOUT, sent NOP message.\n",
-					     hostno, target);
+					printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target);
 				}
 				break;
 
 			case REQ_MSGIN:
 				switch (message = DATA) {
 				case DISCONNECT:
-					DANY ("seagate: deciding to disconnect\n");
+					DANY("seagate: deciding to disconnect\n");
 					should_reconnect = 1;
 					current_data = data;	/* WDE add */
 					current_buffer = buffer;
@@ -1601,9 +1499,7 @@
 					linked_connected = 0;
 #endif
 					done = 1;
-					DPRINTK ((PHASE_RESELECT | PHASE_MSGIN),
-						 "scsi%d : disconnected.\n",
-						 hostno);
+					DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno);
 					break;
 
 #ifdef LINKED
@@ -1611,18 +1507,14 @@
 				case LINKED_FLG_CMD_COMPLETE:
 #endif
 				case COMMAND_COMPLETE:
-/*
- * Note : we should check for underflow here.
- */
-					DPRINTK (PHASE_MSGIN,
-						 "scsi%d : command complete.\n",
-						 hostno);
+					/*
+					 * Note : we should check for underflow here.
+					 */
+					DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno);
 					done = 1;
 					break;
 				case ABORT:
-					DPRINTK (PHASE_MSGIN,
-						 "scsi%d : abort message.\n",
-						 hostno);
+					DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno);
 					done = 1;
 					break;
 				case SAVE_POINTERS:
@@ -1630,9 +1522,7 @@
 					current_bufflen = len;	/* WDE add */
 					current_data = data;	/* WDE mod */
 					current_nobuffs = nobuffs;
-					DPRINTK (PHASE_MSGIN,
-						 "scsi%d : pointers saved.\n",
-						 hostno);
+					DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno);
 					break;
 				case RESTORE_POINTERS:
 					buffer = current_buffer;
@@ -1640,91 +1530,87 @@
 					data = current_data;	/* WDE mod */
 					len = current_bufflen;
 					nobuffs = current_nobuffs;
-					DPRINTK (PHASE_MSGIN,
-						 "scsi%d : pointers restored.\n",
-						 hostno);
+					DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno);
 					break;
 				default:
 
-/*
- *	IDENTIFY distinguishes itself from the other messages by setting the
- *      high byte. [FIXME: should not this read "the high bit"? - pavel@ucw.cz]
- *
- *      Note : we need to handle at least one outstanding command per LUN,
- *      and need to hash the SCSI command for that I_T_L nexus based on the
- *      known ID (at this point) and LUN.
- */
+					/*
+					 *	IDENTIFY distinguishes itself
+					 *	from the other messages by 
+					 *	setting the high bit.
+					 *
+					 *      Note : we need to handle at 
+					 *	least one outstanding command
+					 *	per LUN, and need to hash the 
+					 *	SCSI command for that I_T_L
+					 *	nexus based on the known ID 
+					 *	(at this point) and LUN.
+					 */
 
 					if (message & 0x80) {
-						DPRINTK (PHASE_MSGIN,
-							 "scsi%d : IDENTIFY message received from id %d, lun %d.\n",
-							 hostno, target,
-							 message & 7);
+						DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7);
 					} else {
-
-/*
- *      We should go into a MESSAGE OUT phase, and send  a MESSAGE_REJECT
- *      if we run into a message that we don't like.  The seagate driver
- *      needs some serious restructuring first though.
- */
-
-						DPRINTK (PHASE_MSGIN,
-							 "scsi%d : unknown message %d from target %d.\n",
-							 hostno, message,
-							 target);
+						/*
+						 *      We should go into a
+						 *	MESSAGE OUT phase, and
+						 *	send  a MESSAGE_REJECT
+						 *      if we run into a message 
+						 *	that we don't like.  The
+						 *	seagate driver needs 
+						 *	some serious 
+						 *	restructuring first
+						 *	though.
+						 */
+						DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target);
 					}
 				}
 				break;
-
 			default:
-				printk ("scsi%d : unknown phase.\n", hostno);
+				printk(KERN_ERR "scsi%d : unknown phase.\n", hostno);
 				st0x_aborted = DID_ERROR;
-			}	/* end of switch (status_read &
-				   REQ_MASK) */
-
+			}	/* end of switch (status_read &  REQ_MASK) */
 #ifdef SLOW_RATE
-/*
- * I really don't care to deal with borken devices in each single
- * byte transfer case (ie, message in, message out, status), so
- * I'll do the wait here if necessary.
- */
-			if (borken)
-				borken_wait ();
+			/*
+			 * I really don't care to deal with borken devices in
+			 * each single byte transfer case (ie, message in,
+			 * message out, status), so I'll do the wait here if 
+			 * necessary.
+			 */
+			if(borken)
+				borken_wait();
 #endif
 
 		}		/* if(status_read & STAT_REQ) ends */
-	}			/* while(((status_read = STATUS)...)
-				   ends */
+	}			/* while(((status_read = STATUS)...) ends */
 
-	DPRINTK (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT,
-		 "scsi%d : Transfered %d bytes\n", hostno, transfered);
+	DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);
 
 #if (DEBUG & PHASE_EXIT)
 #if 0				/* Doesn't work for scatter/gather */
-	printk ("Buffer : \n");
-	for (i = 0; i < 20; ++i)
-		printk ("%02x  ", ((unsigned char *) data)[i]);	/* WDE mod */
-	printk ("\n");
+	printk("Buffer : \n");
+	for(i = 0; i < 20; ++i)
+		printk("%02x  ", ((unsigned char *) data)[i]);	/* WDE mod */
+	printk("\n");
 #endif
-	printk ("scsi%d : status = ", hostno);
-	print_status (status);
-	printk (" message = %02x\n", message);
+	printk("scsi%d : status = ", hostno);
+	print_status(status);
+	printk(" message = %02x\n", message);
 #endif
 
-/* We shouldn't reach this until *after* BSY has been deasserted */
+	/* We shouldn't reach this until *after* BSY has been deasserted */
 
 #ifdef LINKED
 	else
 	{
-/*
- * Fix the message byte so that unsuspecting high level drivers don't
- * puke when they see a LINKED COMMAND message in place of the COMMAND
- * COMPLETE they may be expecting.  Shouldn't be necessary, but it's
- * better to be on the safe side.
- *
- * A non LINKED* message byte will indicate that the command completed,
- * and we are now disconnected.
- */
+		/*
+		 * Fix the message byte so that unsuspecting high level drivers
+		 * don't puke when they see a LINKED COMMAND message in place of
+		 * the COMMAND COMPLETE they may be expecting.  Shouldn't be
+		 * necessary, but it's better to be on the safe side.
+		 *
+		 * A non LINKED* message byte will indicate that the command
+		 * completed, and we are now disconnected.
+		 */
 
 		switch (message) {
 		case LINKED_CMD_COMPLETE:
@@ -1733,33 +1619,27 @@
 			linked_target = current_target;
 			linked_lun = current_lun;
 			linked_connected = 1;
-			DPRINTK (DEBUG_LINKED,
-				 "scsi%d : keeping I_T_L nexus established"
-				 "for linked command.\n", hostno);
+			DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno);
 			/* We also will need to adjust status to accommodate intermediate
 			   conditions. */
-			if ((status == INTERMEDIATE_GOOD) ||
-			    (status == INTERMEDIATE_C_GOOD))
+			if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD))
 				status = GOOD;
-
 			break;
-/*
- * We should also handle what are "normal" termination messages
- * here (ABORT, BUS_DEVICE_RESET?, and COMMAND_COMPLETE individually,
- * and flake if things aren't right.
- */
+			/*
+			 * We should also handle what are "normal" termination
+			 * messages here (ABORT, BUS_DEVICE_RESET?, and
+			 * COMMAND_COMPLETE individually, and flake if things
+			 * aren't right.
+			 */
 		default:
-			DPRINTK (DEBUG_LINKED,
-				 "scsi%d : closing I_T_L nexus.\n", hostno);
+			DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno);
 			linked_connected = 0;
 		}
 	}
-#endif				/* LINKED */
+#endif	/* LINKED */
 
 	if (should_reconnect) {
-		DPRINTK (PHASE_RESELECT,
-			 "scsi%d : exiting seagate_st0x_queue_command()"
-			 "with reconnect enabled.\n", hostno);
+		DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);
 		WRITE_CONTROL (BASE_CMD | CMD_INTR);
 	} else
 		WRITE_CONTROL (BASE_CMD);
@@ -1770,7 +1650,7 @@
 static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
 {
 	st0x_aborted = DID_ABORT;
-	return SCSI_ABORT_PENDING;
+	return SUCCESS;
 }
 
 #undef ULOOP
@@ -1778,14 +1658,16 @@
 
 /*
  * the seagate_st0x_reset function resets the SCSI bus 
+ *
+ * May be called with SCpnt = NULL
  */
 
-static int seagate_st0x_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+static int seagate_st0x_bus_reset(Scsi_Cmnd * SCpnt)
 {
-/* No timeouts - this command is going to fail because it was reset. */
+	/* No timeouts - this command is going to fail because it was reset. */
 	DANY ("scsi%d: Reseting bus... ", hostno);
 
-/* assert  RESET signal on SCSI bus.  */
+	/* assert  RESET signal on SCSI bus.  */
 	WRITE_CONTROL (BASE_CMD | CMD_RST);
 
 	udelay (20 * 1000);
@@ -1794,7 +1676,17 @@
 	st0x_aborted = DID_RESET;
 
 	DANY ("done.\n");
-	return SCSI_RESET_WAKEUP;
+	return SUCCESS;
+}
+
+static int seagate_st0x_host_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+static int seagate_st0x_device_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
 }
 
 /* Eventually this will go into an include file, but this will be later */
diff -Nru a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
--- a/drivers/scsi/seagate.h	Fri Oct 11 21:23:03 2002
+++ b/drivers/scsi/seagate.h	Fri Oct 11 21:23:03 2002
@@ -7,30 +7,30 @@
  */
 
 #ifndef _SEAGATE_H
-	#define SEAGATE_H
-/*
-	$Header
-*/
-#ifndef ASM
-int seagate_st0x_detect(Scsi_Host_Template *);
-int seagate_st0x_command(Scsi_Cmnd *);
-int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+#define SEAGATE_H
+
+static int seagate_st0x_detect(Scsi_Host_Template *);
+static int seagate_st0x_command(Scsi_Cmnd *);
+static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 
 static int seagate_st0x_abort(Scsi_Cmnd *);
-const char *seagate_st0x_info(struct Scsi_Host *);
-static int seagate_st0x_reset(Scsi_Cmnd *, unsigned int); 
+static const char *seagate_st0x_info(struct Scsi_Host *);
+static int seagate_st0x_bus_reset(Scsi_Cmnd *);
+static int seagate_st0x_device_reset(Scsi_Cmnd *);
+static int seagate_st0x_host_reset(Scsi_Cmnd *);
 
-#define SEAGATE_ST0X  {  detect:         seagate_st0x_detect,		\
-			 info:           seagate_st0x_info,		\
-			 command:        seagate_st0x_command,		\
-			 queuecommand:   seagate_st0x_queue_command,	\
-			 abort:          seagate_st0x_abort,		\
-			 reset:          seagate_st0x_reset,		\
-			 can_queue:      1,				\
-			 this_id:        7,				\
-			 sg_tablesize:   SG_ALL,			\
-			 cmd_per_lun:    1,				\
+#define SEAGATE_ST0X  {  detect:         seagate_st0x_detect,			\
+			 info:           seagate_st0x_info,			\
+			 command:        seagate_st0x_command,			\
+			 queuecommand:   seagate_st0x_queue_command,		\
+			 eh_abort_handler:	seagate_st0x_abort,		\
+			 eh_bus_reset_handler:  seagate_st0x_bus_reset,		\
+			 eh_host_reset_handler: seagate_st0x_host_reset,	\
+			 eh_device_reset_handler:seagate_st0x_device_reset,	\
+			 can_queue:      1,					\
+			 this_id:        7,					\
+			 sg_tablesize:   SG_ALL,				\
+			 cmd_per_lun:    1,					\
 			 use_clustering: DISABLE_CLUSTERING}
-#endif /* ASM */
 
 #endif /* _SEAGATE_H */
diff -Nru a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
--- a/drivers/scsi/sgiwd93.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/scsi/sgiwd93.c	Fri Oct 11 21:23:04 2002
@@ -287,7 +287,7 @@
 	sgiwd93_host->base = (unsigned long) hregs;
 	sgiwd93_host->irq = SGI_WD93_0_IRQ;
 
-	buf = (uchar *) get_free_page(GFP_KERNEL);
+	buf = (uchar *) get_zeroed_page(GFP_KERNEL);
 	if (!buf) {
 		printk(KERN_WARNING "sgiwd93: Could not allocate memory for host0 buffer.\n");
 		scsi_unregister(sgiwd93_host);
@@ -321,7 +321,7 @@
 			sgiwd93_host1->base = (unsigned long) hregs1;
 			sgiwd93_host1->irq = SGI_WD93_1_IRQ;
 	
-			buf = (uchar *) get_free_page(GFP_KERNEL);
+			buf = (uchar *) get_zeroed_page(GFP_KERNEL);
 			if (!buf) {
 				printk(KERN_WARNING "sgiwd93: Could not allocate memory for host1 buffer.\n");
 				scsi_unregister(sgiwd93_host1);
diff -Nru a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
--- a/drivers/scsi/sim710.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/scsi/sim710.c	Fri Oct 11 21:23:03 2002
@@ -18,6 +18,9 @@
  *----------------------------------------------------------------------------
  *
  * MCA card detection code by Trent McNair.
+ * Fixes to not explicitly nul bss data from Xavier Bestel.
+ * Some multiboard fixes from Rolf Eike Beer.
+ * Auto probing of EISA config space from Trevor Hemsley.
  *
  * Various bits of code in this driver have been copied from 53c7,8xx,c,
  * which is coyright Drew Eckhardt.  The scripts for the SCSI chip are
@@ -41,6 +44,16 @@
  * and insmod parameters similar to
  *	sim710="addr:0x9000 irq:15"
  *
+ * Multiple controllers can also be set up by command line, provided the
+ * addr: parameter is specified first for each controller.  e.g.
+ *      sim710="addr:0x9000 irq:15 addr:0x8000 irq:14"
+ *
+ * To seperate the different options, ' ', '+', and ',' can be used, except
+ * that ',' can not be used in module parameters.  ' ' can be a pain, because
+ * it needs to be quoted, which causes problems with some installers.
+ * The command line above is completely equivalent to
+ *      sim710="addr:0x9000+irq:15+addr:0x8000+irq:14"
+ *
  * The complete list of options are:
  *
  * addr:0x9000		Specifies the base I/O port (or address) of the 53C710.
@@ -49,12 +62,18 @@
  * ignore:0x0a		Makes the driver ignore SCSI IDs 0 and 2.
  * nodisc:0x70		Prevents disconnects from IDs 6, 5 and 4.
  * noneg:0x10		Prevents SDTR negotiation on ID 4.
+ * disabled:1		Completely disables the driver. When present, overrides
+ *			all other options.
+ *
+ * The driver will auto-probe chip addresses and IRQs now, so typically no
+ * parameters are needed.  Auto-probing of addresses is disabled if any addr:
+ * parameters are specified.
  *
  * Current limitations:
  *
  * o  Async only
  * o  Severely lacking in error recovery
- * o  Auto detection of IRQs and chip addresses only on MCA architectures
+ * o  'debug:' should be per host really.
  *
  */
 
@@ -71,27 +90,20 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/mca.h>
+#include <linux/interrupt.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17)
 #include <linux/spinlock.h>
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
-#include <asm/spinlock.h>
-#endif
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>
 #include <linux/blk.h>
 
-#ifdef CONFIG_TP34V_SCSI
-
-#include <asm/tp34vhw.h>
-#define MEM_MAPPED
-
-#elif defined(CONFIG_MCA)
-
+/* All targets are I/O mapped at the moment */
 #define IO_MAPPED
 
+#if defined(CONFIG_MCA)
+
 /*
  * For each known microchannel card using the 53c710 we need a list
  * of possible IRQ and IO settings, as well as their corresponding
@@ -116,12 +128,6 @@
 
 #define MCA_004F_IRQS { 5, 9, 14 }
 
-#else
-
-/* Assume an Intel platform */
-
-#define IO_MAPPED
-
 #endif
 
 #include "scsi.h"
@@ -151,7 +157,7 @@
 
 #ifdef DEBUG
 #define DEB(m,x) if (sim710_debug & m) x
-int sim710_debug = 0;
+int sim710_debug;
 #else
 #define DEB(m,x)
 #endif
@@ -178,7 +184,7 @@
 #define STATE_BUSY		3
 #define STATE_DISABLED		4
 
-#define MAXBOARDS 2	/* Increase this and the sizes of the
+#define MAXBOARDS 4	/* Increase this and the sizes of the
 			   arrays below, if you need more.. */
 
 #ifdef MODULE
@@ -193,44 +199,15 @@
 
 #endif
 
-static int sim710_errors = 0;	/* Count of error interrupts */
-static int sim710_intrs = 0;	/* Count of all interrupts */
-static int ignore_ids = 0;	/* Accept all SCSI IDs */
-static int opt_nodisc = 0;	/* Allow disconnect on all IDs */
-static int opt_noneg = 0;	/* Allow SDTR negotiation on all IDs */
-
-#ifdef CONFIG_TP34V_SCSI
-
-/* Special hardwired case for Tadpole TP34V at the moment, otherwise
- * boot parameters 'sim710=addr:0x8000,irq:15' (for example) must be given.
- */
-
-static int no_of_boards = 2;
-
-static unsigned int bases[MAXBOARDS] = {
-	TP34V_SCSI0_BASE, TP34V_SCSI1_BASE
-};
-static unsigned int irq_vectors[MAXBOARDS] = {
-	TP34V_SCSI0_VECTOR, TP34V_SCSI1_VECTOR
-};
-static unsigned int irq_index[MAXBOARDS] = {
-	TP34V_SCSI0_IRQ_INDEX, TP34V_SCSI1_IRQ_INDEX
-};
-
-#else
-
-/* All other cases use boot/module params, or auto-detect */
-
-static int no_of_boards = 0;
-
-static unsigned int bases[MAXBOARDS] = {
-	0
-};
-static unsigned int irq_vectors[MAXBOARDS] = {
-	0
-};
-
-#endif
+static int sim710_errors;		/* Count of error interrupts */
+static int sim710_intrs;		/* Count of all interrupts */
+static int ignore_ids[MAXBOARDS];	/* Accept all SCSI IDs */
+static int opt_nodisc[MAXBOARDS];	/* Allow disconnect on all IDs */
+static int opt_noneg[MAXBOARDS];	/* Allow SDTR negotiation on all IDs */
+static int hostdata_order;		/* Encoded size of hostdata for free_pages() */
+static int no_of_boards;		/* Actual number of boards/chips */
+static unsigned int bases[MAXBOARDS];	/* Base addresses of chips */
+static unsigned int irq_vectors[MAXBOARDS]; /* IRQ vectors used by chips */
 
 /* The SCSI Script!!! */
 
@@ -249,7 +226,6 @@
 
 #define MAX_SG		128	/* Scatter/Gather elements */
 
-
 #define MAX_MSGOUT	8
 #define MAX_MSGIN	8
 #define MAX_CMND	12
@@ -263,6 +239,9 @@
     u8 negotiate;
     u8 reselected_identify;
     u8 msgin_buf[MAX_MSGIN];
+    u8 msg_reject;
+    u32 test1_src __attribute__ ((aligned (4)));
+    u32 test1_dst;
 
     struct sim710_target {
 	Scsi_Cmnd *cur_cmd;
@@ -294,82 +273,127 @@
 
 
 /*
- * Function: int param_setup(char *str)
+ * Function : static void ncr_dump (struct Scsi_Host *host)
+ *
+ * Purpose :  Dump (possibly) useful info
+ *
+ * Inputs : host - pointer to this host adapter's structure
  */
 
-#ifdef MODULE
-#define ARG_SEP ' '
-#else
-#define ARG_SEP ','
-#endif
+static void
+ncr_dump (struct Scsi_Host *host)
+{
+    unsigned long flags;
+    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+       host->hostdata[0];
 
-static int
+    save_flags(flags);
+    cli();
+    printk("scsi%d: Chip register contents:\n", host->host_no);
+    printk(" (script at virt %p, bus %lx)\n",
+           hostdata->script, virt_to_bus(hostdata->script));
+    printk(" 00  sien:  %02x  sdid:  %02x  scntl1:%02x  scntl0:%02x\n"
+	   " 04  socl:  %02x  sodl:  %02x  sxfer: %02x  scid:  %02x\n"
+	   " 08  sbcl:  %02x  sbdl:  %02x  sidl:  %02x  sfbr:  %02x\n"
+	   " 0C  sstat2:%02x  sstat1:%02x  sstat0:%02x  dstat: %02x\n"
+	   " 10  dsa:   %08x\n"
+	   " 14  ctest3:%02x  ctest2:%02x  ctest1:%02x  ctest0:%02x\n"
+	   " 18  ctest7:%02x  ctest6:%02x  ctest5:%02x  ctest4:%02x\n"
+	   " 1C  temp:  %08x\n"
+	   " 20  lcrc:  %02x  ctest8:%02x  istat: %02x  dfifo: %02x\n"
+	   " 24  dbc:   %08x  dnad:  %08x  dsp:   %08x\n"
+	   " 30  dsps:  %08x  scratch:%08x\n"
+	   " 38  dcntl: %02x  dwt:   %02x  dien:  %02x  dmode: %02x\n"
+	   " 3C  adder: %08x\n",
+	  NCR_read8(SIEN_REG), NCR_read8(SDID_REG), NCR_read8(SCNTL1_REG),
+	  NCR_read8(SCNTL0_REG), NCR_read8(SOCL_REG), NCR_read8(SODL_REG),
+	  NCR_read8(SXFER_REG), NCR_read8(SCID_REG), NCR_read8(SBCL_REG),
+	  NCR_read8(SBDL_REG), NCR_read8(SIDL_REG), NCR_read8(SFBR_REG),
+	  NCR_read8(SSTAT2_REG), NCR_read8(SSTAT1_REG), NCR_read8(SSTAT0_REG),
+	  NCR_read8(DSTAT_REG), NCR_read32(DSA_REG), NCR_read8(CTEST3_REG),
+	  NCR_read8(CTEST2_REG), NCR_read8(CTEST1_REG), NCR_read8(CTEST0_REG),
+	  NCR_read8(CTEST7_REG), NCR_read8(CTEST6_REG), NCR_read8(CTEST5_REG),
+	  NCR_read8(CTEST4_REG), NCR_read8(TEMP_REG), NCR_read8(LCRC_REG),
+	  NCR_read8(CTEST8_REG), NCR_read8(ISTAT_REG), NCR_read8(DFIFO_REG),
+	  NCR_read32(DBC_REG), NCR_read32(DNAD_REG), NCR_read32(DSP_REG),
+	  NCR_read32(DSPS_REG), NCR_read32(SCRATCH_REG), NCR_read8(DCNTL_REG),
+	  NCR_read8(DWT_REG), NCR_read8(DIEN_REG), NCR_read8(DMODE_REG),
+	  NCR_read32(ADDER_REG));
+
+    restore_flags(flags);
+}
+
+
+/*
+ * Function: int param_setup(char *str)
+ */
+
+__init int
 param_setup(char *str)
 {
     char *cur = str;
-    char *pc, *pv;
+    char *p, *pc, *pv;
     int val;
-    int base;
     int c;
 
     no_of_boards = 0;
-    while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+    while (no_of_boards < MAXBOARDS && cur != NULL &&
+		(pc = strchr(cur, ':')) != NULL) {
 	char *pe;
 
 	val = 0;
 	pv = pc;
 	c = *++pv;
 
-	if (c == 'n')
-	    val = 0;
-	else if	(c == 'y')
-	    val = 1;
-	else {
-	    base = 0;
-	    val = (int) simple_strtoul(pv, &pe, base);
-	}
+	val = (int) simple_strtoul(pv, &pe, 0);
+
 	if (!strncmp(cur, "addr:", 5)) {
-	    bases[0] = val;
-	    no_of_boards = 1;
+	    bases[no_of_boards++] = val;
+	}
+#ifdef DEBUG
+	else if (!strncmp(cur, "debug:", 6)) {
+	    sim710_debug = val;
+	}
+#endif
+	else if (no_of_boards == 0) {
+	    printk("sim710: Invalid parameters, addr: must come first\n");
+	    no_of_boards = -1;
+	    return 1;
 	}
 	else if	(!strncmp(cur, "irq:", 4))
-	    irq_vectors[0] = val;
+	    irq_vectors[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "ignore:", 7))
-	    ignore_ids = val;
+	    ignore_ids[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "nodisc:", 7))
-	    opt_nodisc = val;
+	    opt_nodisc[no_of_boards-1] = val;
 	else if	(!strncmp(cur, "noneg:", 6))
-	    opt_noneg = val;
-	else if	(!strncmp(cur, "disabled:", 5)) {
+	    opt_noneg[no_of_boards-1] = val;
+	else if	(!strncmp(cur, "disabled:", 9)) {
 	    no_of_boards = -1;
 	    return 1;
 	}
-#ifdef DEBUG
-	else if (!strncmp(cur, "debug:", 6)) {
-	    sim710_debug = val;
+	else {
+	    printk("sim710: unexpected boot option '%.*s'\n", (int)(pc-cur+1), cur);
+	    no_of_boards = -1;
+	    return 1;
 	}
-#endif
-	else
-	    printk("sim710: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 
-	if ((cur = strchr(cur, ARG_SEP)) != NULL)
-	    ++cur;
+	/* Allow ',', ' ', or '+' seperators.  Used to be ',' at boot and
+	 * ' ' for module load, some installers crap out on the space and
+	 * insmod doesn't like the comma.
+	 */
+       if ((p = strchr(cur, ',')) || (p = strchr(cur, ' ')) ||
+               (p = strchr(cur, '+')))
+           cur = p + 1;
+        else
+           break;
     }
     return 1;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)
 #ifndef MODULE
 __setup("sim710=", param_setup);
 #endif
-#else
-/* Old boot param syntax support */
-void
-sim710_setup(char *str, int *ints)
-{
-    param_setup(str);
-}
-#endif
 
 
 /*
@@ -398,22 +422,6 @@
 
 
 /*
- * Function: static void disable (struct Scsi_Host *host)
- */
-
-static void
-disable (struct Scsi_Host *host)
-{
-    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
-	host->hostdata[0];
-
-    hostdata->state = STATE_DISABLED;
-    printk (KERN_ALERT "scsi%d : disabled.  Unload and reload\n",
-		            host->host_no);
-}
-
-
-/*
  * Function : static int ncr_halt (struct Scsi_Host *host)
  *
  * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
@@ -431,6 +439,8 @@
     struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
 	host->hostdata[0];
     int stage;
+    int timeout;
+    int res = 0;
 
     save_flags(flags);
     cli();
@@ -438,8 +448,10 @@
        Stage 1 : set ABORT
        Stage 2 : eat all but abort interrupts
        Stage 3 : eat all interrupts
+       We loop for 50000 times with a delay of 10us which should give us
+       about half a second.
      */
-    for (stage = 0;;) {
+    for (stage = 0, timeout = 50000; timeout; timeout--) {
 	if (stage == 1) {
 	    DEB(DEB_HALT, printk("ncr_halt: writing ISTAT_ABRT\n"));
 	    NCR_write8(ISTAT_REG, ISTAT_ABRT);
@@ -460,9 +472,8 @@
 		    NCR_write8(ISTAT_REG, 0);
 		    ++stage;
 		} else {
-		    printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
-			host->host_no);
-		    disable (host);
+		    res = 1;
+		    break;
 	    	}
     	    }
 	}
@@ -472,10 +483,18 @@
 	    else if (stage == 3)
 		break;
 	}
+	udelay(10);
     }
-    hostdata->state = STATE_HALTED;
     restore_flags(flags);
-    return 0;
+
+    if (timeout == 0 || res) {
+	printk(KERN_ALERT "scsi%d: could not halt NCR chip\n", host->host_no);
+	return 1;
+    }
+    else {
+	hostdata->state = STATE_HALTED;
+	return 0;
+    }
 }
 
 /*
@@ -494,16 +513,9 @@
 sim710_soft_reset (struct Scsi_Host *host)
 {
     unsigned long flags;
-#ifdef CONFIG_TP34V_SCSI
-    struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
-	host->hostdata[0];
-#endif
 
     save_flags(flags);
     cli();
-#ifdef CONFIG_TP34V_SCSI
-    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x80;
-#endif
     /*
      * Do a soft reset of the chip so that everything is
      * reinitialized to the power-on state.
@@ -528,6 +540,7 @@
 
     mdelay(1000);				/* Let devices recover */
 
+    NCR_write32(SCRATCH_REG, 0);
     NCR_write8(DCNTL_REG, DCNTL_10_COM | DCNTL_700_CF_3);
     NCR_write8(CTEST7_REG, CTEST7_10_CDIS|CTEST7_STD);
     NCR_write8(DMODE_REG, DMODE_10_BL_8 | DMODE_10_FC2);
@@ -544,11 +557,6 @@
     NCR_write8(SIEN_REG_700,
 	    SIEN_PAR | SIEN_700_STO | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_MA);
 
-
-#ifdef CONFIG_TP34V_SCSI
-    tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x30 | TP34V_SCSI0n1_IPL;
-#endif
-
     restore_flags(flags);
 }
 
@@ -577,6 +585,12 @@
     	isa_virt_to_bus((void *)&(hostdata->reselected_identify)));
     patch_abs_32 (hostdata->script, 0, msgin_buf, 
     	isa_virt_to_bus((void *)&(hostdata->msgin_buf[0])));
+    patch_abs_32 (hostdata->script, 0, msg_reject,
+	isa_virt_to_bus((void *)&(hostdata->msg_reject)));
+    patch_abs_32 (hostdata->script, 0, test1_src,
+	isa_virt_to_bus((void *)&(hostdata->test1_src)));
+    patch_abs_32 (hostdata->script, 0, test1_dst,
+	isa_virt_to_bus((void *)&(hostdata->test1_dst)));
     hostdata->state = STATE_INITIALISED;
     hostdata->negotiate = 0xff;
 }
@@ -587,7 +601,7 @@
  * spurious request from the target.  Don't really expect target initiated
  * SDTRs, because we always negotiate on the first command.  Could still
  * get them though..
- * The chip is currently paused with ACK asserted o the last byte of the
+ * The chip is currently paused with ACK asserted on the last byte of the
  * SDTR.
  * resa is the resume address if the message is in response to our outgoing
  * SDTR.  Only possible on initial identify.
@@ -739,6 +753,12 @@
 		host->host_no);
 	    resume_offset = Ent_resume_cmd;
 	}
+	else if (sbcl == SBCL_PHASE_STATIN) {
+	    /* Some devices do this on parity error, at least */
+	    printk("scsi%d: Unexpected switch to STATUSIN on initial message out\n",
+		host->host_no);
+	    resume_offset = Ent_end_data_trans;
+	}
 	else {
 	    printk("scsi%d: Unexpected phase change to %s on initial msgout\n",
 		host->host_no, sbcl_to_phase(sbcl));
@@ -801,6 +821,14 @@
 	    resume_offset = Ent_resume_pmm;
 	}
     }
+    else if (sbcl == SBCL_PHASE_STATIN) {
+	/* Change to Status In at some random point; probably wants to report a
+	 * parity error or similar.
+	 */
+	printk("scsi%d: Unexpected phase change to STATUSIN at index 0x%x\n",
+		host->host_no, index);
+	resume_offset = Ent_end_data_trans;
+    }
     else {
 	printk("scsi%d: Unexpected phase change to %s at index 0x%x\n",
 		host->host_no, sbcl_to_phase(sbcl), index);
@@ -868,12 +896,6 @@
 	printk("scsi%d: int_data_bad_phase, phase %s (%x)\n",
 		host->host_no, sbcl_to_phase(sbcl), sbcl);
 	break;
-    case A_int_bad_extmsg1a:
-    case A_int_bad_extmsg1b:
-    case A_int_bad_extmsg2a:
-    case A_int_bad_extmsg2b:
-    case A_int_bad_extmsg3a:
-    case A_int_bad_extmsg3b:
     case A_int_bad_msg1:
     case A_int_bad_msg2:
     case A_int_bad_msg3:
@@ -918,21 +940,22 @@
 static void
 sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-    unsigned int flags;
     struct Scsi_Host * host = (struct Scsi_Host *)dev_id;
     struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
     Scsi_Cmnd * cmd;
     unsigned char istat, dstat;
     unsigned char sstat0;
-    u32 dsps, resume_offset = 0;
+    u32 scratch, dsps, resume_offset = 0;
 
-    save_flags(flags);
-    cli();
-    sim710_intrs++;
-    while ((istat = NCR_read8(ISTAT_REG)) & (ISTAT_SIP|ISTAT_DIP)) {
+    istat = NCR_read8(ISTAT_REG);
+    if (!(istat & (ISTAT_SIP|ISTAT_DIP)))
+	return;
+    else {
+	sim710_intrs++;
 	dsps = NCR_read32(DSPS_REG);
 	hostdata->state = STATE_HALTED;
 	sstat0 = dstat = 0;
+	scratch = NCR_read32(SCRATCH_REG);
 	if (istat & ISTAT_SIP) {
 	    sstat0 = NCR_read8(SSTAT0_REG);
 	}
@@ -945,7 +968,13 @@
 		"dstat %02x, dsp [%04x], scratch %02x\n",
 	    host->host_no, sim710_intrs, istat, sstat0, dstat,
 	    (u32 *)(isa_bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,
-	    NCR_read32(SCRATCH_REG)));
+	    scratch));
+	if (scratch & 0x100) {
+	    u8 *p = hostdata->msgin_buf;
+	    
+	    DEB(DEB_INTS, printk("  msgin_buf: %02x %02x %02x %02x\n",
+			p[0], p[1], p[2], p[3]));
+	}
 	if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) {
 	    /* Reselected.  Identify the target from LCRC_REG, and
 	     * update current command.  If we were trying to select
@@ -1002,12 +1031,7 @@
 	    hostdata->target[cmd->target].cur_cmd = NULL;
 	    resume_offset = Ent_reselect;
 	}
-	else if (dstat & DSTAT_SIR)
-	    resume_offset = handle_script_int(host, cmd);
-	else if (sstat0 & SSTAT0_MA) {
-	    resume_offset = handle_phase_mismatch(host, cmd);
-	}
-	else if (sstat0 & (SSTAT0_MA|SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
+	else if (sstat0 & (SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
 	    printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no,
 			    sstat0);
 	    sim710_errors++;
@@ -1019,6 +1043,10 @@
 	    sim710_errors++;
 	    /* resume_offset is zero, which will cause a host reset */
 	}
+	else if (dstat & DSTAT_SIR)
+	    resume_offset = handle_script_int(host, cmd);
+	else if (sstat0 & SSTAT0_MA)
+	    resume_offset = handle_phase_mismatch(host, cmd);
 	else if (dstat & DSTAT_IID) {
 	    /* This can be due to a quick reselect while doing a WAIT
 	     * DISCONNECT.
@@ -1044,18 +1072,21 @@
 #ifdef DEBUG_LIMIT_INTS
 	if (sim710_intrs < DEBUG_LIMIT_INTS)
 #endif
-	NCR_write32(DSP_REG, isa_virt_to_bus(hostdata->script+resume_offset/4));
+	{
+	    NCR_write32(SCRATCH_REG, 0);
+	    NCR_write32(DSP_REG,
+		    isa_virt_to_bus(hostdata->script+resume_offset/4));
+	}
 	if (resume_offset == Ent_reselect)
 	    run_process_issue_queue(hostdata);
     }
     else {
 	printk("scsi%d: Failed to handle interrupt.  Failing commands "
 		"and resetting SCSI bus and chip\n", host->host_no);
-	mdelay(4000);		/* Give chance to read screen!! */
+	mdelay(1000);		/* Give chance to read screen!! */
 	full_reset(host);
     }
 
-    restore_flags(flags);
 }
 
 
@@ -1101,9 +1132,9 @@
     memcpy(targdata->dsa_cdb, cmd->cmnd, MAX_CMND);
 
     targdata->dsa_msgout[0] =
-		IDENTIFY((opt_nodisc & (1<<cmd->target)) ? 0 : 1 ,0);
+		IDENTIFY((opt_nodisc[hostdata->chip] & (1<<cmd->target)) ? 0 : 1 ,0);
     if (hostdata->negotiate & (1 << cmd->target)) {
-	if (opt_noneg & (1 << cmd->target)) {
+	if (opt_noneg[hostdata->chip] & (1 << cmd->target)) {
 	    hostdata->negotiate ^= (1 << cmd->target);
 	    targdata->dsa[DSA_MSGOUT] = 1;
 	}
@@ -1143,16 +1174,10 @@
 	u32 cnt = cmd->use_sg ? sgl->length : cmd->request_bufflen;
 
 	if (datain) {
-#ifdef CONFIG_TP34V_SCSI
-	    cache_clear(virt_to_phys(vbuf, cnt);
-#endif
 	    *dip++	= cnt;
 	    *dip++	= bbuf;
 	}
 	if (dataout) {
-#ifdef CONFIG_TP34V_SCSI
-	    cache_push(virt_to_phys(vbuf, cnt);
-#endif
 	    *dop++	= cnt;
 	    *dop++	= bbuf;
 	}
@@ -1288,7 +1313,7 @@
     save_flags(flags);
     cli();
 
-    if (ignore_ids & (1 << cmd->target)) {
+    if (ignore_ids[hostdata->chip] & (1 << cmd->target)) {
 	printk("scsi%d: ignoring target %d\n", host->host_no, cmd->target);
 	cmd->result = (DID_BAD_TARGET << 16);
 	done(cmd);
@@ -1320,18 +1345,25 @@
 }
 
 
-int
+__init int
 sim710_detect(Scsi_Host_Template * tpnt)
 {
-    unsigned char irq_vector;
     unsigned char scsi_id;
     unsigned int base_addr;
     struct Scsi_Host * host = NULL;
     struct sim710_hostdata *hostdata;
+    unsigned long timeout;
+    unsigned long irq_mask;
+    int requested_irq;
+    int probed_irq;
+    u32 dsps;
     int chips = 0;
+    int limit;
     int indx;
     int revision;
-    int order, size;
+    int size;
+    volatile u8 tmp;
+    struct Scsi_Host *our_hosts[MAXBOARDS+1];
 
 #ifdef MODULE
     if (sim710)
@@ -1433,83 +1465,191 @@
     }
 #endif
 
+#ifdef CONFIG_EISA
+    /* Auto probe, if no boards specified in boot parameters */
+    if (no_of_boards == 0) {
+	int io_addr;
+	/* reverse probe, so my on-board controller at 0x9000 is always scsi0 */
+	for (io_addr = 0x9000; no_of_boards < MAXBOARDS && io_addr >= 0x1000; io_addr -= 0x1000) {
+	    if (request_region(io_addr, 0x40, "sim710") != NULL) {
+		int id0 = inw(io_addr + 0xc80);
+		int id1 = inw(io_addr + 0xc82);
+		/* The on-board controller on my Proliant 2000 is 0x1044,
+		 * my EISA card is 0x1144.
+		 */
+		if (id0 == 0x110e && (id1 == 0x1044 || id1 == 0x1144)) {
+		    bases[no_of_boards] = io_addr;
+#if 0
+		    /* This should detect the IRQ, but I havn't proved it for
+		     * myself.  Leave the old probe code active for now, as
+		     * no-one has reported problems with it.
+		     */
+		    switch (inb(io_addr + 0xc88)) {
+			case (0x00):
+			    irq_vectors[no_of_boards] = 11;
+			    break;
+			case (0x01):
+			    irq_vectors[no_of_boards] = 14;
+			    break;
+			case (0x02):
+			    irq_vectors[no_of_boards] = 15;
+			    break;
+			case (0x03):
+			    irq_vectors[no_of_boards] = 10;
+			    break;
+			case (0x04):
+			    irq_vectors[no_of_boards] = 9;
+			    break;
+			default:
+			    printk("sim710.c: irq nasty\n");
+		    }
+#endif
+		    no_of_boards++;
+		}
+		release_region(io_addr, 64);
+	    }
+	}
+    }
+#endif
+      
     if (!no_of_boards) {
-       printk("sim710: No NCR53C710 adapter found.\n");
-       return 0;
+	printk("sim710: No NCR53C710 adapter found.\n");
+	return 0;
     }
 
     size = sizeof(struct sim710_hostdata);
-    order = 0;
-    while (size > (PAGE_SIZE << order))
-	order++;
-    size = PAGE_SIZE << order;
+    hostdata_order = 0;
+    while (size > (PAGE_SIZE << hostdata_order))
+	hostdata_order++;
+    size = PAGE_SIZE << hostdata_order;
 
     DEB(DEB_ANY, printk("sim710: hostdata %d bytes, size %d, order %d\n",
-	sizeof(struct sim710_hostdata), size, order));
+	sizeof(struct sim710_hostdata), size, hostdata_order));
 
     tpnt->proc_name = "sim710";
 
-    for(indx = 0; indx < no_of_boards; indx++) {
-        unsigned long page = __get_free_pages(GFP_ATOMIC, order);
+    memset(our_hosts, 0, sizeof(our_hosts));
+    for (indx = 0; indx < no_of_boards; indx++) {
+        unsigned long page = __get_free_pages(GFP_ATOMIC, hostdata_order);
         if(page == 0UL)
         {
-        	printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx);
-        	break;
+		printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx);
+		break;
         }
 	host = scsi_register(tpnt, 4);
-	if(host == NULL)
-		break;
+	if(host == NULL) {
+	    free_pages(host->hostdata[0], hostdata_order);
+	    break;
+	}
+	our_hosts[chips] = host;
 	host->hostdata[0] = page;
 	hostdata = (struct sim710_hostdata *)host->hostdata[0];
 	memset(hostdata, 0, size);
-#ifdef CONFIG_TP34V_SCSI
-	cache_push(virt_to_phys(hostdata), size);
-	cache_clear(virt_to_phys(hostdata), size);
-	kernel_set_cachemode((void *)hostdata,size,IOMAP_NOCACHE_SER);
-#endif
 	scsi_id = 7;
 	base_addr = bases[indx];
-	irq_vector = irq_vectors[indx];
-	printk("sim710: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
-	    		scsi_id, base_addr, irq_vector);
+	requested_irq = irq_vectors[indx];
+	printk("scsi%d: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
+			host->host_no, scsi_id, base_addr, requested_irq);
 	DEB(DEB_ANY, printk("sim710: hostdata = %p (%d bytes), dsa0 = %p\n",
 			hostdata, sizeof(struct sim710_hostdata),
 			 hostdata->target[0].dsa));
 	hostdata->chip = indx;
-	host->irq = irq_vector;
+	host->irq = requested_irq;
 	host->this_id = scsi_id;
 	host->unique_id = base_addr;
 	host->base = base_addr;
+	hostdata->msg_reject = MESSAGE_REJECT;
 
-	ncr_halt(host);
-
+	if (ncr_halt(host)) {
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    printk("scsi%d: Failed to initialise 53c710 at address %x\n",
+			host->host_no, base_addr);
+	    continue;
+	}
+	DEB(DEB_ANY,ncr_dump(host));
 	revision = (NCR_read8(CTEST8_REG) & 0xF0) >> 4;
 	printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
-
 	sim710_soft_reset(host);
 
 	sim710_driver_init(host);
 
-#ifdef CONFIG_TP34V_SCSI
-	if (request_irq(irq_vector,do_sim710_intr_handle, 0, "sim710", host))
-#else
-	if (request_irq(irq_vector,do_sim710_intr_handle, SA_INTERRUPT, "sim710", host))
-#endif
+	request_region((u32)host->base, 64, "sim710");
+	/* Now run test1 */
+	hostdata->test1_src = 0x53c710aa;
+	hostdata->test1_dst = 0x76543210;
+	NCR_write32(DSPS_REG, 0x89abcdef);
+	irq_mask = probe_irq_on();
+	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_test1/4));
+	timeout = 5;
+	while (hostdata->test1_dst != hostdata->test1_src && timeout--)
+	    mdelay(100);
+	tmp = NCR_read8(ISTAT_REG);
+	tmp = NCR_read8(SSTAT0_REG);
+	udelay(10);
+	tmp = NCR_read8(DSTAT_REG);
+	probed_irq = probe_irq_off(irq_mask);
+	if (requested_irq == 0) {
+	    if (probed_irq > 0) {
+		printk("scsi%d: Chip is using IRQ %d\n", host->host_no,
+			probed_irq);
+		requested_irq = host->irq = probed_irq;
+	    }
+	    else {
+		printk("scsi%d: Failed to probe for IRQ (returned %d)\n",
+			host->host_no, probed_irq);
+		ncr_halt(host);
+		free_pages(host->hostdata[0], hostdata_order);
+		scsi_unregister (host);
+		release_region((u32)host->base, 64);
+		continue;
+	    }
+	}
+	else if (probed_irq > 0 && probed_irq != requested_irq)
+	    printk("scsi%d: WARNING requested IRQ %d, but probed as %d\n",
+			host->host_no, requested_irq, probed_irq);
+	else if (probed_irq <= 0)
+	    printk("scsi%d: WARNING IRQ probe failed, (returned %d)\n",
+			host->host_no, probed_irq);
+	
+	dsps = NCR_read32(DSPS_REG);
+	if (hostdata->test1_dst != 0x53c710aa || dsps != A_int_test1) {
+	    if (hostdata->test1_dst != 0x53c710aa)
+		printk("scsi%d: test 1 FAILED: data: exp 0x53c710aa, got 0x%08x\n",
+			host->host_no, hostdata->test1_dst);
+	    if (dsps != A_int_test1)
+		printk("scsi%d: test 1 FAILED: dsps: exp 0x%08x, got 0x%08x\n",
+			host->host_no, A_int_test1, dsps);
+	    ncr_dump(host);
+	    ncr_halt(host);
+	    free_pages(host->hostdata[0], hostdata_order);
+	    scsi_unregister (host);
+	    release_region((u32)host->base, 64);
+	    continue;
+	}
+	printk("scsi%d: test 1 completed ok.\n", host->host_no);
+
+	NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4));
+	hostdata->state = STATE_IDLE;
+	chips++;
+    }
+    /* OK, now run down our_hosts[] calling request_irq(... SA_SHIRQ ...).
+     * Couldn't call request_irq earlier, as probing would have failed.
+     */
+    for (indx = 0, limit = chips; indx < limit; indx++) {
+	host = our_hosts[indx];
+	if (request_irq(host->irq, do_sim710_intr_handle,
+                       SA_INTERRUPT | SA_SHIRQ, "sim710", host))
 	{
 	    printk("scsi%d : IRQ%d not free, detaching\n",
-	    		host->host_no, host->irq);
-
+			host->host_no, host->irq);
+	    ncr_halt(host);
+	    free_pages(host->hostdata[0], hostdata_order);
 	    scsi_unregister (host);
+	    chips--;
 	}
-	else {
-#ifdef IO_MAPPED
-	    request_region((u32)host->base, 64, "sim710");
-#endif
-	    chips++;
-	}
-	NCR_write32(DSP_REG, isa_virt_to_bus(hostdata->script+Ent_reselect/4));
-	hostdata->state = STATE_IDLE;
     }
+
     return chips;
 }
 
@@ -1558,11 +1698,34 @@
     int target;
     Scsi_Cmnd *cmd;
 
-    ncr_halt(host);
-    printk("scsi%d: dsp = %08x (script[0x%04x]), scratch = %08x\n",
-	host->host_no, NCR_read32(DSP_REG),
-	((u32)isa_bus_to_virt(NCR_read32(DSP_REG)) - (u32)hostdata->script)/4,
-	NCR_read32(SCRATCH_REG));
+    u32 istat, dstat = 0, sstat0 = 0, sstat1 = 0, dsp, dsps, scratch;
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+
+    istat = NCR_read8(ISTAT_REG);
+    if (istat & ISTAT_SIP) {
+	sstat0 = NCR_read8(SSTAT0_REG);
+	sstat1 = NCR_read8(SSTAT1_REG);
+	udelay(10);
+    }
+    if (istat & ISTAT_DIP)
+	dstat = NCR_read8(DSTAT_REG);
+
+    if (ncr_halt(host)) {
+	restore_flags(flags);
+	return FAILED;
+    }
+    restore_flags(flags);
+    dsp = NCR_read32(DSP_REG);
+    dsps = NCR_read32(DSPS_REG);
+    scratch = NCR_read32(SCRATCH_REG);
+    printk("scsi%d: istat = %02x, sstat0 = %02x, sstat1 = %02x, dstat = %02x\n",
+		host->host_no, istat, sstat0, sstat1, dstat);
+    printk("scsi%d: dsp = %08x (script[0x%04x]), dsps = %08x, scratch = %08x\n",
+		host->host_no, dsp,
+		((u32)bus_to_virt(dsp) - (u32)hostdata->script)/4, dsps, scratch);
 
     for (target = 0; target < 7; target++) {
 	if ((cmd = hostdata->target[target].cur_cmd)) {
@@ -1604,10 +1767,10 @@
 int
 sim710_release(struct Scsi_Host *host)
 {
+    ncr_halt(host);
+    free_pages(host->hostdata[0], hostdata_order);
     free_irq(host->irq, host);
-#ifdef IO_MAPPED
     release_region((u32)host->base, 64);
-#endif
     return 1;
 }
 
diff -Nru a/drivers/scsi/sim710.h b/drivers/scsi/sim710.h
--- a/drivers/scsi/sim710.h	Fri Oct 11 21:22:58 2002
+++ b/drivers/scsi/sim710.h	Fri Oct 11 21:22:58 2002
@@ -23,8 +23,8 @@
 
 #include <scsi/scsicam.h>
 
-#define SIM710_SCSI { proc_name:		"sim710",	\
-		      name:			"Simple 53c710", 	\
+#define SIM710_SCSI { proc_name:		"sim710",		\
+		      name:			"53c710",	 	\
 		      detect:			sim710_detect,		\
 		      release:			sim710_release,		\
 		      queuecommand:		sim710_queuecommand,	\
@@ -413,7 +413,7 @@
 #define CTEST3_800_FM		0x02	/* Fetch mode pin */
 /* bit 0 is reserved on 800 series chips */
 
-#define CTEST4_REG_400		(0x18^bE)	/* Chip test 4 rw */
+#define CTEST4_REG_700		(0x18^bE)	/* Chip test 4 rw */
 #define CTEST4_REG_800		(0x21^bE)	/* Chip test 4 rw */
 /* 0x80 is reserved on 700 series chips */
 #define CTEST4_800_BDIS		0x80	/* Burst mode disable */
@@ -791,6 +791,20 @@
 
 #define ISTAT_REG	ISTAT_REG_700
 #define SCRATCH_REG	SCRATCHB_REG_10
+#define ADDER_REG	ADDER_REG_10
+#define SIEN_REG	SIEN_REG_700
+#define SDID_REG	SDID_REG_700
+#define CTEST0_REG	CTEST0_REG_700
+#define CTEST1_REG	CTEST1_REG_700
+#define CTEST2_REG	CTEST2_REG_700
+#define CTEST3_REG	CTEST3_REG_700
+#define CTEST4_REG	CTEST4_REG_700
+#define CTEST5_REG	CTEST5_REG_700
+#define CTEST6_REG	CTEST6_REG_700
+#define SODL_REG	SODL_REG_700
+#define SBDL_REG	SBDL_REG_700
+#define SIDL_REG	SIDL_REG_700
+#define LCRC_REG	LCRC_REG_10
 
 #ifdef MEM_MAPPED
 #define NCR_read8(address) 					\
diff -Nru a/drivers/scsi/sim710.scr b/drivers/scsi/sim710.scr
--- a/drivers/scsi/sim710.scr	Fri Oct 11 21:22:50 2002
+++ b/drivers/scsi/sim710.scr	Fri Oct 11 21:22:50 2002
@@ -15,15 +15,12 @@
 
 ABSOLUTE reselected_identify = 0
 ABSOLUTE msgin_buf = 0
+ABSOLUTE msg_reject = 0
+ABSOLUTE test1_src = 0
+ABSOLUTE test1_dst = 0
 
 /* Interrupt values passed back to driver */
 
-ABSOLUTE int_bad_extmsg1a	= 0xab930000
-ABSOLUTE int_bad_extmsg1b	= 0xab930001
-ABSOLUTE int_bad_extmsg2a	= 0xab930002
-ABSOLUTE int_bad_extmsg2b	= 0xab930003
-ABSOLUTE int_bad_extmsg3a	= 0xab930004
-ABSOLUTE int_bad_extmsg3b	= 0xab930005
 ABSOLUTE int_bad_msg1		= 0xab930006
 ABSOLUTE int_bad_msg2		= 0xab930007
 ABSOLUTE int_bad_msg3		= 0xab930008
@@ -47,9 +44,9 @@
 ABSOLUTE int_disc2		= 0xab93001a
 ABSOLUTE int_disc3		= 0xab93001b
 ABSOLUTE int_not_rej		= 0xab93001c
+ABSOLUTE int_test1		= 0xab93001d
 
-
-/* Bit field settings used to record status in SCRATCH */
+/* Bit field settings used to record status in SCRATCH0 */
 
 ABSOLUTE had_select	= 0x01
 ABSOLUTE had_msgout	= 0x02
@@ -60,6 +57,9 @@
 ABSOLUTE had_msgin	= 0x40
 ABSOLUTE had_extmsg	= 0x80
 
+/* Bit field settings used to record status in SCRATCH1 */
+
+ABSOLUTE did_reject	= 0x01
 
 /* These scripts are heavily based on the examples in the NCR 53C710
  * Programmer's Guide (Preliminary).
@@ -68,7 +68,6 @@
 ENTRY do_select
 do_select:
 	CLEAR TARGET
-	MOVE SCRATCH0 & 0 TO SCRATCH0
 	; Enable selection timer
 	MOVE CTEST7 & 0xef TO CTEST7
 	SELECT ATN FROM dsa_select, reselect
@@ -401,17 +400,23 @@
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 	CLEAR ACK
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
-	JUMP ext_msg1a, IF 0x03
-	INT int_bad_extmsg1a
-ext_msg1a:
+	JUMP reject_msg1, IF NOT 0x03	; Only handle SDTR
 	CLEAR ACK
 	MOVE 1, msgin_buf + 2, WHEN MSG_IN
-	JUMP ext_msg1b, IF 0x01		; Must be SDTR
-	INT int_bad_extmsg1b
-ext_msg1b:
+	JUMP reject_msg1, IF NOT 0x01	; Only handle SDTR
 	CLEAR ACK
 	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 	INT int_msg_sdtr1
+reject_msg1:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
+	SET ATN
+	CLEAR ACK
+	JUMP reject_msg1a, WHEN NOT MSG_IN
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+	JUMP reject_msg1
+reject_msg1a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+	JUMP redo_msgin1
 disc1:
 	CLEAR ACK
 ENTRY wait_disc1
@@ -446,17 +451,23 @@
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 	CLEAR ACK
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
-	JUMP ext_msg2a, IF 0x03
-	INT int_bad_extmsg2a
-ext_msg2a:
+	JUMP reject_msg2, IF NOT 0x03	; Only handle SDTR
 	CLEAR ACK
 	MOVE 1, msgin_buf + 2, WHEN MSG_IN
-	JUMP ext_msg2b, IF 0x01		; Must be SDTR
-	INT int_bad_extmsg2b
-ext_msg2b:
+	JUMP reject_msg2, IF NOT 0x01	; Only handle SDTR
 	CLEAR ACK
 	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 	INT int_msg_sdtr2
+reject_msg2:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
+	SET ATN
+	CLEAR ACK
+	JUMP reject_msg2a, WHEN NOT MSG_IN
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+	JUMP reject_msg2
+reject_msg2a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+	JUMP redo_msgin2
 disc2:
 	CLEAR ACK
 ENTRY wait_disc2
@@ -491,17 +502,23 @@
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 	CLEAR ACK
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
-	JUMP ext_msg3a, IF 0x03
-	INT int_bad_extmsg3a
-ext_msg3a:
+	JUMP reject_msg3, IF NOT 0x03	; Only handle SDTR
 	CLEAR ACK
 	MOVE 1, msgin_buf + 2, WHEN MSG_IN
-	JUMP ext_msg3b, IF 0x01		; Must be SDTR
-	INT int_bad_extmsg3b
-ext_msg3b:
+	JUMP reject_msg3, IF NOT 0x01	; Only handle  SDTR
 	CLEAR ACK
 	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 	INT int_msg_sdtr3
+reject_msg3:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
+	SET ATN
+	CLEAR ACK
+	JUMP reject_msg3a, WHEN NOT MSG_IN
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+	JUMP reject_msg3
+reject_msg3a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+	JUMP redo_msgin3
 disc3:
 	CLEAR ACK
 ENTRY wait_disc3
@@ -551,4 +568,9 @@
 
 selected:
 	INT int_selected
+
+ENTRY test1
+test1:
+	MOVE MEMORY 4, test1_src, test1_dst
+	INT int_test1
 
diff -Nru a/drivers/scsi/sim710_d.h_shipped b/drivers/scsi/sim710_d.h_shipped
--- a/drivers/scsi/sim710_d.h_shipped	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/sim710_d.h_shipped	Fri Oct 11 21:22:55 2002
@@ -18,15 +18,12 @@
 
 ABSOLUTE reselected_identify = 0
 ABSOLUTE msgin_buf = 0
+ABSOLUTE msg_reject = 0
+ABSOLUTE test1_src = 0
+ABSOLUTE test1_dst = 0
 
 
 
-ABSOLUTE int_bad_extmsg1a	= 0xab930000
-ABSOLUTE int_bad_extmsg1b	= 0xab930001
-ABSOLUTE int_bad_extmsg2a	= 0xab930002
-ABSOLUTE int_bad_extmsg2b	= 0xab930003
-ABSOLUTE int_bad_extmsg3a	= 0xab930004
-ABSOLUTE int_bad_extmsg3b	= 0xab930005
 ABSOLUTE int_bad_msg1		= 0xab930006
 ABSOLUTE int_bad_msg2		= 0xab930007
 ABSOLUTE int_bad_msg3		= 0xab930008
@@ -50,7 +47,7 @@
 ABSOLUTE int_disc2		= 0xab93001a
 ABSOLUTE int_disc3		= 0xab93001b
 ABSOLUTE int_not_rej		= 0xab93001c
-
+ABSOLUTE int_test1		= 0xab93001d
 
 
 
@@ -65,6 +62,9 @@
 
 
 
+ABSOLUTE did_reject	= 0x01
+
+
 
 
 
@@ -74,1641 +74,1709 @@
 
 at 0x00000000 : */	0x60000200,0x00000000,
 /*
-	MOVE SCRATCH0 & 0 TO SCRATCH0
-
-at 0x00000002 : */	0x7c340000,0x00000000,
-/*
 	; Enable selection timer
 	MOVE CTEST7 & 0xef TO CTEST7
 
-at 0x00000004 : */	0x7c1bef00,0x00000000,
+at 0x00000002 : */	0x7c1bef00,0x00000000,
 /*
 	SELECT ATN FROM dsa_select, reselect
 
-at 0x00000006 : */	0x43000000,0x00000c48,
+at 0x00000004 : */	0x43000000,0x00000cd0,
 /*
 	JUMP get_status, WHEN STATUS
 
-at 0x00000008 : */	0x830b0000,0x000000a0,
+at 0x00000006 : */	0x830b0000,0x00000098,
 /*
 	; Disable selection timer
 	MOVE CTEST7 | 0x10 TO CTEST7
 
-at 0x0000000a : */	0x7a1b1000,0x00000000,
+at 0x00000008 : */	0x7a1b1000,0x00000000,
 /*
 	MOVE SCRATCH0 | had_select TO SCRATCH0
 
-at 0x0000000c : */	0x7a340100,0x00000000,
+at 0x0000000a : */	0x7a340100,0x00000000,
 /*
 	INT int_sel_no_ident, IF NOT MSG_OUT
 
-at 0x0000000e : */	0x9e020000,0xab930013,
+at 0x0000000c : */	0x9e020000,0xab930013,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x00000010 : */	0x7a340200,0x00000000,
+at 0x0000000e : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x00000012 : */	0x1e000000,0x00000008,
+at 0x00000010 : */	0x1e000000,0x00000008,
 /*
 ENTRY done_ident
 done_ident:
 	JUMP get_status, IF STATUS
 
-at 0x00000014 : */	0x830a0000,0x000000a0,
+at 0x00000012 : */	0x830a0000,0x00000098,
 /*
 redo_msgin1:
 	JUMP get_msgin1, WHEN MSG_IN
 
-at 0x00000016 : */	0x870b0000,0x00000920,
+at 0x00000014 : */	0x870b0000,0x00000918,
 /*
 	INT int_sel_not_cmd, IF NOT CMD
 
-at 0x00000018 : */	0x9a020000,0xab930014,
+at 0x00000016 : */	0x9a020000,0xab930014,
 /*
 ENTRY resume_cmd
 resume_cmd:
 	MOVE SCRATCH0 | had_cmdout TO SCRATCH0
 
-at 0x0000001a : */	0x7a340400,0x00000000,
+at 0x00000018 : */	0x7a340400,0x00000000,
 /*
 	MOVE FROM dsa_cmnd, WHEN CMD
 
-at 0x0000001c : */	0x1a000000,0x00000010,
+at 0x0000001a : */	0x1a000000,0x00000010,
 /*
 ENTRY resume_pmm
 resume_pmm:
 redo_msgin2:
 	JUMP get_msgin2, WHEN MSG_IN
 
-at 0x0000001e : */	0x870b0000,0x00000a20,
+at 0x0000001c : */	0x870b0000,0x00000a48,
 /*
 	JUMP get_status, IF STATUS
 
-at 0x00000020 : */	0x830a0000,0x000000a0,
+at 0x0000001e : */	0x830a0000,0x00000098,
 /*
 	JUMP input_data, IF DATA_IN
 
-at 0x00000022 : */	0x810a0000,0x000000e0,
+at 0x00000020 : */	0x810a0000,0x000000d8,
 /*
 	JUMP output_data, IF DATA_OUT
 
-at 0x00000024 : */	0x800a0000,0x000004f8,
+at 0x00000022 : */	0x800a0000,0x000004f0,
 /*
 	INT int_cmd_bad_phase
 
-at 0x00000026 : */	0x98080000,0xab930009,
+at 0x00000024 : */	0x98080000,0xab930009,
 /*
 
 get_status:
 	; Disable selection timer
 	MOVE CTEST7 | 0x10 TO CTEST7
 
-at 0x00000028 : */	0x7a1b1000,0x00000000,
+at 0x00000026 : */	0x7a1b1000,0x00000000,
 /*
 	MOVE FROM dsa_status, WHEN STATUS
 
-at 0x0000002a : */	0x1b000000,0x00000018,
+at 0x00000028 : */	0x1b000000,0x00000018,
 /*
 	INT int_status_not_msgin, WHEN NOT MSG_IN
 
-at 0x0000002c : */	0x9f030000,0xab930015,
+at 0x0000002a : */	0x9f030000,0xab930015,
 /*
 	MOVE FROM dsa_msgin, WHEN MSG_IN
 
-at 0x0000002e : */	0x1f000000,0x00000020,
+at 0x0000002c : */	0x1f000000,0x00000020,
 /*
 	INT int_not_cmd_complete, IF NOT 0x00
 
-at 0x00000030 : */	0x98040000,0xab930012,
+at 0x0000002e : */	0x98040000,0xab930012,
 /*
 	CLEAR ACK
 
-at 0x00000032 : */	0x60000040,0x00000000,
+at 0x00000030 : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc_complete
 wait_disc_complete:
 	WAIT DISCONNECT
 
-at 0x00000034 : */	0x48000000,0x00000000,
+at 0x00000032 : */	0x48000000,0x00000000,
 /*
 	INT int_cmd_complete
 
-at 0x00000036 : */	0x98080000,0xab93000a,
+at 0x00000034 : */	0x98080000,0xab93000a,
 /*
 
 input_data:
 	MOVE SCRATCH0 | had_datain TO SCRATCH0
 
-at 0x00000038 : */	0x7a340800,0x00000000,
+at 0x00000036 : */	0x7a340800,0x00000000,
 /*
 ENTRY patch_input_data
 patch_input_data:
 	JUMP 0
 
-at 0x0000003a : */	0x80080000,0x00000000,
+at 0x00000038 : */	0x80080000,0x00000000,
 /*
 	MOVE FROM dsa_datain+0x0000, WHEN DATA_IN
 
-at 0x0000003c : */	0x19000000,0x00000028,
+at 0x0000003a : */	0x19000000,0x00000028,
 /*
 	MOVE FROM dsa_datain+0x0008, WHEN DATA_IN
 
-at 0x0000003e : */	0x19000000,0x00000030,
+at 0x0000003c : */	0x19000000,0x00000030,
 /*
 	MOVE FROM dsa_datain+0x0010, WHEN DATA_IN
 
-at 0x00000040 : */	0x19000000,0x00000038,
+at 0x0000003e : */	0x19000000,0x00000038,
 /*
 	MOVE FROM dsa_datain+0x0018, WHEN DATA_IN
 
-at 0x00000042 : */	0x19000000,0x00000040,
+at 0x00000040 : */	0x19000000,0x00000040,
 /*
 	MOVE FROM dsa_datain+0x0020, WHEN DATA_IN
 
-at 0x00000044 : */	0x19000000,0x00000048,
+at 0x00000042 : */	0x19000000,0x00000048,
 /*
 	MOVE FROM dsa_datain+0x0028, WHEN DATA_IN
 
-at 0x00000046 : */	0x19000000,0x00000050,
+at 0x00000044 : */	0x19000000,0x00000050,
 /*
 	MOVE FROM dsa_datain+0x0030, WHEN DATA_IN
 
-at 0x00000048 : */	0x19000000,0x00000058,
+at 0x00000046 : */	0x19000000,0x00000058,
 /*
 	MOVE FROM dsa_datain+0x0038, WHEN DATA_IN
 
-at 0x0000004a : */	0x19000000,0x00000060,
+at 0x00000048 : */	0x19000000,0x00000060,
 /*
 	MOVE FROM dsa_datain+0x0040, WHEN DATA_IN
 
-at 0x0000004c : */	0x19000000,0x00000068,
+at 0x0000004a : */	0x19000000,0x00000068,
 /*
 	MOVE FROM dsa_datain+0x0048, WHEN DATA_IN
 
-at 0x0000004e : */	0x19000000,0x00000070,
+at 0x0000004c : */	0x19000000,0x00000070,
 /*
 	MOVE FROM dsa_datain+0x0050, WHEN DATA_IN
 
-at 0x00000050 : */	0x19000000,0x00000078,
+at 0x0000004e : */	0x19000000,0x00000078,
 /*
 	MOVE FROM dsa_datain+0x0058, WHEN DATA_IN
 
-at 0x00000052 : */	0x19000000,0x00000080,
+at 0x00000050 : */	0x19000000,0x00000080,
 /*
 	MOVE FROM dsa_datain+0x0060, WHEN DATA_IN
 
-at 0x00000054 : */	0x19000000,0x00000088,
+at 0x00000052 : */	0x19000000,0x00000088,
 /*
 	MOVE FROM dsa_datain+0x0068, WHEN DATA_IN
 
-at 0x00000056 : */	0x19000000,0x00000090,
+at 0x00000054 : */	0x19000000,0x00000090,
 /*
 	MOVE FROM dsa_datain+0x0070, WHEN DATA_IN
 
-at 0x00000058 : */	0x19000000,0x00000098,
+at 0x00000056 : */	0x19000000,0x00000098,
 /*
 	MOVE FROM dsa_datain+0x0078, WHEN DATA_IN
 
-at 0x0000005a : */	0x19000000,0x000000a0,
+at 0x00000058 : */	0x19000000,0x000000a0,
 /*
 	MOVE FROM dsa_datain+0x0080, WHEN DATA_IN
 
-at 0x0000005c : */	0x19000000,0x000000a8,
+at 0x0000005a : */	0x19000000,0x000000a8,
 /*
 	MOVE FROM dsa_datain+0x0088, WHEN DATA_IN
 
-at 0x0000005e : */	0x19000000,0x000000b0,
+at 0x0000005c : */	0x19000000,0x000000b0,
 /*
 	MOVE FROM dsa_datain+0x0090, WHEN DATA_IN
 
-at 0x00000060 : */	0x19000000,0x000000b8,
+at 0x0000005e : */	0x19000000,0x000000b8,
 /*
 	MOVE FROM dsa_datain+0x0098, WHEN DATA_IN
 
-at 0x00000062 : */	0x19000000,0x000000c0,
+at 0x00000060 : */	0x19000000,0x000000c0,
 /*
 	MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN
 
-at 0x00000064 : */	0x19000000,0x000000c8,
+at 0x00000062 : */	0x19000000,0x000000c8,
 /*
 	MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN
 
-at 0x00000066 : */	0x19000000,0x000000d0,
+at 0x00000064 : */	0x19000000,0x000000d0,
 /*
 	MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN
 
-at 0x00000068 : */	0x19000000,0x000000d8,
+at 0x00000066 : */	0x19000000,0x000000d8,
 /*
 	MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN
 
-at 0x0000006a : */	0x19000000,0x000000e0,
+at 0x00000068 : */	0x19000000,0x000000e0,
 /*
 	MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN
 
-at 0x0000006c : */	0x19000000,0x000000e8,
+at 0x0000006a : */	0x19000000,0x000000e8,
 /*
 	MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN
 
-at 0x0000006e : */	0x19000000,0x000000f0,
+at 0x0000006c : */	0x19000000,0x000000f0,
 /*
 	MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN
 
-at 0x00000070 : */	0x19000000,0x000000f8,
+at 0x0000006e : */	0x19000000,0x000000f8,
 /*
 	MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN
 
-at 0x00000072 : */	0x19000000,0x00000100,
+at 0x00000070 : */	0x19000000,0x00000100,
 /*
 	MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN
 
-at 0x00000074 : */	0x19000000,0x00000108,
+at 0x00000072 : */	0x19000000,0x00000108,
 /*
 	MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN
 
-at 0x00000076 : */	0x19000000,0x00000110,
+at 0x00000074 : */	0x19000000,0x00000110,
 /*
 	MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN
 
-at 0x00000078 : */	0x19000000,0x00000118,
+at 0x00000076 : */	0x19000000,0x00000118,
 /*
 	MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN
 
-at 0x0000007a : */	0x19000000,0x00000120,
+at 0x00000078 : */	0x19000000,0x00000120,
 /*
 	MOVE FROM dsa_datain+0x0100, WHEN DATA_IN
 
-at 0x0000007c : */	0x19000000,0x00000128,
+at 0x0000007a : */	0x19000000,0x00000128,
 /*
 	MOVE FROM dsa_datain+0x0108, WHEN DATA_IN
 
-at 0x0000007e : */	0x19000000,0x00000130,
+at 0x0000007c : */	0x19000000,0x00000130,
 /*
 	MOVE FROM dsa_datain+0x0110, WHEN DATA_IN
 
-at 0x00000080 : */	0x19000000,0x00000138,
+at 0x0000007e : */	0x19000000,0x00000138,
 /*
 	MOVE FROM dsa_datain+0x0118, WHEN DATA_IN
 
-at 0x00000082 : */	0x19000000,0x00000140,
+at 0x00000080 : */	0x19000000,0x00000140,
 /*
 	MOVE FROM dsa_datain+0x0120, WHEN DATA_IN
 
-at 0x00000084 : */	0x19000000,0x00000148,
+at 0x00000082 : */	0x19000000,0x00000148,
 /*
 	MOVE FROM dsa_datain+0x0128, WHEN DATA_IN
 
-at 0x00000086 : */	0x19000000,0x00000150,
+at 0x00000084 : */	0x19000000,0x00000150,
 /*
 	MOVE FROM dsa_datain+0x0130, WHEN DATA_IN
 
-at 0x00000088 : */	0x19000000,0x00000158,
+at 0x00000086 : */	0x19000000,0x00000158,
 /*
 	MOVE FROM dsa_datain+0x0138, WHEN DATA_IN
 
-at 0x0000008a : */	0x19000000,0x00000160,
+at 0x00000088 : */	0x19000000,0x00000160,
 /*
 	MOVE FROM dsa_datain+0x0140, WHEN DATA_IN
 
-at 0x0000008c : */	0x19000000,0x00000168,
+at 0x0000008a : */	0x19000000,0x00000168,
 /*
 	MOVE FROM dsa_datain+0x0148, WHEN DATA_IN
 
-at 0x0000008e : */	0x19000000,0x00000170,
+at 0x0000008c : */	0x19000000,0x00000170,
 /*
 	MOVE FROM dsa_datain+0x0150, WHEN DATA_IN
 
-at 0x00000090 : */	0x19000000,0x00000178,
+at 0x0000008e : */	0x19000000,0x00000178,
 /*
 	MOVE FROM dsa_datain+0x0158, WHEN DATA_IN
 
-at 0x00000092 : */	0x19000000,0x00000180,
+at 0x00000090 : */	0x19000000,0x00000180,
 /*
 	MOVE FROM dsa_datain+0x0160, WHEN DATA_IN
 
-at 0x00000094 : */	0x19000000,0x00000188,
+at 0x00000092 : */	0x19000000,0x00000188,
 /*
 	MOVE FROM dsa_datain+0x0168, WHEN DATA_IN
 
-at 0x00000096 : */	0x19000000,0x00000190,
+at 0x00000094 : */	0x19000000,0x00000190,
 /*
 	MOVE FROM dsa_datain+0x0170, WHEN DATA_IN
 
-at 0x00000098 : */	0x19000000,0x00000198,
+at 0x00000096 : */	0x19000000,0x00000198,
 /*
 	MOVE FROM dsa_datain+0x0178, WHEN DATA_IN
 
-at 0x0000009a : */	0x19000000,0x000001a0,
+at 0x00000098 : */	0x19000000,0x000001a0,
 /*
 	MOVE FROM dsa_datain+0x0180, WHEN DATA_IN
 
-at 0x0000009c : */	0x19000000,0x000001a8,
+at 0x0000009a : */	0x19000000,0x000001a8,
 /*
 	MOVE FROM dsa_datain+0x0188, WHEN DATA_IN
 
-at 0x0000009e : */	0x19000000,0x000001b0,
+at 0x0000009c : */	0x19000000,0x000001b0,
 /*
 	MOVE FROM dsa_datain+0x0190, WHEN DATA_IN
 
-at 0x000000a0 : */	0x19000000,0x000001b8,
+at 0x0000009e : */	0x19000000,0x000001b8,
 /*
 	MOVE FROM dsa_datain+0x0198, WHEN DATA_IN
 
-at 0x000000a2 : */	0x19000000,0x000001c0,
+at 0x000000a0 : */	0x19000000,0x000001c0,
 /*
 	MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN
 
-at 0x000000a4 : */	0x19000000,0x000001c8,
+at 0x000000a2 : */	0x19000000,0x000001c8,
 /*
 	MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN
 
-at 0x000000a6 : */	0x19000000,0x000001d0,
+at 0x000000a4 : */	0x19000000,0x000001d0,
 /*
 	MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN
 
-at 0x000000a8 : */	0x19000000,0x000001d8,
+at 0x000000a6 : */	0x19000000,0x000001d8,
 /*
 	MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN
 
-at 0x000000aa : */	0x19000000,0x000001e0,
+at 0x000000a8 : */	0x19000000,0x000001e0,
 /*
 	MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN
 
-at 0x000000ac : */	0x19000000,0x000001e8,
+at 0x000000aa : */	0x19000000,0x000001e8,
 /*
 	MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN
 
-at 0x000000ae : */	0x19000000,0x000001f0,
+at 0x000000ac : */	0x19000000,0x000001f0,
 /*
 	MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN
 
-at 0x000000b0 : */	0x19000000,0x000001f8,
+at 0x000000ae : */	0x19000000,0x000001f8,
 /*
 	MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN
 
-at 0x000000b2 : */	0x19000000,0x00000200,
+at 0x000000b0 : */	0x19000000,0x00000200,
 /*
 	MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN
 
-at 0x000000b4 : */	0x19000000,0x00000208,
+at 0x000000b2 : */	0x19000000,0x00000208,
 /*
 	MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN
 
-at 0x000000b6 : */	0x19000000,0x00000210,
+at 0x000000b4 : */	0x19000000,0x00000210,
 /*
 	MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN
 
-at 0x000000b8 : */	0x19000000,0x00000218,
+at 0x000000b6 : */	0x19000000,0x00000218,
 /*
 	MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN
 
-at 0x000000ba : */	0x19000000,0x00000220,
+at 0x000000b8 : */	0x19000000,0x00000220,
 /*
 	MOVE FROM dsa_datain+0x0200, WHEN DATA_IN
 
-at 0x000000bc : */	0x19000000,0x00000228,
+at 0x000000ba : */	0x19000000,0x00000228,
 /*
 	MOVE FROM dsa_datain+0x0208, WHEN DATA_IN
 
-at 0x000000be : */	0x19000000,0x00000230,
+at 0x000000bc : */	0x19000000,0x00000230,
 /*
 	MOVE FROM dsa_datain+0x0210, WHEN DATA_IN
 
-at 0x000000c0 : */	0x19000000,0x00000238,
+at 0x000000be : */	0x19000000,0x00000238,
 /*
 	MOVE FROM dsa_datain+0x0218, WHEN DATA_IN
 
-at 0x000000c2 : */	0x19000000,0x00000240,
+at 0x000000c0 : */	0x19000000,0x00000240,
 /*
 	MOVE FROM dsa_datain+0x0220, WHEN DATA_IN
 
-at 0x000000c4 : */	0x19000000,0x00000248,
+at 0x000000c2 : */	0x19000000,0x00000248,
 /*
 	MOVE FROM dsa_datain+0x0228, WHEN DATA_IN
 
-at 0x000000c6 : */	0x19000000,0x00000250,
+at 0x000000c4 : */	0x19000000,0x00000250,
 /*
 	MOVE FROM dsa_datain+0x0230, WHEN DATA_IN
 
-at 0x000000c8 : */	0x19000000,0x00000258,
+at 0x000000c6 : */	0x19000000,0x00000258,
 /*
 	MOVE FROM dsa_datain+0x0238, WHEN DATA_IN
 
-at 0x000000ca : */	0x19000000,0x00000260,
+at 0x000000c8 : */	0x19000000,0x00000260,
 /*
 	MOVE FROM dsa_datain+0x0240, WHEN DATA_IN
 
-at 0x000000cc : */	0x19000000,0x00000268,
+at 0x000000ca : */	0x19000000,0x00000268,
 /*
 	MOVE FROM dsa_datain+0x0248, WHEN DATA_IN
 
-at 0x000000ce : */	0x19000000,0x00000270,
+at 0x000000cc : */	0x19000000,0x00000270,
 /*
 	MOVE FROM dsa_datain+0x0250, WHEN DATA_IN
 
-at 0x000000d0 : */	0x19000000,0x00000278,
+at 0x000000ce : */	0x19000000,0x00000278,
 /*
 	MOVE FROM dsa_datain+0x0258, WHEN DATA_IN
 
-at 0x000000d2 : */	0x19000000,0x00000280,
+at 0x000000d0 : */	0x19000000,0x00000280,
 /*
 	MOVE FROM dsa_datain+0x0260, WHEN DATA_IN
 
-at 0x000000d4 : */	0x19000000,0x00000288,
+at 0x000000d2 : */	0x19000000,0x00000288,
 /*
 	MOVE FROM dsa_datain+0x0268, WHEN DATA_IN
 
-at 0x000000d6 : */	0x19000000,0x00000290,
+at 0x000000d4 : */	0x19000000,0x00000290,
 /*
 	MOVE FROM dsa_datain+0x0270, WHEN DATA_IN
 
-at 0x000000d8 : */	0x19000000,0x00000298,
+at 0x000000d6 : */	0x19000000,0x00000298,
 /*
 	MOVE FROM dsa_datain+0x0278, WHEN DATA_IN
 
-at 0x000000da : */	0x19000000,0x000002a0,
+at 0x000000d8 : */	0x19000000,0x000002a0,
 /*
 	MOVE FROM dsa_datain+0x0280, WHEN DATA_IN
 
-at 0x000000dc : */	0x19000000,0x000002a8,
+at 0x000000da : */	0x19000000,0x000002a8,
 /*
 	MOVE FROM dsa_datain+0x0288, WHEN DATA_IN
 
-at 0x000000de : */	0x19000000,0x000002b0,
+at 0x000000dc : */	0x19000000,0x000002b0,
 /*
 	MOVE FROM dsa_datain+0x0290, WHEN DATA_IN
 
-at 0x000000e0 : */	0x19000000,0x000002b8,
+at 0x000000de : */	0x19000000,0x000002b8,
 /*
 	MOVE FROM dsa_datain+0x0298, WHEN DATA_IN
 
-at 0x000000e2 : */	0x19000000,0x000002c0,
+at 0x000000e0 : */	0x19000000,0x000002c0,
 /*
 	MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN
 
-at 0x000000e4 : */	0x19000000,0x000002c8,
+at 0x000000e2 : */	0x19000000,0x000002c8,
 /*
 	MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN
 
-at 0x000000e6 : */	0x19000000,0x000002d0,
+at 0x000000e4 : */	0x19000000,0x000002d0,
 /*
 	MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN
 
-at 0x000000e8 : */	0x19000000,0x000002d8,
+at 0x000000e6 : */	0x19000000,0x000002d8,
 /*
 	MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN
 
-at 0x000000ea : */	0x19000000,0x000002e0,
+at 0x000000e8 : */	0x19000000,0x000002e0,
 /*
 	MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN
 
-at 0x000000ec : */	0x19000000,0x000002e8,
+at 0x000000ea : */	0x19000000,0x000002e8,
 /*
 	MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN
 
-at 0x000000ee : */	0x19000000,0x000002f0,
+at 0x000000ec : */	0x19000000,0x000002f0,
 /*
 	MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN
 
-at 0x000000f0 : */	0x19000000,0x000002f8,
+at 0x000000ee : */	0x19000000,0x000002f8,
 /*
 	MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN
 
-at 0x000000f2 : */	0x19000000,0x00000300,
+at 0x000000f0 : */	0x19000000,0x00000300,
 /*
 	MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN
 
-at 0x000000f4 : */	0x19000000,0x00000308,
+at 0x000000f2 : */	0x19000000,0x00000308,
 /*
 	MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN
 
-at 0x000000f6 : */	0x19000000,0x00000310,
+at 0x000000f4 : */	0x19000000,0x00000310,
 /*
 	MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN
 
-at 0x000000f8 : */	0x19000000,0x00000318,
+at 0x000000f6 : */	0x19000000,0x00000318,
 /*
 	MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN
 
-at 0x000000fa : */	0x19000000,0x00000320,
+at 0x000000f8 : */	0x19000000,0x00000320,
 /*
 	MOVE FROM dsa_datain+0x0300, WHEN DATA_IN
 
-at 0x000000fc : */	0x19000000,0x00000328,
+at 0x000000fa : */	0x19000000,0x00000328,
 /*
 	MOVE FROM dsa_datain+0x0308, WHEN DATA_IN
 
-at 0x000000fe : */	0x19000000,0x00000330,
+at 0x000000fc : */	0x19000000,0x00000330,
 /*
 	MOVE FROM dsa_datain+0x0310, WHEN DATA_IN
 
-at 0x00000100 : */	0x19000000,0x00000338,
+at 0x000000fe : */	0x19000000,0x00000338,
 /*
 	MOVE FROM dsa_datain+0x0318, WHEN DATA_IN
 
-at 0x00000102 : */	0x19000000,0x00000340,
+at 0x00000100 : */	0x19000000,0x00000340,
 /*
 	MOVE FROM dsa_datain+0x0320, WHEN DATA_IN
 
-at 0x00000104 : */	0x19000000,0x00000348,
+at 0x00000102 : */	0x19000000,0x00000348,
 /*
 	MOVE FROM dsa_datain+0x0328, WHEN DATA_IN
 
-at 0x00000106 : */	0x19000000,0x00000350,
+at 0x00000104 : */	0x19000000,0x00000350,
 /*
 	MOVE FROM dsa_datain+0x0330, WHEN DATA_IN
 
-at 0x00000108 : */	0x19000000,0x00000358,
+at 0x00000106 : */	0x19000000,0x00000358,
 /*
 	MOVE FROM dsa_datain+0x0338, WHEN DATA_IN
 
-at 0x0000010a : */	0x19000000,0x00000360,
+at 0x00000108 : */	0x19000000,0x00000360,
 /*
 	MOVE FROM dsa_datain+0x0340, WHEN DATA_IN
 
-at 0x0000010c : */	0x19000000,0x00000368,
+at 0x0000010a : */	0x19000000,0x00000368,
 /*
 	MOVE FROM dsa_datain+0x0348, WHEN DATA_IN
 
-at 0x0000010e : */	0x19000000,0x00000370,
+at 0x0000010c : */	0x19000000,0x00000370,
 /*
 	MOVE FROM dsa_datain+0x0350, WHEN DATA_IN
 
-at 0x00000110 : */	0x19000000,0x00000378,
+at 0x0000010e : */	0x19000000,0x00000378,
 /*
 	MOVE FROM dsa_datain+0x0358, WHEN DATA_IN
 
-at 0x00000112 : */	0x19000000,0x00000380,
+at 0x00000110 : */	0x19000000,0x00000380,
 /*
 	MOVE FROM dsa_datain+0x0360, WHEN DATA_IN
 
-at 0x00000114 : */	0x19000000,0x00000388,
+at 0x00000112 : */	0x19000000,0x00000388,
 /*
 	MOVE FROM dsa_datain+0x0368, WHEN DATA_IN
 
-at 0x00000116 : */	0x19000000,0x00000390,
+at 0x00000114 : */	0x19000000,0x00000390,
 /*
 	MOVE FROM dsa_datain+0x0370, WHEN DATA_IN
 
-at 0x00000118 : */	0x19000000,0x00000398,
+at 0x00000116 : */	0x19000000,0x00000398,
 /*
 	MOVE FROM dsa_datain+0x0378, WHEN DATA_IN
 
-at 0x0000011a : */	0x19000000,0x000003a0,
+at 0x00000118 : */	0x19000000,0x000003a0,
 /*
 	MOVE FROM dsa_datain+0x0380, WHEN DATA_IN
 
-at 0x0000011c : */	0x19000000,0x000003a8,
+at 0x0000011a : */	0x19000000,0x000003a8,
 /*
 	MOVE FROM dsa_datain+0x0388, WHEN DATA_IN
 
-at 0x0000011e : */	0x19000000,0x000003b0,
+at 0x0000011c : */	0x19000000,0x000003b0,
 /*
 	MOVE FROM dsa_datain+0x0390, WHEN DATA_IN
 
-at 0x00000120 : */	0x19000000,0x000003b8,
+at 0x0000011e : */	0x19000000,0x000003b8,
 /*
 	MOVE FROM dsa_datain+0x0398, WHEN DATA_IN
 
-at 0x00000122 : */	0x19000000,0x000003c0,
+at 0x00000120 : */	0x19000000,0x000003c0,
 /*
 	MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN
 
-at 0x00000124 : */	0x19000000,0x000003c8,
+at 0x00000122 : */	0x19000000,0x000003c8,
 /*
 	MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN
 
-at 0x00000126 : */	0x19000000,0x000003d0,
+at 0x00000124 : */	0x19000000,0x000003d0,
 /*
 	MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN
 
-at 0x00000128 : */	0x19000000,0x000003d8,
+at 0x00000126 : */	0x19000000,0x000003d8,
 /*
 	MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN
 
-at 0x0000012a : */	0x19000000,0x000003e0,
+at 0x00000128 : */	0x19000000,0x000003e0,
 /*
 	MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN
 
-at 0x0000012c : */	0x19000000,0x000003e8,
+at 0x0000012a : */	0x19000000,0x000003e8,
 /*
 	MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN
 
-at 0x0000012e : */	0x19000000,0x000003f0,
+at 0x0000012c : */	0x19000000,0x000003f0,
 /*
 	MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN
 
-at 0x00000130 : */	0x19000000,0x000003f8,
+at 0x0000012e : */	0x19000000,0x000003f8,
 /*
 	MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN
 
-at 0x00000132 : */	0x19000000,0x00000400,
+at 0x00000130 : */	0x19000000,0x00000400,
 /*
 	MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN
 
-at 0x00000134 : */	0x19000000,0x00000408,
+at 0x00000132 : */	0x19000000,0x00000408,
 /*
 	MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN
 
-at 0x00000136 : */	0x19000000,0x00000410,
+at 0x00000134 : */	0x19000000,0x00000410,
 /*
 	MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN
 
-at 0x00000138 : */	0x19000000,0x00000418,
+at 0x00000136 : */	0x19000000,0x00000418,
 /*
 	MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN
 
-at 0x0000013a : */	0x19000000,0x00000420,
+at 0x00000138 : */	0x19000000,0x00000420,
 /*
 	JUMP end_data_trans
 
-at 0x0000013c : */	0x80080000,0x00000908,
+at 0x0000013a : */	0x80080000,0x00000900,
 /*
 
 output_data:
 	MOVE SCRATCH0 | had_dataout TO SCRATCH0
 
-at 0x0000013e : */	0x7a341000,0x00000000,
+at 0x0000013c : */	0x7a341000,0x00000000,
 /*
 ENTRY patch_output_data
 patch_output_data:
 	JUMP 0
 
-at 0x00000140 : */	0x80080000,0x00000000,
+at 0x0000013e : */	0x80080000,0x00000000,
 /*
 	MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT
 
-at 0x00000142 : */	0x18000000,0x00000428,
+at 0x00000140 : */	0x18000000,0x00000428,
 /*
 	MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT
 
-at 0x00000144 : */	0x18000000,0x00000430,
+at 0x00000142 : */	0x18000000,0x00000430,
 /*
 	MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT
 
-at 0x00000146 : */	0x18000000,0x00000438,
+at 0x00000144 : */	0x18000000,0x00000438,
 /*
 	MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT
 
-at 0x00000148 : */	0x18000000,0x00000440,
+at 0x00000146 : */	0x18000000,0x00000440,
 /*
 	MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT
 
-at 0x0000014a : */	0x18000000,0x00000448,
+at 0x00000148 : */	0x18000000,0x00000448,
 /*
 	MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT
 
-at 0x0000014c : */	0x18000000,0x00000450,
+at 0x0000014a : */	0x18000000,0x00000450,
 /*
 	MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT
 
-at 0x0000014e : */	0x18000000,0x00000458,
+at 0x0000014c : */	0x18000000,0x00000458,
 /*
 	MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT
 
-at 0x00000150 : */	0x18000000,0x00000460,
+at 0x0000014e : */	0x18000000,0x00000460,
 /*
 	MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT
 
-at 0x00000152 : */	0x18000000,0x00000468,
+at 0x00000150 : */	0x18000000,0x00000468,
 /*
 	MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT
 
-at 0x00000154 : */	0x18000000,0x00000470,
+at 0x00000152 : */	0x18000000,0x00000470,
 /*
 	MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT
 
-at 0x00000156 : */	0x18000000,0x00000478,
+at 0x00000154 : */	0x18000000,0x00000478,
 /*
 	MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT
 
-at 0x00000158 : */	0x18000000,0x00000480,
+at 0x00000156 : */	0x18000000,0x00000480,
 /*
 	MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT
 
-at 0x0000015a : */	0x18000000,0x00000488,
+at 0x00000158 : */	0x18000000,0x00000488,
 /*
 	MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT
 
-at 0x0000015c : */	0x18000000,0x00000490,
+at 0x0000015a : */	0x18000000,0x00000490,
 /*
 	MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT
 
-at 0x0000015e : */	0x18000000,0x00000498,
+at 0x0000015c : */	0x18000000,0x00000498,
 /*
 	MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT
 
-at 0x00000160 : */	0x18000000,0x000004a0,
+at 0x0000015e : */	0x18000000,0x000004a0,
 /*
 	MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT
 
-at 0x00000162 : */	0x18000000,0x000004a8,
+at 0x00000160 : */	0x18000000,0x000004a8,
 /*
 	MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT
 
-at 0x00000164 : */	0x18000000,0x000004b0,
+at 0x00000162 : */	0x18000000,0x000004b0,
 /*
 	MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT
 
-at 0x00000166 : */	0x18000000,0x000004b8,
+at 0x00000164 : */	0x18000000,0x000004b8,
 /*
 	MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT
 
-at 0x00000168 : */	0x18000000,0x000004c0,
+at 0x00000166 : */	0x18000000,0x000004c0,
 /*
 	MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT
 
-at 0x0000016a : */	0x18000000,0x000004c8,
+at 0x00000168 : */	0x18000000,0x000004c8,
 /*
 	MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT
 
-at 0x0000016c : */	0x18000000,0x000004d0,
+at 0x0000016a : */	0x18000000,0x000004d0,
 /*
 	MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT
 
-at 0x0000016e : */	0x18000000,0x000004d8,
+at 0x0000016c : */	0x18000000,0x000004d8,
 /*
 	MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT
 
-at 0x00000170 : */	0x18000000,0x000004e0,
+at 0x0000016e : */	0x18000000,0x000004e0,
 /*
 	MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT
 
-at 0x00000172 : */	0x18000000,0x000004e8,
+at 0x00000170 : */	0x18000000,0x000004e8,
 /*
 	MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT
 
-at 0x00000174 : */	0x18000000,0x000004f0,
+at 0x00000172 : */	0x18000000,0x000004f0,
 /*
 	MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT
 
-at 0x00000176 : */	0x18000000,0x000004f8,
+at 0x00000174 : */	0x18000000,0x000004f8,
 /*
 	MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT
 
-at 0x00000178 : */	0x18000000,0x00000500,
+at 0x00000176 : */	0x18000000,0x00000500,
 /*
 	MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT
 
-at 0x0000017a : */	0x18000000,0x00000508,
+at 0x00000178 : */	0x18000000,0x00000508,
 /*
 	MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT
 
-at 0x0000017c : */	0x18000000,0x00000510,
+at 0x0000017a : */	0x18000000,0x00000510,
 /*
 	MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT
 
-at 0x0000017e : */	0x18000000,0x00000518,
+at 0x0000017c : */	0x18000000,0x00000518,
 /*
 	MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT
 
-at 0x00000180 : */	0x18000000,0x00000520,
+at 0x0000017e : */	0x18000000,0x00000520,
 /*
 	MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT
 
-at 0x00000182 : */	0x18000000,0x00000528,
+at 0x00000180 : */	0x18000000,0x00000528,
 /*
 	MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT
 
-at 0x00000184 : */	0x18000000,0x00000530,
+at 0x00000182 : */	0x18000000,0x00000530,
 /*
 	MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT
 
-at 0x00000186 : */	0x18000000,0x00000538,
+at 0x00000184 : */	0x18000000,0x00000538,
 /*
 	MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT
 
-at 0x00000188 : */	0x18000000,0x00000540,
+at 0x00000186 : */	0x18000000,0x00000540,
 /*
 	MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT
 
-at 0x0000018a : */	0x18000000,0x00000548,
+at 0x00000188 : */	0x18000000,0x00000548,
 /*
 	MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT
 
-at 0x0000018c : */	0x18000000,0x00000550,
+at 0x0000018a : */	0x18000000,0x00000550,
 /*
 	MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT
 
-at 0x0000018e : */	0x18000000,0x00000558,
+at 0x0000018c : */	0x18000000,0x00000558,
 /*
 	MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT
 
-at 0x00000190 : */	0x18000000,0x00000560,
+at 0x0000018e : */	0x18000000,0x00000560,
 /*
 	MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT
 
-at 0x00000192 : */	0x18000000,0x00000568,
+at 0x00000190 : */	0x18000000,0x00000568,
 /*
 	MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT
 
-at 0x00000194 : */	0x18000000,0x00000570,
+at 0x00000192 : */	0x18000000,0x00000570,
 /*
 	MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT
 
-at 0x00000196 : */	0x18000000,0x00000578,
+at 0x00000194 : */	0x18000000,0x00000578,
 /*
 	MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT
 
-at 0x00000198 : */	0x18000000,0x00000580,
+at 0x00000196 : */	0x18000000,0x00000580,
 /*
 	MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT
 
-at 0x0000019a : */	0x18000000,0x00000588,
+at 0x00000198 : */	0x18000000,0x00000588,
 /*
 	MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT
 
-at 0x0000019c : */	0x18000000,0x00000590,
+at 0x0000019a : */	0x18000000,0x00000590,
 /*
 	MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT
 
-at 0x0000019e : */	0x18000000,0x00000598,
+at 0x0000019c : */	0x18000000,0x00000598,
 /*
 	MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT
 
-at 0x000001a0 : */	0x18000000,0x000005a0,
+at 0x0000019e : */	0x18000000,0x000005a0,
 /*
 	MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT
 
-at 0x000001a2 : */	0x18000000,0x000005a8,
+at 0x000001a0 : */	0x18000000,0x000005a8,
 /*
 	MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT
 
-at 0x000001a4 : */	0x18000000,0x000005b0,
+at 0x000001a2 : */	0x18000000,0x000005b0,
 /*
 	MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT
 
-at 0x000001a6 : */	0x18000000,0x000005b8,
+at 0x000001a4 : */	0x18000000,0x000005b8,
 /*
 	MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT
 
-at 0x000001a8 : */	0x18000000,0x000005c0,
+at 0x000001a6 : */	0x18000000,0x000005c0,
 /*
 	MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT
 
-at 0x000001aa : */	0x18000000,0x000005c8,
+at 0x000001a8 : */	0x18000000,0x000005c8,
 /*
 	MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT
 
-at 0x000001ac : */	0x18000000,0x000005d0,
+at 0x000001aa : */	0x18000000,0x000005d0,
 /*
 	MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT
 
-at 0x000001ae : */	0x18000000,0x000005d8,
+at 0x000001ac : */	0x18000000,0x000005d8,
 /*
 	MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT
 
-at 0x000001b0 : */	0x18000000,0x000005e0,
+at 0x000001ae : */	0x18000000,0x000005e0,
 /*
 	MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT
 
-at 0x000001b2 : */	0x18000000,0x000005e8,
+at 0x000001b0 : */	0x18000000,0x000005e8,
 /*
 	MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT
 
-at 0x000001b4 : */	0x18000000,0x000005f0,
+at 0x000001b2 : */	0x18000000,0x000005f0,
 /*
 	MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT
 
-at 0x000001b6 : */	0x18000000,0x000005f8,
+at 0x000001b4 : */	0x18000000,0x000005f8,
 /*
 	MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT
 
-at 0x000001b8 : */	0x18000000,0x00000600,
+at 0x000001b6 : */	0x18000000,0x00000600,
 /*
 	MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT
 
-at 0x000001ba : */	0x18000000,0x00000608,
+at 0x000001b8 : */	0x18000000,0x00000608,
 /*
 	MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT
 
-at 0x000001bc : */	0x18000000,0x00000610,
+at 0x000001ba : */	0x18000000,0x00000610,
 /*
 	MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT
 
-at 0x000001be : */	0x18000000,0x00000618,
+at 0x000001bc : */	0x18000000,0x00000618,
 /*
 	MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT
 
-at 0x000001c0 : */	0x18000000,0x00000620,
+at 0x000001be : */	0x18000000,0x00000620,
 /*
 	MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT
 
-at 0x000001c2 : */	0x18000000,0x00000628,
+at 0x000001c0 : */	0x18000000,0x00000628,
 /*
 	MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT
 
-at 0x000001c4 : */	0x18000000,0x00000630,
+at 0x000001c2 : */	0x18000000,0x00000630,
 /*
 	MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT
 
-at 0x000001c6 : */	0x18000000,0x00000638,
+at 0x000001c4 : */	0x18000000,0x00000638,
 /*
 	MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT
 
-at 0x000001c8 : */	0x18000000,0x00000640,
+at 0x000001c6 : */	0x18000000,0x00000640,
 /*
 	MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT
 
-at 0x000001ca : */	0x18000000,0x00000648,
+at 0x000001c8 : */	0x18000000,0x00000648,
 /*
 	MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT
 
-at 0x000001cc : */	0x18000000,0x00000650,
+at 0x000001ca : */	0x18000000,0x00000650,
 /*
 	MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT
 
-at 0x000001ce : */	0x18000000,0x00000658,
+at 0x000001cc : */	0x18000000,0x00000658,
 /*
 	MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT
 
-at 0x000001d0 : */	0x18000000,0x00000660,
+at 0x000001ce : */	0x18000000,0x00000660,
 /*
 	MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT
 
-at 0x000001d2 : */	0x18000000,0x00000668,
+at 0x000001d0 : */	0x18000000,0x00000668,
 /*
 	MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT
 
-at 0x000001d4 : */	0x18000000,0x00000670,
+at 0x000001d2 : */	0x18000000,0x00000670,
 /*
 	MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT
 
-at 0x000001d6 : */	0x18000000,0x00000678,
+at 0x000001d4 : */	0x18000000,0x00000678,
 /*
 	MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT
 
-at 0x000001d8 : */	0x18000000,0x00000680,
+at 0x000001d6 : */	0x18000000,0x00000680,
 /*
 	MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT
 
-at 0x000001da : */	0x18000000,0x00000688,
+at 0x000001d8 : */	0x18000000,0x00000688,
 /*
 	MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT
 
-at 0x000001dc : */	0x18000000,0x00000690,
+at 0x000001da : */	0x18000000,0x00000690,
 /*
 	MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT
 
-at 0x000001de : */	0x18000000,0x00000698,
+at 0x000001dc : */	0x18000000,0x00000698,
 /*
 	MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT
 
-at 0x000001e0 : */	0x18000000,0x000006a0,
+at 0x000001de : */	0x18000000,0x000006a0,
 /*
 	MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT
 
-at 0x000001e2 : */	0x18000000,0x000006a8,
+at 0x000001e0 : */	0x18000000,0x000006a8,
 /*
 	MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT
 
-at 0x000001e4 : */	0x18000000,0x000006b0,
+at 0x000001e2 : */	0x18000000,0x000006b0,
 /*
 	MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT
 
-at 0x000001e6 : */	0x18000000,0x000006b8,
+at 0x000001e4 : */	0x18000000,0x000006b8,
 /*
 	MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT
 
-at 0x000001e8 : */	0x18000000,0x000006c0,
+at 0x000001e6 : */	0x18000000,0x000006c0,
 /*
 	MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT
 
-at 0x000001ea : */	0x18000000,0x000006c8,
+at 0x000001e8 : */	0x18000000,0x000006c8,
 /*
 	MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT
 
-at 0x000001ec : */	0x18000000,0x000006d0,
+at 0x000001ea : */	0x18000000,0x000006d0,
 /*
 	MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT
 
-at 0x000001ee : */	0x18000000,0x000006d8,
+at 0x000001ec : */	0x18000000,0x000006d8,
 /*
 	MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT
 
-at 0x000001f0 : */	0x18000000,0x000006e0,
+at 0x000001ee : */	0x18000000,0x000006e0,
 /*
 	MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT
 
-at 0x000001f2 : */	0x18000000,0x000006e8,
+at 0x000001f0 : */	0x18000000,0x000006e8,
 /*
 	MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT
 
-at 0x000001f4 : */	0x18000000,0x000006f0,
+at 0x000001f2 : */	0x18000000,0x000006f0,
 /*
 	MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT
 
-at 0x000001f6 : */	0x18000000,0x000006f8,
+at 0x000001f4 : */	0x18000000,0x000006f8,
 /*
 	MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT
 
-at 0x000001f8 : */	0x18000000,0x00000700,
+at 0x000001f6 : */	0x18000000,0x00000700,
 /*
 	MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT
 
-at 0x000001fa : */	0x18000000,0x00000708,
+at 0x000001f8 : */	0x18000000,0x00000708,
 /*
 	MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT
 
-at 0x000001fc : */	0x18000000,0x00000710,
+at 0x000001fa : */	0x18000000,0x00000710,
 /*
 	MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT
 
-at 0x000001fe : */	0x18000000,0x00000718,
+at 0x000001fc : */	0x18000000,0x00000718,
 /*
 	MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT
 
-at 0x00000200 : */	0x18000000,0x00000720,
+at 0x000001fe : */	0x18000000,0x00000720,
 /*
 	MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT
 
-at 0x00000202 : */	0x18000000,0x00000728,
+at 0x00000200 : */	0x18000000,0x00000728,
 /*
 	MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT
 
-at 0x00000204 : */	0x18000000,0x00000730,
+at 0x00000202 : */	0x18000000,0x00000730,
 /*
 	MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT
 
-at 0x00000206 : */	0x18000000,0x00000738,
+at 0x00000204 : */	0x18000000,0x00000738,
 /*
 	MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT
 
-at 0x00000208 : */	0x18000000,0x00000740,
+at 0x00000206 : */	0x18000000,0x00000740,
 /*
 	MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT
 
-at 0x0000020a : */	0x18000000,0x00000748,
+at 0x00000208 : */	0x18000000,0x00000748,
 /*
 	MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT
 
-at 0x0000020c : */	0x18000000,0x00000750,
+at 0x0000020a : */	0x18000000,0x00000750,
 /*
 	MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT
 
-at 0x0000020e : */	0x18000000,0x00000758,
+at 0x0000020c : */	0x18000000,0x00000758,
 /*
 	MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT
 
-at 0x00000210 : */	0x18000000,0x00000760,
+at 0x0000020e : */	0x18000000,0x00000760,
 /*
 	MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT
 
-at 0x00000212 : */	0x18000000,0x00000768,
+at 0x00000210 : */	0x18000000,0x00000768,
 /*
 	MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT
 
-at 0x00000214 : */	0x18000000,0x00000770,
+at 0x00000212 : */	0x18000000,0x00000770,
 /*
 	MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT
 
-at 0x00000216 : */	0x18000000,0x00000778,
+at 0x00000214 : */	0x18000000,0x00000778,
 /*
 	MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT
 
-at 0x00000218 : */	0x18000000,0x00000780,
+at 0x00000216 : */	0x18000000,0x00000780,
 /*
 	MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT
 
-at 0x0000021a : */	0x18000000,0x00000788,
+at 0x00000218 : */	0x18000000,0x00000788,
 /*
 	MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT
 
-at 0x0000021c : */	0x18000000,0x00000790,
+at 0x0000021a : */	0x18000000,0x00000790,
 /*
 	MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT
 
-at 0x0000021e : */	0x18000000,0x00000798,
+at 0x0000021c : */	0x18000000,0x00000798,
 /*
 	MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT
 
-at 0x00000220 : */	0x18000000,0x000007a0,
+at 0x0000021e : */	0x18000000,0x000007a0,
 /*
 	MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT
 
-at 0x00000222 : */	0x18000000,0x000007a8,
+at 0x00000220 : */	0x18000000,0x000007a8,
 /*
 	MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT
 
-at 0x00000224 : */	0x18000000,0x000007b0,
+at 0x00000222 : */	0x18000000,0x000007b0,
 /*
 	MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT
 
-at 0x00000226 : */	0x18000000,0x000007b8,
+at 0x00000224 : */	0x18000000,0x000007b8,
 /*
 	MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT
 
-at 0x00000228 : */	0x18000000,0x000007c0,
+at 0x00000226 : */	0x18000000,0x000007c0,
 /*
 	MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT
 
-at 0x0000022a : */	0x18000000,0x000007c8,
+at 0x00000228 : */	0x18000000,0x000007c8,
 /*
 	MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT
 
-at 0x0000022c : */	0x18000000,0x000007d0,
+at 0x0000022a : */	0x18000000,0x000007d0,
 /*
 	MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT
 
-at 0x0000022e : */	0x18000000,0x000007d8,
+at 0x0000022c : */	0x18000000,0x000007d8,
 /*
 	MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT
 
-at 0x00000230 : */	0x18000000,0x000007e0,
+at 0x0000022e : */	0x18000000,0x000007e0,
 /*
 	MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT
 
-at 0x00000232 : */	0x18000000,0x000007e8,
+at 0x00000230 : */	0x18000000,0x000007e8,
 /*
 	MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT
 
-at 0x00000234 : */	0x18000000,0x000007f0,
+at 0x00000232 : */	0x18000000,0x000007f0,
 /*
 	MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT
 
-at 0x00000236 : */	0x18000000,0x000007f8,
+at 0x00000234 : */	0x18000000,0x000007f8,
 /*
 	MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT
 
-at 0x00000238 : */	0x18000000,0x00000800,
+at 0x00000236 : */	0x18000000,0x00000800,
 /*
 	MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT
 
-at 0x0000023a : */	0x18000000,0x00000808,
+at 0x00000238 : */	0x18000000,0x00000808,
 /*
 	MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT
 
-at 0x0000023c : */	0x18000000,0x00000810,
+at 0x0000023a : */	0x18000000,0x00000810,
 /*
 	MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT
 
-at 0x0000023e : */	0x18000000,0x00000818,
+at 0x0000023c : */	0x18000000,0x00000818,
 /*
 	MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT
 
-at 0x00000240 : */	0x18000000,0x00000820,
+at 0x0000023e : */	0x18000000,0x00000820,
 /*
 ENTRY end_data_trans
 end_data_trans:
 redo_msgin3:
 	JUMP get_status, WHEN STATUS
 
-at 0x00000242 : */	0x830b0000,0x000000a0,
+at 0x00000240 : */	0x830b0000,0x00000098,
 /*
 	JUMP get_msgin3, WHEN MSG_IN
 
-at 0x00000244 : */	0x870b0000,0x00000b20,
+at 0x00000242 : */	0x870b0000,0x00000b78,
 /*
 	INT int_data_bad_phase
 
-at 0x00000246 : */	0x98080000,0xab93000b,
+at 0x00000244 : */	0x98080000,0xab93000b,
 /*
 
 get_msgin1:
 	MOVE SCRATCH0 | had_msgin TO SCRATCH0
 
-at 0x00000248 : */	0x7a344000,0x00000000,
+at 0x00000246 : */	0x7a344000,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x0000024a : */	0x0f000001,0x00000000,
+at 0x00000248 : */	0x0f000001,0x00000000,
 /*
 	JUMP ext_msg1, IF 0x01		; Extended Message
 
-at 0x0000024c : */	0x800c0001,0x00000968,
+at 0x0000024a : */	0x800c0001,0x00000960,
 /*
 	JUMP ignore_msg1, IF 0x02	; Save Data Pointers
 
-at 0x0000024e : */	0x800c0002,0x00000958,
+at 0x0000024c : */	0x800c0002,0x00000950,
 /*
 	JUMP ignore_msg1, IF 0x03	; Save Restore Pointers
 
-at 0x00000250 : */	0x800c0003,0x00000958,
+at 0x0000024e : */	0x800c0003,0x00000950,
 /*
 	JUMP disc1, IF 0x04		; Disconnect
 
-at 0x00000252 : */	0x800c0004,0x000009c8,
+at 0x00000250 : */	0x800c0004,0x000009f0,
 /*
 	INT int_bad_msg1
 
-at 0x00000254 : */	0x98080000,0xab930006,
+at 0x00000252 : */	0x98080000,0xab930006,
 /*
 ignore_msg1:
 	CLEAR ACK
 
-at 0x00000256 : */	0x60000040,0x00000000,
+at 0x00000254 : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin1
 
-at 0x00000258 : */	0x80080000,0x00000058,
+at 0x00000256 : */	0x80080000,0x00000050,
 /*
 ext_msg1:
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 
-at 0x0000025a : */	0x7a348000,0x00000000,
+at 0x00000258 : */	0x7a348000,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x0000025c : */	0x60000040,0x00000000,
+at 0x0000025a : */	0x60000040,0x00000000,
 /*
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
 
-at 0x0000025e : */	0x0f000001,0x00000001,
+at 0x0000025c : */	0x0f000001,0x00000001,
 /*
-	JUMP ext_msg1a, IF 0x03
+	JUMP reject_msg1, IF NOT 0x03	; Only handle SDTR
 
-at 0x00000260 : */	0x800c0003,0x00000990,
+at 0x0000025e : */	0x80040003,0x000009b0,
 /*
-	INT int_bad_extmsg1a
+	CLEAR ACK
 
-at 0x00000262 : */	0x98080000,0xab930000,
+at 0x00000260 : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x00000262 : */	0x0f000001,0x00000002,
+/*
+	JUMP reject_msg1, IF NOT 0x01	; Only handle SDTR
+
+at 0x00000264 : */	0x80040001,0x000009b0,
 /*
-ext_msg1a:
 	CLEAR ACK
 
-at 0x00000264 : */	0x60000040,0x00000000,
+at 0x00000266 : */	0x60000040,0x00000000,
 /*
-	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 
-at 0x00000266 : */	0x0f000001,0x00000002,
+at 0x00000268 : */	0x0f000002,0x00000003,
 /*
-	JUMP ext_msg1b, IF 0x01		; Must be SDTR
+	INT int_msg_sdtr1
+
+at 0x0000026a : */	0x98080000,0xab93000c,
+/*
+reject_msg1:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
 
-at 0x00000268 : */	0x800c0001,0x000009b0,
+at 0x0000026c : */	0x7a350100,0x00000000,
 /*
-	INT int_bad_extmsg1b
+	SET ATN
 
-at 0x0000026a : */	0x98080000,0xab930001,
+at 0x0000026e : */	0x58000008,0x00000000,
 /*
-ext_msg1b:
 	CLEAR ACK
 
-at 0x0000026c : */	0x60000040,0x00000000,
+at 0x00000270 : */	0x60000040,0x00000000,
 /*
-	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	JUMP reject_msg1a, WHEN NOT MSG_IN
 
-at 0x0000026e : */	0x0f000002,0x00000003,
+at 0x00000272 : */	0x87030000,0x000009e0,
 /*
-	INT int_msg_sdtr1
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
 
-at 0x00000270 : */	0x98080000,0xab93000c,
+at 0x00000274 : */	0x0f000001,0x00000007,
+/*
+	JUMP reject_msg1
+
+at 0x00000276 : */	0x80080000,0x000009b0,
+/*
+reject_msg1a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+
+at 0x00000278 : */	0x0e000001,0x00000000,
+/*
+	JUMP redo_msgin1
+
+at 0x0000027a : */	0x80080000,0x00000050,
 /*
 disc1:
 	CLEAR ACK
 
-at 0x00000272 : */	0x60000040,0x00000000,
+at 0x0000027c : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc1
 wait_disc1:
 	WAIT DISCONNECT
 
-at 0x00000274 : */	0x48000000,0x00000000,
+at 0x0000027e : */	0x48000000,0x00000000,
 /*
 	INT int_disc1
 
-at 0x00000276 : */	0x98080000,0xab930019,
+at 0x00000280 : */	0x98080000,0xab930019,
 /*
 ENTRY resume_msgin1a
 resume_msgin1a:
 	CLEAR ACK
 
-at 0x00000278 : */	0x60000040,0x00000000,
+at 0x00000282 : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin1
 
-at 0x0000027a : */	0x80080000,0x00000058,
+at 0x00000284 : */	0x80080000,0x00000050,
 /*
 ENTRY resume_msgin1b
 resume_msgin1b:
 	SET ATN
 
-at 0x0000027c : */	0x58000008,0x00000000,
+at 0x00000286 : */	0x58000008,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x0000027e : */	0x60000040,0x00000000,
+at 0x00000288 : */	0x60000040,0x00000000,
 /*
 	INT int_no_msgout1, WHEN NOT MSG_OUT
 
-at 0x00000280 : */	0x9e030000,0xab93000f,
+at 0x0000028a : */	0x9e030000,0xab93000f,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x00000282 : */	0x7a340200,0x00000000,
+at 0x0000028c : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x00000284 : */	0x1e000000,0x00000008,
+at 0x0000028e : */	0x1e000000,0x00000008,
 /*
 	JUMP redo_msgin1
 
-at 0x00000286 : */	0x80080000,0x00000058,
+at 0x00000290 : */	0x80080000,0x00000050,
 /*
 
 get_msgin2:
 	MOVE SCRATCH0 | had_msgin TO SCRATCH0
 
-at 0x00000288 : */	0x7a344000,0x00000000,
+at 0x00000292 : */	0x7a344000,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x0000028a : */	0x0f000001,0x00000000,
+at 0x00000294 : */	0x0f000001,0x00000000,
 /*
 	JUMP ext_msg2, IF 0x01		; Extended Message
 
-at 0x0000028c : */	0x800c0001,0x00000a68,
+at 0x00000296 : */	0x800c0001,0x00000a90,
 /*
 	JUMP ignore_msg2, IF 0x02	; Save Data Pointers
 
-at 0x0000028e : */	0x800c0002,0x00000a58,
+at 0x00000298 : */	0x800c0002,0x00000a80,
 /*
 	JUMP ignore_msg2, IF 0x03	; Save Restore Pointers
 
-at 0x00000290 : */	0x800c0003,0x00000a58,
+at 0x0000029a : */	0x800c0003,0x00000a80,
 /*
 	JUMP disc2, IF 0x04		; Disconnect
 
-at 0x00000292 : */	0x800c0004,0x00000ac8,
+at 0x0000029c : */	0x800c0004,0x00000b20,
 /*
 	INT int_bad_msg2
 
-at 0x00000294 : */	0x98080000,0xab930007,
+at 0x0000029e : */	0x98080000,0xab930007,
 /*
 ignore_msg2:
 	CLEAR ACK
 
-at 0x00000296 : */	0x60000040,0x00000000,
+at 0x000002a0 : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin2
 
-at 0x00000298 : */	0x80080000,0x00000078,
+at 0x000002a2 : */	0x80080000,0x00000070,
 /*
 ext_msg2:
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 
-at 0x0000029a : */	0x7a348000,0x00000000,
+at 0x000002a4 : */	0x7a348000,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x0000029c : */	0x60000040,0x00000000,
+at 0x000002a6 : */	0x60000040,0x00000000,
 /*
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
 
-at 0x0000029e : */	0x0f000001,0x00000001,
+at 0x000002a8 : */	0x0f000001,0x00000001,
+/*
+	JUMP reject_msg2, IF NOT 0x03	; Only handle SDTR
+
+at 0x000002aa : */	0x80040003,0x00000ae0,
+/*
+	CLEAR ACK
+
+at 0x000002ac : */	0x60000040,0x00000000,
 /*
-	JUMP ext_msg2a, IF 0x03
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
 
-at 0x000002a0 : */	0x800c0003,0x00000a90,
+at 0x000002ae : */	0x0f000001,0x00000002,
 /*
-	INT int_bad_extmsg2a
+	JUMP reject_msg2, IF NOT 0x01	; Only handle SDTR
 
-at 0x000002a2 : */	0x98080000,0xab930002,
+at 0x000002b0 : */	0x80040001,0x00000ae0,
 /*
-ext_msg2a:
 	CLEAR ACK
 
-at 0x000002a4 : */	0x60000040,0x00000000,
+at 0x000002b2 : */	0x60000040,0x00000000,
 /*
-	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x000002b4 : */	0x0f000002,0x00000003,
+/*
+	INT int_msg_sdtr2
 
-at 0x000002a6 : */	0x0f000001,0x00000002,
+at 0x000002b6 : */	0x98080000,0xab93000d,
 /*
-	JUMP ext_msg2b, IF 0x01		; Must be SDTR
+reject_msg2:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
 
-at 0x000002a8 : */	0x800c0001,0x00000ab0,
+at 0x000002b8 : */	0x7a350100,0x00000000,
 /*
-	INT int_bad_extmsg2b
+	SET ATN
 
-at 0x000002aa : */	0x98080000,0xab930003,
+at 0x000002ba : */	0x58000008,0x00000000,
 /*
-ext_msg2b:
 	CLEAR ACK
 
-at 0x000002ac : */	0x60000040,0x00000000,
+at 0x000002bc : */	0x60000040,0x00000000,
 /*
-	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	JUMP reject_msg2a, WHEN NOT MSG_IN
 
-at 0x000002ae : */	0x0f000002,0x00000003,
+at 0x000002be : */	0x87030000,0x00000b10,
 /*
-	INT int_msg_sdtr2
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+
+at 0x000002c0 : */	0x0f000001,0x00000007,
+/*
+	JUMP reject_msg2
+
+at 0x000002c2 : */	0x80080000,0x00000ae0,
+/*
+reject_msg2a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+
+at 0x000002c4 : */	0x0e000001,0x00000000,
+/*
+	JUMP redo_msgin2
 
-at 0x000002b0 : */	0x98080000,0xab93000d,
+at 0x000002c6 : */	0x80080000,0x00000070,
 /*
 disc2:
 	CLEAR ACK
 
-at 0x000002b2 : */	0x60000040,0x00000000,
+at 0x000002c8 : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc2
 wait_disc2:
 	WAIT DISCONNECT
 
-at 0x000002b4 : */	0x48000000,0x00000000,
+at 0x000002ca : */	0x48000000,0x00000000,
 /*
 	INT int_disc2
 
-at 0x000002b6 : */	0x98080000,0xab93001a,
+at 0x000002cc : */	0x98080000,0xab93001a,
 /*
 ENTRY resume_msgin2a
 resume_msgin2a:
 	CLEAR ACK
 
-at 0x000002b8 : */	0x60000040,0x00000000,
+at 0x000002ce : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin2
 
-at 0x000002ba : */	0x80080000,0x00000078,
+at 0x000002d0 : */	0x80080000,0x00000070,
 /*
 ENTRY resume_msgin2b
 resume_msgin2b:
 	SET ATN
 
-at 0x000002bc : */	0x58000008,0x00000000,
+at 0x000002d2 : */	0x58000008,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x000002be : */	0x60000040,0x00000000,
+at 0x000002d4 : */	0x60000040,0x00000000,
 /*
 	INT int_no_msgout2, WHEN NOT MSG_OUT
 
-at 0x000002c0 : */	0x9e030000,0xab930010,
+at 0x000002d6 : */	0x9e030000,0xab930010,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x000002c2 : */	0x7a340200,0x00000000,
+at 0x000002d8 : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x000002c4 : */	0x1e000000,0x00000008,
+at 0x000002da : */	0x1e000000,0x00000008,
 /*
 	JUMP redo_msgin2
 
-at 0x000002c6 : */	0x80080000,0x00000078,
+at 0x000002dc : */	0x80080000,0x00000070,
 /*
 
 get_msgin3:
 	MOVE SCRATCH0 | had_msgin TO SCRATCH0
 
-at 0x000002c8 : */	0x7a344000,0x00000000,
+at 0x000002de : */	0x7a344000,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x000002ca : */	0x0f000001,0x00000000,
+at 0x000002e0 : */	0x0f000001,0x00000000,
 /*
 	JUMP ext_msg3, IF 0x01		; Extended Message
 
-at 0x000002cc : */	0x800c0001,0x00000b68,
+at 0x000002e2 : */	0x800c0001,0x00000bc0,
 /*
 	JUMP ignore_msg3, IF 0x02	; Save Data Pointers
 
-at 0x000002ce : */	0x800c0002,0x00000b58,
+at 0x000002e4 : */	0x800c0002,0x00000bb0,
 /*
 	JUMP ignore_msg3, IF 0x03	; Save Restore Pointers
 
-at 0x000002d0 : */	0x800c0003,0x00000b58,
+at 0x000002e6 : */	0x800c0003,0x00000bb0,
 /*
 	JUMP disc3, IF 0x04		; Disconnect
 
-at 0x000002d2 : */	0x800c0004,0x00000bc8,
+at 0x000002e8 : */	0x800c0004,0x00000c50,
 /*
 	INT int_bad_msg3
 
-at 0x000002d4 : */	0x98080000,0xab930008,
+at 0x000002ea : */	0x98080000,0xab930008,
 /*
 ignore_msg3:
 	CLEAR ACK
 
-at 0x000002d6 : */	0x60000040,0x00000000,
+at 0x000002ec : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin3
 
-at 0x000002d8 : */	0x80080000,0x00000908,
+at 0x000002ee : */	0x80080000,0x00000900,
 /*
 ext_msg3:
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 
-at 0x000002da : */	0x7a348000,0x00000000,
+at 0x000002f0 : */	0x7a348000,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x000002dc : */	0x60000040,0x00000000,
+at 0x000002f2 : */	0x60000040,0x00000000,
 /*
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
 
-at 0x000002de : */	0x0f000001,0x00000001,
+at 0x000002f4 : */	0x0f000001,0x00000001,
 /*
-	JUMP ext_msg3a, IF 0x03
+	JUMP reject_msg3, IF NOT 0x03	; Only handle SDTR
 
-at 0x000002e0 : */	0x800c0003,0x00000b90,
+at 0x000002f6 : */	0x80040003,0x00000c10,
 /*
-	INT int_bad_extmsg3a
+	CLEAR ACK
 
-at 0x000002e2 : */	0x98080000,0xab930004,
+at 0x000002f8 : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x000002fa : */	0x0f000001,0x00000002,
+/*
+	JUMP reject_msg3, IF NOT 0x01	; Only handle  SDTR
+
+at 0x000002fc : */	0x80040001,0x00000c10,
 /*
-ext_msg3a:
 	CLEAR ACK
 
-at 0x000002e4 : */	0x60000040,0x00000000,
+at 0x000002fe : */	0x60000040,0x00000000,
 /*
-	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x00000300 : */	0x0f000002,0x00000003,
+/*
+	INT int_msg_sdtr3
 
-at 0x000002e6 : */	0x0f000001,0x00000002,
+at 0x00000302 : */	0x98080000,0xab93000e,
 /*
-	JUMP ext_msg3b, IF 0x01		; Must be SDTR
+reject_msg3:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
 
-at 0x000002e8 : */	0x800c0001,0x00000bb0,
+at 0x00000304 : */	0x7a350100,0x00000000,
 /*
-	INT int_bad_extmsg3b
+	SET ATN
 
-at 0x000002ea : */	0x98080000,0xab930005,
+at 0x00000306 : */	0x58000008,0x00000000,
 /*
-ext_msg3b:
 	CLEAR ACK
 
-at 0x000002ec : */	0x60000040,0x00000000,
+at 0x00000308 : */	0x60000040,0x00000000,
 /*
-	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	JUMP reject_msg3a, WHEN NOT MSG_IN
 
-at 0x000002ee : */	0x0f000002,0x00000003,
+at 0x0000030a : */	0x87030000,0x00000c40,
 /*
-	INT int_msg_sdtr3
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+
+at 0x0000030c : */	0x0f000001,0x00000007,
+/*
+	JUMP reject_msg3
+
+at 0x0000030e : */	0x80080000,0x00000c10,
+/*
+reject_msg3a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
 
-at 0x000002f0 : */	0x98080000,0xab93000e,
+at 0x00000310 : */	0x0e000001,0x00000000,
+/*
+	JUMP redo_msgin3
+
+at 0x00000312 : */	0x80080000,0x00000900,
 /*
 disc3:
 	CLEAR ACK
 
-at 0x000002f2 : */	0x60000040,0x00000000,
+at 0x00000314 : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc3
 wait_disc3:
 	WAIT DISCONNECT
 
-at 0x000002f4 : */	0x48000000,0x00000000,
+at 0x00000316 : */	0x48000000,0x00000000,
 /*
 	INT int_disc3
 
-at 0x000002f6 : */	0x98080000,0xab93001b,
+at 0x00000318 : */	0x98080000,0xab93001b,
 /*
 ENTRY resume_msgin3a
 resume_msgin3a:
 	CLEAR ACK
 
-at 0x000002f8 : */	0x60000040,0x00000000,
+at 0x0000031a : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin3
 
-at 0x000002fa : */	0x80080000,0x00000908,
+at 0x0000031c : */	0x80080000,0x00000900,
 /*
 ENTRY resume_msgin3b
 resume_msgin3b:
 	SET ATN
 
-at 0x000002fc : */	0x58000008,0x00000000,
+at 0x0000031e : */	0x58000008,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x000002fe : */	0x60000040,0x00000000,
+at 0x00000320 : */	0x60000040,0x00000000,
 /*
 	INT int_no_msgout3, WHEN NOT MSG_OUT
 
-at 0x00000300 : */	0x9e030000,0xab930011,
+at 0x00000322 : */	0x9e030000,0xab930011,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x00000302 : */	0x7a340200,0x00000000,
+at 0x00000324 : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x00000304 : */	0x1e000000,0x00000008,
+at 0x00000326 : */	0x1e000000,0x00000008,
 /*
 	JUMP redo_msgin3
 
-at 0x00000306 : */	0x80080000,0x00000908,
+at 0x00000328 : */	0x80080000,0x00000900,
 /*
 
 ENTRY resume_rej_ident
 resume_rej_ident:
 	CLEAR ATN
 
-at 0x00000308 : */	0x60000008,0x00000000,
+at 0x0000032a : */	0x60000008,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x0000030a : */	0x0f000001,0x00000000,
+at 0x0000032c : */	0x0f000001,0x00000000,
 /*
 	INT int_not_rej, IF NOT 0x07		; Reject
 
-at 0x0000030c : */	0x98040007,0xab93001c,
+at 0x0000032e : */	0x98040007,0xab93001c,
 /*
 	CLEAR ACK
 
-at 0x0000030e : */	0x60000040,0x00000000,
+at 0x00000330 : */	0x60000040,0x00000000,
 /*
 	JUMP done_ident
 
-at 0x00000310 : */	0x80080000,0x00000050,
+at 0x00000332 : */	0x80080000,0x00000048,
 /*
 
 ENTRY reselect
@@ -1716,73 +1784,92 @@
 	; Disable selection timer
 	MOVE CTEST7 | 0x10 TO CTEST7
 
-at 0x00000312 : */	0x7a1b1000,0x00000000,
+at 0x00000334 : */	0x7a1b1000,0x00000000,
 /*
 	WAIT RESELECT resel_err
 
-at 0x00000314 : */	0x50000000,0x00000c70,
+at 0x00000336 : */	0x50000000,0x00000cf8,
 /*
 	INT int_resel_not_msgin, WHEN NOT MSG_IN
 
-at 0x00000316 : */	0x9f030000,0xab930016,
+at 0x00000338 : */	0x9f030000,0xab930016,
 /*
 	MOVE 1, reselected_identify, WHEN MSG_IN
 
-at 0x00000318 : */	0x0f000001,0x00000000,
+at 0x0000033a : */	0x0f000001,0x00000000,
 /*
 	INT int_reselected
 
-at 0x0000031a : */	0x98080000,0xab930017,
+at 0x0000033c : */	0x98080000,0xab930017,
 /*
 resel_err:
 	MOVE CTEST2 & 0x40 TO SFBR
 
-at 0x0000031c : */	0x74164000,0x00000000,
+at 0x0000033e : */	0x74164000,0x00000000,
 /*
 	JUMP selected, IF 0x00
 
-at 0x0000031e : */	0x800c0000,0x00000cb0,
+at 0x00000340 : */	0x800c0000,0x00000d38,
 /*
 	MOVE SFBR & 0 TO SFBR
 
-at 0x00000320 : */	0x7c080000,0x00000000,
+at 0x00000342 : */	0x7c080000,0x00000000,
 /*
 ENTRY patch_new_dsa
 patch_new_dsa:
 	MOVE SFBR | 0x11 TO DSA0
 
-at 0x00000322 : */	0x6a101100,0x00000000,
+at 0x00000344 : */	0x6a101100,0x00000000,
 /*
 	MOVE SFBR | 0x22 TO DSA1
 
-at 0x00000324 : */	0x6a112200,0x00000000,
+at 0x00000346 : */	0x6a112200,0x00000000,
 /*
 	MOVE SFBR | 0x33 TO DSA2
 
-at 0x00000326 : */	0x6a123300,0x00000000,
+at 0x00000348 : */	0x6a123300,0x00000000,
 /*
 	MOVE SFBR | 0x44 TO DSA3
 
-at 0x00000328 : */	0x6a134400,0x00000000,
+at 0x0000034a : */	0x6a134400,0x00000000,
 /*
 	JUMP do_select
 
-at 0x0000032a : */	0x80080000,0x00000000,
+at 0x0000034c : */	0x80080000,0x00000000,
 /*
 
 selected:
 	INT int_selected
 
-at 0x0000032c : */	0x98080000,0xab930018,
+at 0x0000034e : */	0x98080000,0xab930018,
+/*
+
+ENTRY test1
+test1:
+	MOVE MEMORY 4, test1_src, test1_dst
+
+at 0x00000350 : */	0xc0000004,0x00000000,0x00000000,
+/*
+	INT int_test1
+
+at 0x00000353 : */	0x98080000,0xab93001d,
+};
+
+#define A_did_reject	0x00000001
+static u32 A_did_reject_used[] __attribute((unused)) = {
+	0x0000026c,
+	0x000002b8,
+	0x00000304,
 };
 
 #define A_dsa_cmnd	0x00000010
 static u32 A_dsa_cmnd_used[] __attribute((unused)) = {
-	0x0000001d,
+	0x0000001b,
 };
 
 #define A_dsa_datain	0x00000028
 static u32 A_dsa_datain_used[] __attribute((unused)) = {
+	0x0000003b,
 	0x0000003d,
 	0x0000003f,
 	0x00000041,
@@ -1910,11 +1997,11 @@
 	0x00000135,
 	0x00000137,
 	0x00000139,
-	0x0000013b,
 };
 
 #define A_dsa_dataout	0x00000428
 static u32 A_dsa_dataout_used[] __attribute((unused)) = {
+	0x00000141,
 	0x00000143,
 	0x00000145,
 	0x00000147,
@@ -2042,25 +2129,24 @@
 	0x0000023b,
 	0x0000023d,
 	0x0000023f,
-	0x00000241,
 };
 
 #define A_dsa_msgin	0x00000020
 static u32 A_dsa_msgin_used[] __attribute((unused)) = {
-	0x0000002f,
+	0x0000002d,
 };
 
 #define A_dsa_msgout	0x00000008
 static u32 A_dsa_msgout_used[] __attribute((unused)) = {
-	0x00000013,
-	0x00000285,
-	0x000002c5,
-	0x00000305,
+	0x00000011,
+	0x0000028f,
+	0x000002db,
+	0x00000327,
 };
 
 #define A_dsa_select	0x00000000
 static u32 A_dsa_select_used[] __attribute((unused)) = {
-	0x00000006,
+	0x00000004,
 };
 
 #define A_dsa_size	0x00000828
@@ -2069,285 +2155,290 @@
 
 #define A_dsa_status	0x00000018
 static u32 A_dsa_status_used[] __attribute((unused)) = {
-	0x0000002b,
+	0x00000029,
 };
 
 #define A_had_cmdout	0x00000004
 static u32 A_had_cmdout_used[] __attribute((unused)) = {
-	0x0000001a,
+	0x00000018,
 };
 
 #define A_had_datain	0x00000008
 static u32 A_had_datain_used[] __attribute((unused)) = {
-	0x00000038,
+	0x00000036,
 };
 
 #define A_had_dataout	0x00000010
 static u32 A_had_dataout_used[] __attribute((unused)) = {
-	0x0000013e,
+	0x0000013c,
 };
 
 #define A_had_extmsg	0x00000080
 static u32 A_had_extmsg_used[] __attribute((unused)) = {
-	0x0000025a,
-	0x0000029a,
-	0x000002da,
+	0x00000258,
+	0x000002a4,
+	0x000002f0,
 };
 
 #define A_had_msgin	0x00000040
 static u32 A_had_msgin_used[] __attribute((unused)) = {
-	0x00000248,
-	0x00000288,
-	0x000002c8,
+	0x00000246,
+	0x00000292,
+	0x000002de,
 };
 
 #define A_had_msgout	0x00000002
 static u32 A_had_msgout_used[] __attribute((unused)) = {
-	0x00000010,
-	0x00000282,
-	0x000002c2,
-	0x00000302,
+	0x0000000e,
+	0x0000028c,
+	0x000002d8,
+	0x00000324,
 };
 
 #define A_had_select	0x00000001
 static u32 A_had_select_used[] __attribute((unused)) = {
-	0x0000000c,
+	0x0000000a,
 };
 
 #define A_had_status	0x00000020
 static u32 A_had_status_used[] __attribute((unused)) = {
 };
 
-#define A_int_bad_extmsg1a	0xab930000
-static u32 A_int_bad_extmsg1a_used[] __attribute((unused)) = {
-	0x00000263,
-};
-
-#define A_int_bad_extmsg1b	0xab930001
-static u32 A_int_bad_extmsg1b_used[] __attribute((unused)) = {
-	0x0000026b,
-};
-
-#define A_int_bad_extmsg2a	0xab930002
-static u32 A_int_bad_extmsg2a_used[] __attribute((unused)) = {
-	0x000002a3,
-};
-
-#define A_int_bad_extmsg2b	0xab930003
-static u32 A_int_bad_extmsg2b_used[] __attribute((unused)) = {
-	0x000002ab,
-};
-
-#define A_int_bad_extmsg3a	0xab930004
-static u32 A_int_bad_extmsg3a_used[] __attribute((unused)) = {
-	0x000002e3,
-};
-
-#define A_int_bad_extmsg3b	0xab930005
-static u32 A_int_bad_extmsg3b_used[] __attribute((unused)) = {
-	0x000002eb,
-};
-
 #define A_int_bad_msg1	0xab930006
 static u32 A_int_bad_msg1_used[] __attribute((unused)) = {
-	0x00000255,
+	0x00000253,
 };
 
 #define A_int_bad_msg2	0xab930007
 static u32 A_int_bad_msg2_used[] __attribute((unused)) = {
-	0x00000295,
+	0x0000029f,
 };
 
 #define A_int_bad_msg3	0xab930008
 static u32 A_int_bad_msg3_used[] __attribute((unused)) = {
-	0x000002d5,
+	0x000002eb,
 };
 
 #define A_int_cmd_bad_phase	0xab930009
 static u32 A_int_cmd_bad_phase_used[] __attribute((unused)) = {
-	0x00000027,
+	0x00000025,
 };
 
 #define A_int_cmd_complete	0xab93000a
 static u32 A_int_cmd_complete_used[] __attribute((unused)) = {
-	0x00000037,
+	0x00000035,
 };
 
 #define A_int_data_bad_phase	0xab93000b
 static u32 A_int_data_bad_phase_used[] __attribute((unused)) = {
-	0x00000247,
+	0x00000245,
 };
 
 #define A_int_disc1	0xab930019
 static u32 A_int_disc1_used[] __attribute((unused)) = {
-	0x00000277,
+	0x00000281,
 };
 
 #define A_int_disc2	0xab93001a
 static u32 A_int_disc2_used[] __attribute((unused)) = {
-	0x000002b7,
+	0x000002cd,
 };
 
 #define A_int_disc3	0xab93001b
 static u32 A_int_disc3_used[] __attribute((unused)) = {
-	0x000002f7,
+	0x00000319,
 };
 
 #define A_int_msg_sdtr1	0xab93000c
 static u32 A_int_msg_sdtr1_used[] __attribute((unused)) = {
-	0x00000271,
+	0x0000026b,
 };
 
 #define A_int_msg_sdtr2	0xab93000d
 static u32 A_int_msg_sdtr2_used[] __attribute((unused)) = {
-	0x000002b1,
+	0x000002b7,
 };
 
 #define A_int_msg_sdtr3	0xab93000e
 static u32 A_int_msg_sdtr3_used[] __attribute((unused)) = {
-	0x000002f1,
+	0x00000303,
 };
 
 #define A_int_no_msgout1	0xab93000f
 static u32 A_int_no_msgout1_used[] __attribute((unused)) = {
-	0x00000281,
+	0x0000028b,
 };
 
 #define A_int_no_msgout2	0xab930010
 static u32 A_int_no_msgout2_used[] __attribute((unused)) = {
-	0x000002c1,
+	0x000002d7,
 };
 
 #define A_int_no_msgout3	0xab930011
 static u32 A_int_no_msgout3_used[] __attribute((unused)) = {
-	0x00000301,
+	0x00000323,
 };
 
 #define A_int_not_cmd_complete	0xab930012
 static u32 A_int_not_cmd_complete_used[] __attribute((unused)) = {
-	0x00000031,
+	0x0000002f,
 };
 
 #define A_int_not_rej	0xab93001c
 static u32 A_int_not_rej_used[] __attribute((unused)) = {
-	0x0000030d,
+	0x0000032f,
 };
 
 #define A_int_resel_not_msgin	0xab930016
 static u32 A_int_resel_not_msgin_used[] __attribute((unused)) = {
-	0x00000317,
+	0x00000339,
 };
 
 #define A_int_reselected	0xab930017
 static u32 A_int_reselected_used[] __attribute((unused)) = {
-	0x0000031b,
+	0x0000033d,
 };
 
 #define A_int_sel_no_ident	0xab930013
 static u32 A_int_sel_no_ident_used[] __attribute((unused)) = {
-	0x0000000f,
+	0x0000000d,
 };
 
 #define A_int_sel_not_cmd	0xab930014
 static u32 A_int_sel_not_cmd_used[] __attribute((unused)) = {
-	0x00000019,
+	0x00000017,
 };
 
 #define A_int_selected	0xab930018
 static u32 A_int_selected_used[] __attribute((unused)) = {
-	0x0000032d,
+	0x0000034f,
 };
 
 #define A_int_status_not_msgin	0xab930015
 static u32 A_int_status_not_msgin_used[] __attribute((unused)) = {
-	0x0000002d,
+	0x0000002b,
+};
+
+#define A_int_test1	0xab93001d
+static u32 A_int_test1_used[] __attribute((unused)) = {
+	0x00000354,
+};
+
+#define A_msg_reject	0x00000000
+static u32 A_msg_reject_used[] __attribute((unused)) = {
+	0x00000279,
+	0x000002c5,
+	0x00000311,
 };
 
 #define A_msgin_buf	0x00000000
 static u32 A_msgin_buf_used[] __attribute((unused)) = {
-	0x0000024b,
-	0x0000025f,
-	0x00000267,
-	0x0000026f,
-	0x0000028b,
-	0x0000029f,
-	0x000002a7,
+	0x00000249,
+	0x0000025d,
+	0x00000263,
+	0x00000269,
+	0x00000275,
+	0x00000295,
+	0x000002a9,
 	0x000002af,
-	0x000002cb,
-	0x000002df,
-	0x000002e7,
-	0x000002ef,
-	0x0000030b,
+	0x000002b5,
+	0x000002c1,
+	0x000002e1,
+	0x000002f5,
+	0x000002fb,
+	0x00000301,
+	0x0000030d,
+	0x0000032d,
 };
 
 #define A_reselected_identify	0x00000000
 static u32 A_reselected_identify_used[] __attribute((unused)) = {
-	0x00000319,
+	0x0000033b,
+};
+
+#define A_test1_dst	0x00000000
+static u32 A_test1_dst_used[] __attribute((unused)) = {
+	0x00000352,
+};
+
+#define A_test1_src	0x00000000
+static u32 A_test1_src_used[] __attribute((unused)) = {
+	0x00000351,
 };
 
 #define Ent_do_select	0x00000000
-#define Ent_done_ident	0x00000050
-#define Ent_end_data_trans	0x00000908
-#define Ent_patch_input_data	0x000000e8
-#define Ent_patch_new_dsa	0x00000c88
-#define Ent_patch_output_data	0x00000500
-#define Ent_reselect	0x00000c48
-#define Ent_resume_cmd	0x00000068
-#define Ent_resume_msgin1a	0x000009e0
-#define Ent_resume_msgin1b	0x000009f0
-#define Ent_resume_msgin2a	0x00000ae0
-#define Ent_resume_msgin2b	0x00000af0
-#define Ent_resume_msgin3a	0x00000be0
-#define Ent_resume_msgin3b	0x00000bf0
-#define Ent_resume_pmm	0x00000078
-#define Ent_resume_rej_ident	0x00000c20
-#define Ent_wait_disc1	0x000009d0
-#define Ent_wait_disc2	0x00000ad0
-#define Ent_wait_disc3	0x00000bd0
-#define Ent_wait_disc_complete	0x000000d0
+#define Ent_done_ident	0x00000048
+#define Ent_end_data_trans	0x00000900
+#define Ent_patch_input_data	0x000000e0
+#define Ent_patch_new_dsa	0x00000d10
+#define Ent_patch_output_data	0x000004f8
+#define Ent_reselect	0x00000cd0
+#define Ent_resume_cmd	0x00000060
+#define Ent_resume_msgin1a	0x00000a08
+#define Ent_resume_msgin1b	0x00000a18
+#define Ent_resume_msgin2a	0x00000b38
+#define Ent_resume_msgin2b	0x00000b48
+#define Ent_resume_msgin3a	0x00000c68
+#define Ent_resume_msgin3b	0x00000c78
+#define Ent_resume_pmm	0x00000070
+#define Ent_resume_rej_ident	0x00000ca8
+#define Ent_test1	0x00000d40
+#define Ent_wait_disc1	0x000009f8
+#define Ent_wait_disc2	0x00000b28
+#define Ent_wait_disc3	0x00000c58
+#define Ent_wait_disc_complete	0x000000c8
 static u32 LABELPATCHES[] __attribute((unused)) = {
+	0x00000005,
 	0x00000007,
-	0x00000009,
+	0x00000013,
 	0x00000015,
-	0x00000017,
+	0x0000001d,
 	0x0000001f,
 	0x00000021,
 	0x00000023,
-	0x00000025,
-	0x0000013d,
+	0x0000013b,
+	0x00000241,
 	0x00000243,
-	0x00000245,
+	0x0000024b,
 	0x0000024d,
 	0x0000024f,
 	0x00000251,
-	0x00000253,
-	0x00000259,
-	0x00000261,
-	0x00000269,
+	0x00000257,
+	0x0000025f,
+	0x00000265,
+	0x00000273,
+	0x00000277,
 	0x0000027b,
-	0x00000287,
-	0x0000028d,
-	0x0000028f,
+	0x00000285,
 	0x00000291,
-	0x00000293,
+	0x00000297,
 	0x00000299,
-	0x000002a1,
-	0x000002a9,
-	0x000002bb,
+	0x0000029b,
+	0x0000029d,
+	0x000002a3,
+	0x000002ab,
+	0x000002b1,
+	0x000002bf,
+	0x000002c3,
 	0x000002c7,
-	0x000002cd,
-	0x000002cf,
 	0x000002d1,
-	0x000002d3,
-	0x000002d9,
-	0x000002e1,
+	0x000002dd,
+	0x000002e3,
+	0x000002e5,
+	0x000002e7,
 	0x000002e9,
-	0x000002fb,
-	0x00000307,
-	0x00000311,
-	0x00000315,
-	0x0000031f,
-	0x0000032b,
+	0x000002ef,
+	0x000002f7,
+	0x000002fd,
+	0x0000030b,
+	0x0000030f,
+	0x00000313,
+	0x0000031d,
+	0x00000329,
+	0x00000333,
+	0x00000337,
+	0x00000341,
+	0x0000034d,
 };
 
 static struct {
@@ -2356,6 +2447,6 @@
 } EXTERNAL_PATCHES[] __attribute((unused)) = {
 };
 
-static u32 INSTRUCTIONS __attribute((unused))	= 407;
-static u32 PATCHES __attribute((unused))	= 42;
+static u32 INSTRUCTIONS __attribute((unused))	= 426;
+static u32 PATCHES __attribute((unused))	= 51;
 static u32 EXTERNAL_PATCHES_LEN __attribute((unused))	= 0;
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/scsi/sr.c	Fri Oct 11 21:22:54 2002
@@ -323,7 +323,7 @@
 	/*
 	 * request doesn't start on hw block boundary, add scatter pads
 	 */
-	if ((SCpnt->request->sector % (s_size >> 9)) || (SCpnt->request_bufflen % s_size)) {
+	if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) || (SCpnt->request_bufflen % s_size)) {
 		printk("sr: unaligned transfer\n");
 		return 0;
 	}
@@ -339,7 +339,7 @@
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
 			 ((SCpnt->lun << 5) & 0xe0) : 0;
 
-	block = SCpnt->request->sector / (s_size >> 9);
+	block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
 
 	if (this_count > 0xffff)
 		this_count = 0xffff;
diff -Nru a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
--- a/drivers/scsi/sun3_NCR5380.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/scsi/sun3_NCR5380.c	Fri Oct 11 21:22:53 2002
@@ -1213,9 +1213,9 @@
 
     if((sun3scsi_dma_finish(hostdata->connected->request->cmd))) {
 	    printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO);
-	    printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+	    printk("please e-mail sammy@sammy.net with a description of how this\n");
 	    printk("error was produced.\n");
-	    machine_halt();
+	    BUG();
     }
 
     /* make sure we're not stuck in a data phase */
@@ -1226,9 +1226,9 @@
 	    printk("scsi%d: bus stuck in data phase -- probably a
  single byte overrun!\n", HOSTNO); 
 	    printk("not prepared for this error!\n");
-	    printk("please e-mail sammy@oh.verio.com with a description of how this\n");
+	    printk("please e-mail sammy@sammy.net with a description of how this\n");
 	    printk("error was produced.\n");
-	    machine_halt();
+	    BUG();
     }
 
 
@@ -1916,7 +1916,7 @@
     /* sanity check */
     if(!sun3_dma_setup_done) {
 	 printk("scsi%d: transfer_dma without setup!\n", HOSTNO);
-	 machine_halt();
+	 BUG();
     }
 
     hostdata->dma_len = c;
diff -Nru a/drivers/scsi/t128.h b/drivers/scsi/t128.h
--- a/drivers/scsi/t128.h	Fri Oct 11 21:22:55 2002
+++ b/drivers/scsi/t128.h	Fri Oct 11 21:22:55 2002
@@ -95,7 +95,9 @@
 int t128_biosparam(Disk *, struct block_device *, int*);
 int t128_detect(Scsi_Host_Template *);
 int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int t128_reset(Scsi_Cmnd *, unsigned int reset_flags);
+int t128_host_reset(Scsi_Cmnd *);
+int t128_bus_reset(Scsi_Cmnd *);
+int t128_device_reset(Scsi_Cmnd *);
 int t128_proc_info (char *buffer, char **start, off_t offset,
 		   int length, int hostno, int inout);
 
@@ -121,8 +123,10 @@
 	name:           "Trantor T128/T128F/T228",	\
 	detect:         t128_detect,			\
 	queuecommand:   t128_queue_command,		\
-	abort:          t128_abort,			\
-	reset:          t128_reset,			\
+	eh_abort_handler: t128_abort,			\
+	eh_bus_reset_handler:    t128_bus_reset,	\
+	eh_host_reset_handler:   t128_host_reset,	\
+	eh_device_reset_handler: t128_device_reset,	\
 	bios_param:     t128_biosparam,			\
 	can_queue:      CAN_QUEUE,			\
         this_id:        7,				\
@@ -162,7 +166,9 @@
 #define do_NCR5380_intr do_t128_intr
 #define NCR5380_queue_command t128_queue_command
 #define NCR5380_abort t128_abort
-#define NCR5380_reset t128_reset
+#define NCR5380_host_reset t128_hostreset
+#define NCR5380_device_reset t128_device_reset
+#define NCR5380_bus_reset t128_bus_reset
 #define NCR5380_proc_info t128_proc_info
 
 /* 15 14 12 10 7 5 3 
diff -Nru a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
--- a/drivers/scsi/wd33c93.h	Fri Oct 11 21:22:54 2002
+++ b/drivers/scsi/wd33c93.h	Fri Oct 11 21:22:54 2002
@@ -19,11 +19,8 @@
  * GNU General Public License for more details.
  *
  */
-
 #ifndef WD33C93_H
 #define WD33C93_H
-
-#include <linux/config.h>
 
 #define PROC_INTERFACE     /* add code for /proc/scsi/wd33c93/xxx interface */
 #ifdef  PROC_INTERFACE
diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
--- a/drivers/scsi/wd7000.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/scsi/wd7000.c	Fri Oct 11 21:23:05 2002
@@ -216,8 +216,8 @@
  *
  */
 typedef volatile struct mailbox {
-    unchar status;
-    unchar scbptr[3];		/* SCSI-style - MSB first (big endian) */
+	unchar status;
+	unchar scbptr[3];	/* SCSI-style - MSB first (big endian) */
 } Mailbox;
 
 /*
@@ -225,38 +225,36 @@
  *  new global per-adapter data should put in here.
  */
 typedef struct adapter {
-    struct Scsi_Host *sh;	/* Pointer to Scsi_Host structure    */
-    int iobase;			/* This adapter's I/O base address   */
-    int irq;			/* This adapter's IRQ level          */
-    int dma;			/* This adapter's DMA channel        */
-    int int_counter;		/* This adapter's interrupt counter  */
-    int bus_on;			/* This adapter's BUS_ON time        */
-    int bus_off;		/* This adapter's BUS_OFF time       */
-    struct {			/* This adapter's mailboxes          */
-	Mailbox ogmb[OGMB_CNT];	/* Outgoing mailboxes                */
-	Mailbox icmb[ICMB_CNT];	/* Incoming mailboxes                */
-    } mb;
-    int next_ogmb;		/* to reduce contention at mailboxes */
-    unchar control;		/* shadows CONTROL port value        */
-    unchar rev1, rev2;		/* filled in by wd7000_revision      */
+	struct Scsi_Host *sh;	/* Pointer to Scsi_Host structure    */
+	int iobase;		/* This adapter's I/O base address   */
+	int irq;		/* This adapter's IRQ level          */
+	int dma;		/* This adapter's DMA channel        */
+	int int_counter;	/* This adapter's interrupt counter  */
+	int bus_on;		/* This adapter's BUS_ON time        */
+	int bus_off;		/* This adapter's BUS_OFF time       */
+	struct {		/* This adapter's mailboxes          */
+		Mailbox ogmb[OGMB_CNT];	/* Outgoing mailboxes                */
+		Mailbox icmb[ICMB_CNT];	/* Incoming mailboxes                */
+	} mb;
+	int next_ogmb;		/* to reduce contention at mailboxes */
+	unchar control;		/* shadows CONTROL port value        */
+	unchar rev1, rev2;	/* filled in by wd7000_revision      */
 } Adapter;
 
 /*
  * (linear) base address for ROM BIOS
  */
-static const long wd7000_biosaddr[] =
-{
-    0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
-    0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
+static const long wd7000_biosaddr[] = {
+	0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
+	0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
 };
 #define NUM_ADDRS (sizeof(wd7000_biosaddr)/sizeof(long))
 
-static const unsigned short wd7000_iobase[] =
-{
-    0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
-    0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
-    0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
-    0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
+static const unsigned short wd7000_iobase[] = {
+	0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
+	0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
+	0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
+	0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
 };
 #define NUM_IOPORTS (sizeof(wd7000_iobase)/sizeof(unsigned short))
 
@@ -270,36 +268,35 @@
  * The following is set up by wd7000_detect, and used thereafter for
  * proc and other global ookups
  */
- 
+
 #define UNITS	8
 static struct Scsi_Host *wd7000_host[UNITS];
 
-#define BUS_ON    64	/* x 125ns = 8000ns (BIOS default) */
-#define BUS_OFF   15	/* x 125ns = 1875ns (BIOS default) */
+#define BUS_ON    64		/* x 125ns = 8000ns (BIOS default) */
+#define BUS_OFF   15		/* x 125ns = 1875ns (BIOS default) */
 
 /*
  *  Standard Adapter Configurations - used by wd7000_detect
  */
 typedef struct {
-    short irq;		/* IRQ level                                  */
-    short dma;		/* DMA channel                                */
-    unsigned iobase;	/* I/O base address                           */
-    short bus_on;	/* Time that WD7000 spends on the AT-bus when */
-			/* transferring data. BIOS default is 8000ns. */
-    short bus_off;	/* Time that WD7000 spends OFF THE BUS after  */
-			/* while it is transferring data.             */
-			/* BIOS default is 1875ns                     */
+	short irq;		/* IRQ level                                  */
+	short dma;		/* DMA channel                                */
+	unsigned iobase;	/* I/O base address                           */
+	short bus_on;		/* Time that WD7000 spends on the AT-bus when */
+	/* transferring data. BIOS default is 8000ns. */
+	short bus_off;		/* Time that WD7000 spends OFF THE BUS after  */
+	/* while it is transferring data.             */
+	/* BIOS default is 1875ns                     */
 } Config;
 
 /*
  * Add here your configuration...
  */
-static Config configs[] =
-{
-    { 15,  6, 0x350, BUS_ON, BUS_OFF },	/* defaults for single adapter */
-    { 11,  5, 0x320, BUS_ON, BUS_OFF },	/* defaults for second adapter */
-    {  7,  6, 0x350, BUS_ON, BUS_OFF },	/* My configuration (Zaga)     */
-    { -1, -1, 0x0,   BUS_ON, BUS_OFF }	/* Empty slot                  */
+static Config configs[] = {
+	{15, 6, 0x350, BUS_ON, BUS_OFF},	/* defaults for single adapter */
+	{11, 5, 0x320, BUS_ON, BUS_OFF},	/* defaults for second adapter */
+	{7, 6, 0x350, BUS_ON, BUS_OFF},	/* My configuration (Zaga)     */
+	{-1, -1, 0x0, BUS_ON, BUS_OFF}	/* Empty slot                  */
 };
 #define NUM_CONFIGS (sizeof(configs)/sizeof(Config))
 
@@ -309,14 +306,13 @@
  *  added for the Future Domain version.
  */
 typedef struct signature {
-    const char *sig;		/* String to look for            */
-    unsigned long ofs;		/* offset from BIOS base address */
-    unsigned len;		/* length of string              */
+	const char *sig;	/* String to look for            */
+	unsigned long ofs;	/* offset from BIOS base address */
+	unsigned len;		/* length of string              */
 } Signature;
 
-static const Signature signatures[] =
-{
-    {"SSTBIOS", 0x0000d, 7}	/* "SSTBIOS" @ offset 0x0000d */
+static const Signature signatures[] = {
+	{"SSTBIOS", 0x0000d, 7}	/* "SSTBIOS" @ offset 0x0000d */
 };
 #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
 
@@ -363,14 +359,14 @@
  * For INITIALIZATION:
  */
 typedef struct initCmd {
-    unchar op;			/* command opcode (= 1)                    */
-    unchar ID;			/* Adapter's SCSI ID                       */
-    unchar bus_on;		/* Bus on time, x 125ns (see below)        */
-    unchar bus_off;		/* Bus off time, ""         ""             */
-    unchar rsvd;		/* Reserved                                */
-    unchar mailboxes[3];	/* Address of Mailboxes, MSB first         */
-    unchar ogmbs;		/* Number of outgoing MBs, max 64, 0,1 = 1 */
-    unchar icmbs;		/* Number of incoming MBs,   ""       ""   */
+	unchar op;		/* command opcode (= 1)                    */
+	unchar ID;		/* Adapter's SCSI ID                       */
+	unchar bus_on;		/* Bus on time, x 125ns (see below)        */
+	unchar bus_off;		/* Bus off time, ""         ""             */
+	unchar rsvd;		/* Reserved                                */
+	unchar mailboxes[3];	/* Address of Mailboxes, MSB first         */
+	unchar ogmbs;		/* Number of outgoing MBs, max 64, 0,1 = 1 */
+	unchar icmbs;		/* Number of incoming MBs,   ""       ""   */
 } InitCmd;
 
 /*
@@ -430,29 +426,29 @@
  *  WD7000-specific scatter/gather element structure
  */
 typedef struct sgb {
-    unchar len[3];
-    unchar ptr[3];		/* Also SCSI-style - MSB first */
+	unchar len[3];
+	unchar ptr[3];		/* Also SCSI-style - MSB first */
 } Sgb;
 
 typedef struct scb {		/* Command Control Block 5.4.1               */
-    unchar op;			/* Command Control Block Operation Code      */
-    unchar idlun;		/* op=0,2:Target Id, op=1:Initiator Id       */
-				/* Outbound data transfer, length is checked */
-				/* Inbound data transfer, length is checked  */
-				/* Logical Unit Number                       */
-    unchar cdb[12];		/* SCSI Command Block                        */
-    volatile unchar status;	/* SCSI Return Status                        */
-    volatile unchar vue;	/* Vendor Unique Error Code                  */
-    unchar maxlen[3];		/* Maximum Data Transfer Length              */
-    unchar dataptr[3];		/* SCSI Data Block Pointer                   */
-    unchar linkptr[3];		/* Next Command Link Pointer                 */
-    unchar direc;		/* Transfer Direction                        */
-    unchar reserved2[6];	/* SCSI Command Descriptor Block             */
-				/* end of hardware SCB                       */
-    Scsi_Cmnd *SCpnt;		/* Scsi_Cmnd using this SCB                  */
-    Sgb sgb[WD7000_SG];		/* Scatter/gather list for this SCB          */
-    Adapter *host;		/* host adapter                              */
-    struct scb *next;		/* for lists of scbs                         */
+	unchar op;		/* Command Control Block Operation Code      */
+	unchar idlun;		/* op=0,2:Target Id, op=1:Initiator Id       */
+	/* Outbound data transfer, length is checked */
+	/* Inbound data transfer, length is checked  */
+	/* Logical Unit Number                       */
+	unchar cdb[12];		/* SCSI Command Block                        */
+	volatile unchar status;	/* SCSI Return Status                        */
+	volatile unchar vue;	/* Vendor Unique Error Code                  */
+	unchar maxlen[3];	/* Maximum Data Transfer Length              */
+	unchar dataptr[3];	/* SCSI Data Block Pointer                   */
+	unchar linkptr[3];	/* Next Command Link Pointer                 */
+	unchar direc;		/* Transfer Direction                        */
+	unchar reserved2[6];	/* SCSI Command Descriptor Block             */
+	/* end of hardware SCB                       */
+	Scsi_Cmnd *SCpnt;	/* Scsi_Cmnd using this SCB                  */
+	Sgb sgb[WD7000_SG];	/* Scatter/gather list for this SCB          */
+	Adapter *host;		/* host adapter                              */
+	struct scb *next;	/* for lists of scbs                         */
 } Scb;
 
 /*
@@ -484,56 +480,56 @@
 #define ICB_OP_GET_EPARMS     0x8F	/* read execution parameters           */
 
 typedef struct icbRecvCmd {
-    unchar op;
-    unchar IDlun;		/* Initiator SCSI ID/lun     */
-    unchar len[3];		/* command buffer length     */
-    unchar ptr[3];		/* command buffer address    */
-    unchar rsvd[7];		/* reserved                  */
-    volatile unchar vue;	/* vendor-unique error code  */
-    volatile unchar status;	/* returned (icmb) status    */
-    volatile unchar phase;	/* used by interrupt handler */
+	unchar op;
+	unchar IDlun;		/* Initiator SCSI ID/lun     */
+	unchar len[3];		/* command buffer length     */
+	unchar ptr[3];		/* command buffer address    */
+	unchar rsvd[7];		/* reserved                  */
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
 } IcbRecvCmd;
 
 typedef struct icbSendStat {
-    unchar op;
-    unchar IDlun;		/* Target SCSI ID/lun                  */
-    unchar stat;		/* (outgoing) completion status byte 1 */
-    unchar rsvd[12];		/* reserved                            */
-    volatile unchar vue;	/* vendor-unique error code            */
-    volatile unchar status;	/* returned (icmb) status              */
-    volatile unchar phase;	/* used by interrupt handler           */
+	unchar op;
+	unchar IDlun;		/* Target SCSI ID/lun                  */
+	unchar stat;		/* (outgoing) completion status byte 1 */
+	unchar rsvd[12];	/* reserved                            */
+	volatile unchar vue;	/* vendor-unique error code            */
+	volatile unchar status;	/* returned (icmb) status              */
+	volatile unchar phase;	/* used by interrupt handler           */
 } IcbSendStat;
 
 typedef struct icbRevLvl {
-    unchar op;
-    volatile unchar primary;	/* primary revision level (returned)   */
-    volatile unchar secondary;	/* secondary revision level (returned) */
-    unchar rsvd[12];		/* reserved                            */
-    volatile unchar vue;	/* vendor-unique error code            */
-    volatile unchar status;	/* returned (icmb) status              */
-    volatile unchar phase;	/* used by interrupt handler           */
+	unchar op;
+	volatile unchar primary;	/* primary revision level (returned)   */
+	volatile unchar secondary;	/* secondary revision level (returned) */
+	unchar rsvd[12];	/* reserved                            */
+	volatile unchar vue;	/* vendor-unique error code            */
+	volatile unchar status;	/* returned (icmb) status              */
+	volatile unchar phase;	/* used by interrupt handler           */
 } IcbRevLvl;
 
 typedef struct icbUnsMask {	/* I'm totally guessing here */
-    unchar op;
-    volatile unchar mask[14];	/* mask bits                 */
+	unchar op;
+	volatile unchar mask[14];	/* mask bits                 */
 #if 0
-    unchar rsvd[12];		/* reserved                  */
+	unchar rsvd[12];	/* reserved                  */
 #endif
-    volatile unchar vue;	/* vendor-unique error code  */
-    volatile unchar status;	/* returned (icmb) status    */
-    volatile unchar phase;	/* used by interrupt handler */
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
 } IcbUnsMask;
 
 typedef struct icbDiag {
-    unchar op;
-    unchar type;		/* diagnostics type code (0-3) */
-    unchar len[3];		/* buffer length               */
-    unchar ptr[3];		/* buffer address              */
-    unchar rsvd[7];		/* reserved                    */
-    volatile unchar vue;	/* vendor-unique error code    */
-    volatile unchar status;	/* returned (icmb) status      */
-    volatile unchar phase;	/* used by interrupt handler   */
+	unchar op;
+	unchar type;		/* diagnostics type code (0-3) */
+	unchar len[3];		/* buffer length               */
+	unchar ptr[3];		/* buffer address              */
+	unchar rsvd[7];		/* reserved                    */
+	volatile unchar vue;	/* vendor-unique error code    */
+	volatile unchar status;	/* returned (icmb) status      */
+	volatile unchar phase;	/* used by interrupt handler   */
 } IcbDiag;
 
 #define ICB_DIAG_POWERUP   0	/* Power-up diags only       */
@@ -542,34 +538,34 @@
 #define ICB_DIAG_FULL      3	/* do both 1 & 2             */
 
 typedef struct icbParms {
-    unchar op;
-    unchar rsvd1;		/* reserved                  */
-    unchar len[3];		/* parms buffer length       */
-    unchar ptr[3];		/* parms buffer address      */
-    unchar idx[2];		/* index (MSB-LSB)           */
-    unchar rsvd2[5];		/* reserved                  */
-    volatile unchar vue;	/* vendor-unique error code  */
-    volatile unchar status;	/* returned (icmb) status    */
-    volatile unchar phase;	/* used by interrupt handler */
+	unchar op;
+	unchar rsvd1;		/* reserved                  */
+	unchar len[3];		/* parms buffer length       */
+	unchar ptr[3];		/* parms buffer address      */
+	unchar idx[2];		/* index (MSB-LSB)           */
+	unchar rsvd2[5];	/* reserved                  */
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
 } IcbParms;
 
 typedef struct icbAny {
-    unchar op;
-    unchar data[14];		/* format-specific data      */
-    volatile unchar vue;	/* vendor-unique error code  */
-    volatile unchar status;	/* returned (icmb) status    */
-    volatile unchar phase;	/* used by interrupt handler */
+	unchar op;
+	unchar data[14];	/* format-specific data      */
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
 } IcbAny;
 
 typedef union icb {
-    unchar op;			/* ICB opcode                     */
-    IcbRecvCmd recv_cmd;	/* format for receive command     */
-    IcbSendStat send_stat;	/* format for send status         */
-    IcbRevLvl rev_lvl;		/* format for get revision level  */
-    IcbDiag diag;		/* format for execute diagnostics */
-    IcbParms eparms;		/* format for get/set exec parms  */
-    IcbAny icb;			/* generic format                 */
-    unchar data[18];
+	unchar op;		/* ICB opcode                     */
+	IcbRecvCmd recv_cmd;	/* format for receive command     */
+	IcbSendStat send_stat;	/* format for send status         */
+	IcbRevLvl rev_lvl;	/* format for get revision level  */
+	IcbDiag diag;		/* format for execute diagnostics */
+	IcbParms eparms;	/* format for get/set exec parms  */
+	IcbAny icb;		/* generic format                 */
+	unchar data[18];
 } Icb;
 
 #ifdef MODULE
@@ -586,22 +582,19 @@
 static Scb scbs[MAX_SCBS];
 static Scb *scbfree;		/* free list         */
 static int freescbs = MAX_SCBS;	/* free list counter */
-static spinlock_t scbpool_lock; /* guards the scb free list and count */
+static spinlock_t scbpool_lock;	/* guards the scb free list and count */
 
 /*
  *  END of data/declarations - code follows.
  */
 static void __init setup_error(char *mesg, int *ints)
 {
-    if (ints[0] == 3)
-        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
-               ints[1], ints[2], ints[3], mesg);
-    else if (ints[0] == 4)
-        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
-               ints[1], ints[2], ints[3], ints[4], mesg);
-    else
-        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
-               ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
+	if (ints[0] == 3)
+		printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", ints[1], ints[2], ints[3], mesg);
+	else if (ints[0] == 4)
+		printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], mesg);
+	else
+		printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
 }
 
 
@@ -621,23 +614,19 @@
  */
 static int __init wd7000_setup(char *str)
 {
-	static short wd7000_card_num; /* .bss will zero this */
+	static short wd7000_card_num;	/* .bss will zero this */
 	short i;
 	int ints[6];
 
-	(void)get_options(str, ARRAY_SIZE(ints), ints);
+	(void) get_options(str, ARRAY_SIZE(ints), ints);
 
 	if (wd7000_card_num >= NUM_CONFIGS) {
-		printk(KERN_ERR
-			"%s: Too many \"wd7000=\" configurations in "
-			"command line!\n", __FUNCTION__);
+		printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __FUNCTION__);
 		return 0;
 	}
 
 	if ((ints[0] < 3) || (ints[0] > 5)) {
-		printk(KERN_ERR "%s: Error in command line!  "
-			"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>"
-			"[,<BUS_OFF>]]\n", __FUNCTION__);
+		printk(KERN_ERR "%s: Error in command line!  " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __FUNCTION__);
 	} else {
 		for (i = 0; i < NUM_IRQS; i++)
 			if (ints[1] == wd7000_irq[i])
@@ -671,8 +660,7 @@
 
 		if (ints[0] > 3) {
 			if ((ints[4] < 500) || (ints[4] > 31875)) {
-				setup_error("BUS_ON value is out of range (500"
-					    " to 31875 nanoseconds)!", ints);
+				setup_error("BUS_ON value is out of range (500" " to 31875 nanoseconds)!", ints);
 				configs[wd7000_card_num].bus_on = BUS_ON;
 			} else
 				configs[wd7000_card_num].bus_on = ints[4] / 125;
@@ -681,12 +669,10 @@
 
 		if (ints[0] > 4) {
 			if ((ints[5] < 500) || (ints[5] > 31875)) {
-				setup_error("BUS_OFF value is out of range (500"
-					    " to 31875 nanoseconds)!", ints);
+				setup_error("BUS_OFF value is out of range (500" " to 31875 nanoseconds)!", ints);
 				configs[wd7000_card_num].bus_off = BUS_OFF;
 			} else
-				configs[wd7000_card_num].bus_off = ints[5] /
-								   125;
+				configs[wd7000_card_num].bus_off = ints[5] / 125;
 		} else
 			configs[wd7000_card_num].bus_off = BUS_OFF;
 
@@ -696,32 +682,22 @@
 
 				for (; j < wd7000_card_num; j++)
 					if (configs[i].irq == configs[j].irq) {
-						setup_error("duplicated IRQ!",
-							    ints);
-						return 0;
-					}
-					if (configs[i].dma == configs[j].dma) {
-						setup_error("duplicated DMA "
-							    "channel!", ints);
-						return 0;
-					}
-					if (configs[i].iobase ==
-					    configs[j].iobase) {
-						setup_error("duplicated I/O "
-							    "base address!",
-							    ints);
+						setup_error("duplicated IRQ!", ints);
 						return 0;
 					}
+				if (configs[i].dma == configs[j].dma) {
+					setup_error("duplicated DMA " "channel!", ints);
+					return 0;
+				}
+				if (configs[i].iobase == configs[j].iobase) {
+					setup_error("duplicated I/O " "base address!", ints);
+					return 0;
+				}
 			}
 		}
 
 		dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
-				  "BUS_ON=%dns, BUS_OFF=%dns\n",
-			configs[wd7000_card_num].irq,
-			configs[wd7000_card_num].dma,
-			configs[wd7000_card_num].iobase,
-			configs[wd7000_card_num].bus_on * 125,
-			configs[wd7000_card_num].bus_off * 125);
+			"BUS_ON=%dns, BUS_OFF=%dns\n", configs[wd7000_card_num].irq, configs[wd7000_card_num].dma, configs[wd7000_card_num].iobase, configs[wd7000_card_num].bus_on * 125, configs[wd7000_card_num].bus_off * 125);
 
 		wd7000_card_num++;
 	}
@@ -740,29 +716,29 @@
  * (They were simply 4-byte versions of these routines).
  */
 typedef union {			/* let's cheat... */
-    int i;
-    unchar u[sizeof (int)];	/* the sizeof(int) makes it more portable */
+	int i;
+	unchar u[sizeof(int)];	/* the sizeof(int) makes it more portable */
 } i_u;
 
 
-static inline void any2scsi (unchar * scsi, int any)
+static inline void any2scsi(unchar * scsi, int any)
 {
-    *scsi++ = ((i_u) any).u[2];
-    *scsi++ = ((i_u) any).u[1];
-    *scsi++ = ((i_u) any).u[0];
+	*scsi++ = ((i_u) any).u[2];
+	*scsi++ = ((i_u) any).u[1];
+	*scsi++ = ((i_u) any).u[0];
 }
 
 
-static inline int scsi2int (unchar * scsi)
+static inline int scsi2int(unchar * scsi)
 {
-    i_u result;
+	i_u result;
 
-    result.i = 0;		/* clears unused bytes */
-    result.u[2] = *scsi++;
-    result.u[1] = *scsi++;
-    result.u[0] = *scsi++;
+	result.i = 0;		/* clears unused bytes */
+	result.u[2] = *scsi++;
+	result.u[1] = *scsi++;
+	result.u[0] = *scsi++;
 
-    return (result.i);
+	return (result.i);
 }
 #else
 /*
@@ -780,63 +756,63 @@
 #endif
 
 
-static inline void wd7000_enable_intr (Adapter *host)
+static inline void wd7000_enable_intr(Adapter * host)
 {
-    host->control |= INT_EN;
-    outb (host->control, host->iobase + ASC_CONTROL);
+	host->control |= INT_EN;
+	outb(host->control, host->iobase + ASC_CONTROL);
 }
 
 
-static inline void wd7000_enable_dma (Adapter *host)
+static inline void wd7000_enable_dma(Adapter * host)
 {
-    unsigned long flags;
-    host->control |= DMA_EN;
-    outb (host->control, host->iobase + ASC_CONTROL);
-    
-    flags = claim_dma_lock();
-    set_dma_mode (host->dma, DMA_MODE_CASCADE);
-    enable_dma (host->dma);
-    release_dma_lock(flags);
-    
+	unsigned long flags;
+	host->control |= DMA_EN;
+	outb(host->control, host->iobase + ASC_CONTROL);
+
+	flags = claim_dma_lock();
+	set_dma_mode(host->dma, DMA_MODE_CASCADE);
+	enable_dma(host->dma);
+	release_dma_lock(flags);
+
 }
 
 
 #define WAITnexttimeout 200	/* 2 seconds */
 
-static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned noneof)
+static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof)
 {
-    register unsigned WAITbits;
-    register unsigned long WAITtimeout = jiffies + WAITnexttimeout;
+	register unsigned WAITbits;
+	register unsigned long WAITtimeout = jiffies + WAITnexttimeout;
 
-    while (time_before_eq(jiffies, WAITtimeout)) {
-	WAITbits = inb (port) & mask;
+	while (time_before_eq(jiffies, WAITtimeout)) {
+		WAITbits = inb(port) & mask;
 
-	if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
-	    return (0);
-    }
+		if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
+			return (0);
+	}
 
-    return (1);
+	return (1);
 }
 
 
-static inline int command_out (Adapter * host, unchar * cmd, int len)
+static inline int command_out(Adapter * host, unchar * cmd, int len)
 {
-    if (!WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
-	while (len--) {
-	    do {
-		outb (*cmd, host->iobase + ASC_COMMAND);
-		WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
-	    } while (inb (host->iobase + ASC_STAT) & CMD_REJ);
+	if (!WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+		while (len--) {
+			do {
+				outb(*cmd, host->iobase + ASC_COMMAND);
+				WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
+			} while (inb(host->iobase + ASC_STAT) & CMD_REJ);
 
-	    cmd++;
-	}
+			cmd++;
+		}
 
-	return (1);
-    }
+		return (1);
+	}
 
-    printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
+	printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
 
-    return (0);
+	return (0);
 }
 
 
@@ -852,655 +828,645 @@
  */
 static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
 {
-    register Scb *scb, *p = NULL;
-    register unsigned long flags;
-    register unsigned long timeout = jiffies + WAITnexttimeout;
-    register unsigned long now;
-    int i;
-
-    if (needed <= 0)
-	return (NULL);		/* sanity check */
-
-    spin_unlock_irq(host->host_lock);
-	
-retry:
-    while (freescbs < needed) {
-	timeout = jiffies + WAITnexttimeout;
-	do {
-	    /* FIXME: can we actually just yield here ?? */
-	    for (now = jiffies; now == jiffies; )
-	    	cpu_relax();	/* wait a jiffy */
-	} while (freescbs < needed && time_before_eq(jiffies, timeout));
-	/*
-	 *  If we get here with enough free Scbs, we can take them.
-	 *  Otherwise, we timed out and didn't get enough.
-	 */
+	register Scb *scb, *p = NULL;
+	register unsigned long flags;
+	register unsigned long timeout = jiffies + WAITnexttimeout;
+	register unsigned long now;
+	int i;
+
+	if (needed <= 0)
+		return (NULL);	/* sanity check */
+
+	spin_unlock_irq(host->host_lock);
+
+      retry:
+	while (freescbs < needed) {
+		timeout = jiffies + WAITnexttimeout;
+		do {
+			/* FIXME: can we actually just yield here ?? */
+			for (now = jiffies; now == jiffies;)
+				cpu_relax();	/* wait a jiffy */
+		} while (freescbs < needed && time_before_eq(jiffies, timeout));
+		/*
+		 *  If we get here with enough free Scbs, we can take them.
+		 *  Otherwise, we timed out and didn't get enough.
+		 */
+		if (freescbs < needed) {
+			printk(KERN_ERR "wd7000: can't get enough free SCBs.\n");
+			return (NULL);
+		}
+	}
+
+	/* Take the lock, then check we didnt get beaten, if so try again */
+	spin_lock_irqsave(&scbpool_lock, flags);
 	if (freescbs < needed) {
-	    printk (KERN_ERR "wd7000: can't get enough free SCBs.\n");
-	    spin_unlock_irq(host->host_lock);
-	    return (NULL);
+		spin_unlock_irqrestore(&scbpool_lock, flags);
+		goto retry;
+	}
+
+	scb = scbfree;
+	freescbs -= needed;
+	for (i = 0; i < needed; i++) {
+		p = scbfree;
+		scbfree = p->next;
 	}
-    }
+	p->next = NULL;
 
-    /* Take the lock, then check we didnt get beaten, if so try again */
-    spin_lock_irqsave(&scbpool_lock, flags);
-    if(freescbs < needed)
-    {
-    	spin_unlock_irqrestore(&scbpool_lock, flags);
-    	goto retry;
-    }
-    	
-    scb = scbfree;
-    freescbs -= needed;
-    for (i = 0; i < needed; i++) {
-	p = scbfree;
-	scbfree = p->next;
-    }
-    p->next = NULL;
-   
-    spin_unlock_irqrestore(&scbpool_lock, flags);
+	spin_unlock_irqrestore(&scbpool_lock, flags);
 
-    spin_lock_irq(host->host_lock);
-    return (scb);
+	spin_lock_irq(host->host_lock);
+	return (scb);
 }
 
 
-static inline void free_scb (Scb *scb)
+static inline void free_scb(Scb * scb)
 {
-    register unsigned long flags;
+	register unsigned long flags;
 
-    spin_lock_irqsave(&scbpool_lock, flags);
+	spin_lock_irqsave(&scbpool_lock, flags);
 
-    memset (scb, 0, sizeof (Scb));
-    scb->next = scbfree;
-    scbfree = scb;
-    freescbs++;
+	memset(scb, 0, sizeof(Scb));
+	scb->next = scbfree;
+	scbfree = scb;
+	freescbs++;
 
-    spin_unlock_irqrestore(&scbpool_lock, flags);
+	spin_unlock_irqrestore(&scbpool_lock, flags);
 }
 
 
-static inline void init_scbs (void)
+static inline void init_scbs(void)
 {
-    int i;
+	int i;
 
-    spin_lock_init(&scbpool_lock);
+	spin_lock_init(&scbpool_lock);
 
-    /* This is only ever called before the SCB pool is active */
-    
-    scbfree = &(scbs[0]);
-    memset (scbs, 0, sizeof (scbs));
-    for (i = 0; i < MAX_SCBS - 1; i++) {
-	scbs[i].next = &(scbs[i + 1]);
-	scbs[i].SCpnt = NULL;
-    }
-    scbs[MAX_SCBS - 1].next = NULL;
-    scbs[MAX_SCBS - 1].SCpnt = NULL;
+	/* This is only ever called before the SCB pool is active */
+
+	scbfree = &(scbs[0]);
+	memset(scbs, 0, sizeof(scbs));
+	for (i = 0; i < MAX_SCBS - 1; i++) {
+		scbs[i].next = &(scbs[i + 1]);
+		scbs[i].SCpnt = NULL;
+	}
+	scbs[MAX_SCBS - 1].next = NULL;
+	scbs[MAX_SCBS - 1].SCpnt = NULL;
 }
 
 
-static int mail_out (Adapter *host, Scb *scbptr)
+static int mail_out(Adapter * host, Scb * scbptr)
 /*
  *  Note: this can also be used for ICBs; just cast to the parm type.
  */
 {
-    register int i, ogmb;
-    register unsigned long flags;
-    unchar start_ogmb;
-    Mailbox *ogmbs = host->mb.ogmb;
-    int *next_ogmb = &(host->next_ogmb);
-
-    dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
-
-    /* We first look for a free outgoing mailbox */
-    spin_lock_irqsave(host->sh->host_lock, flags);
-    ogmb = *next_ogmb;
-    for (i = 0; i < OGMB_CNT; i++) {
-	if (ogmbs[ogmb].status == 0) {
-	    dprintk(" using OGMB 0x%x", ogmb);
-	    ogmbs[ogmb].status = 1;
-	    any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
+	register int i, ogmb;
+	register unsigned long flags;
+	unchar start_ogmb;
+	Mailbox *ogmbs = host->mb.ogmb;
+	int *next_ogmb = &(host->next_ogmb);
+
+	dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
+
+	/* We first look for a free outgoing mailbox */
+	spin_lock_irqsave(host->sh->host_lock, flags);
+	ogmb = *next_ogmb;
+	for (i = 0; i < OGMB_CNT; i++) {
+		if (ogmbs[ogmb].status == 0) {
+			dprintk(" using OGMB 0x%x", ogmb);
+			ogmbs[ogmb].status = 1;
+			any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
 
-	    *next_ogmb = (ogmb + 1) % OGMB_CNT;
-	    break;
+			*next_ogmb = (ogmb + 1) % OGMB_CNT;
+			break;
+		} else
+			ogmb = (ogmb + 1) % OGMB_CNT;
 	}
-	else
-	    ogmb = (ogmb + 1) % OGMB_CNT;
-    }
-    spin_unlock_irqrestore(host->sh->host_lock, flags);
-    
-    dprintk(", scb is 0x%06lx", (long) scbptr);
+	spin_unlock_irqrestore(host->sh->host_lock, flags);
 
-    if (i >= OGMB_CNT) {
-	/*
-	 *  Alternatively, we might issue the "interrupt on free OGMB",
-	 *  and sleep, but it must be ensured that it isn't the init
-	 *  task running.  Instead, this version assumes that the caller
-	 *  will be persistent, and try again.  Since it's the adapter
-	 *  that marks OGMB's free, waiting even with interrupts off
-	 *  should work, since they are freed very quickly in most cases.
-	 */
-	dprintk(", no free OGMBs.\n");
-	return (0);
-    }
+	dprintk(", scb is 0x%06lx", (long) scbptr);
+
+	if (i >= OGMB_CNT) {
+		/*
+		 *  Alternatively, we might issue the "interrupt on free OGMB",
+		 *  and sleep, but it must be ensured that it isn't the init
+		 *  task running.  Instead, this version assumes that the caller
+		 *  will be persistent, and try again.  Since it's the adapter
+		 *  that marks OGMB's free, waiting even with interrupts off
+		 *  should work, since they are freed very quickly in most cases.
+		 */
+		dprintk(", no free OGMBs.\n");
+		return (0);
+	}
 
-    wd7000_enable_intr (host);
+	wd7000_enable_intr(host);
 
-    start_ogmb = START_OGMB | ogmb;
-    command_out (host, &start_ogmb, 1);
+	start_ogmb = START_OGMB | ogmb;
+	command_out(host, &start_ogmb, 1);
 
-    dprintk(", awaiting interrupt.\n");
+	dprintk(", awaiting interrupt.\n");
 
-    return (1);
+	return (1);
 }
 
 
-static int make_code (unsigned hosterr, unsigned scsierr)
+static int make_code(unsigned hosterr, unsigned scsierr)
 {
 #ifdef WD7000_DEBUG
-    int in_error = hosterr;
+	int in_error = hosterr;
 #endif
 
-    switch ((hosterr >> 8) & 0xff) {
-	case 0:  /* Reserved */
-                 hosterr = DID_ERROR;
-                 break;
-	case 1:  /* Command Complete, no errors */
-                 hosterr = DID_OK;
-                 break;
-	case 2:  /* Command complete, error logged in scb status (scsierr) */
-                 hosterr = DID_OK;
-                 break;
-	case 4:  /* Command failed to complete - timeout */
-                 hosterr = DID_TIME_OUT;
-                 break;
-	case 5:  /* Command terminated; Bus reset by external device */
-                 hosterr = DID_RESET;
-                 break;
-	case 6:  /* Unexpected Command Received w/ host as target */
-                 hosterr = DID_BAD_TARGET;
-                 break;
-	case 80: /* Unexpected Reselection */
-	case 81: /* Unexpected Selection */
-                 hosterr = DID_BAD_INTR;
-                 break;
-	case 82: /* Abort Command Message  */
-                 hosterr = DID_ABORT;
-                 break;
-	case 83: /* SCSI Bus Software Reset */
-	case 84: /* SCSI Bus Hardware Reset */
-                 hosterr = DID_RESET;
-                 break;
-	default: /* Reserved */
-                 hosterr = DID_ERROR;
-    }
+	switch ((hosterr >> 8) & 0xff) {
+	case 0:		/* Reserved */
+		hosterr = DID_ERROR;
+		break;
+	case 1:		/* Command Complete, no errors */
+		hosterr = DID_OK;
+		break;
+	case 2:		/* Command complete, error logged in scb status (scsierr) */
+		hosterr = DID_OK;
+		break;
+	case 4:		/* Command failed to complete - timeout */
+		hosterr = DID_TIME_OUT;
+		break;
+	case 5:		/* Command terminated; Bus reset by external device */
+		hosterr = DID_RESET;
+		break;
+	case 6:		/* Unexpected Command Received w/ host as target */
+		hosterr = DID_BAD_TARGET;
+		break;
+	case 80:		/* Unexpected Reselection */
+	case 81:		/* Unexpected Selection */
+		hosterr = DID_BAD_INTR;
+		break;
+	case 82:		/* Abort Command Message  */
+		hosterr = DID_ABORT;
+		break;
+	case 83:		/* SCSI Bus Software Reset */
+	case 84:		/* SCSI Bus Hardware Reset */
+		hosterr = DID_RESET;
+		break;
+	default:		/* Reserved */
+		hosterr = DID_ERROR;
+	}
 #ifdef WD7000_DEBUG
-    if (scsierr || hosterr)
-	dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
-		scsierr, in_error, hosterr);
+	if (scsierr || hosterr)
+		dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr, in_error, hosterr);
 #endif
-    return (scsierr | (hosterr << 16));
+	return (scsierr | (hosterr << 16));
 }
 
 
-static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
+static void wd7000_scsi_done(Scsi_Cmnd * SCpnt)
 {
-    dprintk("wd7000_scsi_done: 0x%06lx\n", (long)SCpnt);
-    SCpnt->SCp.phase = 0;
+	dprintk("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);
+	SCpnt->SCp.phase = 0;
 }
 
 
 #define wd7000_intr_ack(host)   outb (0, host->iobase + ASC_INTR_ACK)
 
-static void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
+static void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-    register int flag, icmb, errstatus, icmb_status;
-    register int host_error, scsi_error;
-    register Scb *scb;		/* for SCSI commands */
-    register IcbAny *icb;	/* for host commands */
-    register Scsi_Cmnd *SCpnt;
-    Adapter *host = (Adapter *)dev_id;
-    Mailbox *icmbs = host->mb.icmb;
-
-    host->int_counter++;
-
-    dprintk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
-
-    flag = inb (host->iobase + ASC_INTR_STAT);
-
-    dprintk("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
-
-    if (!(inb (host->iobase + ASC_STAT) & INT_IM)) {
-	/* NB: these are _very_ possible if IRQ 15 is being used, since
-	 * it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,
-	 * any interrupt signal into the 8259 which can't be identified
-	 * comes out as 7 from the 8259, which is 15 to the host.  Thus, it
-	 * is a good thing the WD7000 has an interrupt status port, so we
-	 * can sort these out.  Otherwise, electrical noise and other such
-	 * problems would be indistinguishable from valid interrupts...
-	 */
-	dprintk("wd7000_intr_handle: phantom interrupt...\n");
-	wd7000_intr_ack (host);
-	return;
-    }
-
-    if (flag & MB_INTR) {
-	/* The interrupt is for a mailbox */
-	if (!(flag & IMB_INTR)) {
-	    dprintk("wd7000_intr_handle: free outgoing mailbox\n");
-	    /*
-	     * If sleep_on() and the "interrupt on free OGMB" command are
-	     * used in mail_out(), wake_up() should correspondingly be called
-	     * here.  For now, we don't need to do anything special.
-	     */
-	    wd7000_intr_ack (host);
-	    return;
-	}
-	else {
-	    /* The interrupt is for an incoming mailbox */
-	    icmb = flag & MB_MASK;
-	    icmb_status = icmbs[icmb].status;
-	    if (icmb_status & 0x80) {	/* unsolicited - result in ICMB */
-		dprintk("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
-			icmb_status);
-		wd7000_intr_ack (host);
+	register int flag, icmb, errstatus, icmb_status;
+	register int host_error, scsi_error;
+	register Scb *scb;	/* for SCSI commands */
+	register IcbAny *icb;	/* for host commands */
+	register Scsi_Cmnd *SCpnt;
+	Adapter *host = (Adapter *) dev_id;
+	Mailbox *icmbs = host->mb.icmb;
+
+	host->int_counter++;
+
+	dprintk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
+
+	flag = inb(host->iobase + ASC_INTR_STAT);
+
+	dprintk("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
+
+	if (!(inb(host->iobase + ASC_STAT) & INT_IM)) {
+		/* NB: these are _very_ possible if IRQ 15 is being used, since
+		 * it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,
+		 * any interrupt signal into the 8259 which can't be identified
+		 * comes out as 7 from the 8259, which is 15 to the host.  Thus, it
+		 * is a good thing the WD7000 has an interrupt status port, so we
+		 * can sort these out.  Otherwise, electrical noise and other such
+		 * problems would be indistinguishable from valid interrupts...
+		 */
+		dprintk("wd7000_intr_handle: phantom interrupt...\n");
+		wd7000_intr_ack(host);
 		return;
-	    }
-	    /* Aaaargh! (Zaga) */
-	    scb = isa_bus_to_virt(scsi2int ((unchar *) icmbs[icmb].scbptr));
-	    icmbs[icmb].status = 0;
-	    if (!(scb->op & ICB_OP_MASK)) {	/* an SCB is done */
-		SCpnt = scb->SCpnt;
-		if (--(SCpnt->SCp.phase) <= 0) {	/* all scbs are done */
-		    host_error = scb->vue | (icmb_status << 8);
-		    scsi_error = scb->status;
-		    errstatus = make_code (host_error, scsi_error);
-		    SCpnt->result = errstatus;
-
-		    free_scb (scb);
+	}
 
-		    SCpnt->scsi_done (SCpnt);
-		}
-	    }
-	    else {		/* an ICB is done */
-		icb = (IcbAny *) scb;
-		icb->status = icmb_status;
-		icb->phase = 0;
-	    }
-	}			/* incoming mailbox */
-    }
+	if (flag & MB_INTR) {
+		/* The interrupt is for a mailbox */
+		if (!(flag & IMB_INTR)) {
+			dprintk("wd7000_intr_handle: free outgoing mailbox\n");
+			/*
+			 * If sleep_on() and the "interrupt on free OGMB" command are
+			 * used in mail_out(), wake_up() should correspondingly be called
+			 * here.  For now, we don't need to do anything special.
+			 */
+			wd7000_intr_ack(host);
+			return;
+		} else {
+			/* The interrupt is for an incoming mailbox */
+			icmb = flag & MB_MASK;
+			icmb_status = icmbs[icmb].status;
+			if (icmb_status & 0x80) {	/* unsolicited - result in ICMB */
+				dprintk("wd7000_intr_handle: unsolicited interrupt 0x%02x\n", icmb_status);
+				wd7000_intr_ack(host);
+				return;
+			}
+			/* Aaaargh! (Zaga) */
+			scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr));
+			icmbs[icmb].status = 0;
+			if (!(scb->op & ICB_OP_MASK)) {	/* an SCB is done */
+				SCpnt = scb->SCpnt;
+				if (--(SCpnt->SCp.phase) <= 0) {	/* all scbs are done */
+					host_error = scb->vue | (icmb_status << 8);
+					scsi_error = scb->status;
+					errstatus = make_code(host_error, scsi_error);
+					SCpnt->result = errstatus;
+
+					free_scb(scb);
+
+					SCpnt->scsi_done(SCpnt);
+				}
+			} else {	/* an ICB is done */
+				icb = (IcbAny *) scb;
+				icb->status = icmb_status;
+				icb->phase = 0;
+			}
+		}		/* incoming mailbox */
+	}
 
-    wd7000_intr_ack (host);
+	wd7000_intr_ack(host);
 
-    dprintk("wd7000_intr_handle: return from interrupt handler\n");
+	dprintk("wd7000_intr_handle: return from interrupt handler\n");
 }
 
-static void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
+static void do_wd7000_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
-    unsigned long flags;
-    struct Scsi_Host *host = dev_id;
+	unsigned long flags;
+	struct Scsi_Host *host = dev_id;
 
-    spin_lock_irqsave(host->host_lock, flags);
-    wd7000_intr_handle(irq, dev_id, regs);
-    spin_unlock_irqrestore(host->host_lock, flags);
+	spin_lock_irqsave(host->host_lock, flags);
+	wd7000_intr_handle(irq, dev_id, regs);
+	spin_unlock_irqrestore(host->host_lock, flags);
 }
 
 
-static int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *))
+static int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
-    register Scb *scb;
-    register Sgb *sgb;
-    register unchar *cdb = (unchar *) SCpnt->cmnd;
-    register unchar idlun;
-    register short cdblen;
-    Adapter *host = (Adapter *) SCpnt->host->hostdata;
-
-    cdblen = SCpnt->cmd_len;
-    idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
-    SCpnt->scsi_done = done;
-    SCpnt->SCp.phase = 1;
-    scb = alloc_scbs(SCpnt->host, 1);
-    scb->idlun = idlun;
-    memcpy (scb->cdb, cdb, cdblen);
-    scb->direc = 0x40;		/* Disable direction check */
+	register Scb *scb;
+	register Sgb *sgb;
+	register unchar *cdb = (unchar *) SCpnt->cmnd;
+	register unchar idlun;
+	register short cdblen;
+	Adapter *host = (Adapter *) SCpnt->host->hostdata;
 
-    scb->SCpnt = SCpnt;		/* so we can find stuff later */
-    SCpnt->host_scribble = (unchar *) scb;
-    scb->host = host;
+	cdblen = SCpnt->cmd_len;
+	idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
+	SCpnt->scsi_done = done;
+	SCpnt->SCp.phase = 1;
+	scb = alloc_scbs(SCpnt->host, 1);
+	scb->idlun = idlun;
+	memcpy(scb->cdb, cdb, cdblen);
+	scb->direc = 0x40;	/* Disable direction check */
 
-    if (SCpnt->use_sg) {
-	struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
-	unsigned i;
+	scb->SCpnt = SCpnt;	/* so we can find stuff later */
+	SCpnt->host_scribble = (unchar *) scb;
+	scb->host = host;
 
-	if (SCpnt->host->sg_tablesize == SG_NONE) {
-	    panic ("wd7000_queuecommand: scatter/gather not supported.\n");
-	}
-	dprintk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
+	if (SCpnt->use_sg) {
+		struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+		unsigned i;
 
-	sgb = scb->sgb;
-	scb->op = 1;
-	any2scsi (scb->dataptr, (int) sgb);
-	any2scsi (scb->maxlen, SCpnt->use_sg * sizeof (Sgb));
+		if (SCpnt->host->sg_tablesize == SG_NONE) {
+			panic("wd7000_queuecommand: scatter/gather not supported.\n");
+		}
+		dprintk("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
 
-	for (i = 0; i < SCpnt->use_sg; i++) {
-	    any2scsi (sgb[i].ptr,
-		      isa_page_to_bus(sg[i].page) + sg[i].offset);
-	    any2scsi (sgb[i].len, sg[i].length);
+		sgb = scb->sgb;
+		scb->op = 1;
+		any2scsi(scb->dataptr, (int) sgb);
+		any2scsi(scb->maxlen, SCpnt->use_sg * sizeof(Sgb));
+
+		for (i = 0; i < SCpnt->use_sg; i++) {
+			any2scsi(sgb[i].ptr, isa_page_to_bus(sg[i].page) + sg[i].offset);
+			any2scsi(sgb[i].len, sg[i].length);
+		}
+	} else {
+		scb->op = 0;
+		any2scsi(scb->dataptr, isa_virt_to_bus(SCpnt->request_buffer));
+		any2scsi(scb->maxlen, SCpnt->request_bufflen);
 	}
-    }
-    else {
-	scb->op = 0;
-	any2scsi (scb->dataptr, isa_virt_to_bus(SCpnt->request_buffer));
-	any2scsi (scb->maxlen, SCpnt->request_bufflen);
-    }
-    
-    /* FIXME: drop lock and yield here ? */
 
-    while (!mail_out (host, scb))
-    	cpu_relax();	/* keep trying */
+	/* FIXME: drop lock and yield here ? */
+
+	while (!mail_out(host, scb))
+		cpu_relax();	/* keep trying */
 
-    return 0;
+	return 0;
 }
 
 
-static int wd7000_command (Scsi_Cmnd *SCpnt)
+static int wd7000_command(Scsi_Cmnd * SCpnt)
 {
-    wd7000_queuecommand (SCpnt, wd7000_scsi_done);
+	wd7000_queuecommand(SCpnt, wd7000_scsi_done);
 
-    while (SCpnt->SCp.phase > 0)
-    {
-    	cpu_relax();
-	barrier();		/* phase counts scbs down to 0 */
-    }
+	while (SCpnt->SCp.phase > 0) {
+		cpu_relax();
+		barrier();	/* phase counts scbs down to 0 */
+	}
 
-    return (SCpnt->result);
+	return (SCpnt->result);
 }
 
 
-static int wd7000_diagnostics (Adapter *host, int code)
+static int wd7000_diagnostics(Adapter * host, int code)
 {
-    static IcbDiag icb = {ICB_OP_DIAGNOSTICS};
-    static unchar buf[256];
-    unsigned long timeout;
+	static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
+	static unchar buf[256];
+	unsigned long timeout;
 
-    icb.type = code;
-    any2scsi (icb.len, sizeof (buf));
-    any2scsi (icb.ptr, (int) &buf);
-    icb.phase = 1;
-    /*
-     * This routine is only called at init, so there should be OGMBs
-     * available.  I'm assuming so here.  If this is going to
-     * fail, I can just let the timeout catch the failure.
-     */
-    mail_out (host, (struct scb *) &icb);
-    timeout = jiffies + WAITnexttimeout;	/* wait up to 2 seconds */
-    while (icb.phase && time_before(jiffies, timeout))
-    {
-	cpu_relax();		/* wait for completion */
-	barrier();
-    }
+	icb.type = code;
+	any2scsi(icb.len, sizeof(buf));
+	any2scsi(icb.ptr, (int) &buf);
+	icb.phase = 1;
+	/*
+	 * This routine is only called at init, so there should be OGMBs
+	 * available.  I'm assuming so here.  If this is going to
+	 * fail, I can just let the timeout catch the failure.
+	 */
+	mail_out(host, (struct scb *) &icb);
+	timeout = jiffies + WAITnexttimeout;	/* wait up to 2 seconds */
+	while (icb.phase && time_before(jiffies, timeout)) {
+		cpu_relax();	/* wait for completion */
+		barrier();
+	}
 
-    if (icb.phase) {
-	printk ("wd7000_diagnostics: timed out.\n");
-	return (0);
-    }
-    if (make_code (icb.vue | (icb.status << 8), 0)) {
-	printk ("wd7000_diagnostics: failed (0x%02x,0x%02x)\n",
-		icb.vue, icb.status);
-	return (0);
-    }
+	if (icb.phase) {
+		printk("wd7000_diagnostics: timed out.\n");
+		return (0);
+	}
+	if (make_code(icb.vue | (icb.status << 8), 0)) {
+		printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", icb.vue, icb.status);
+		return (0);
+	}
 
-    return (1);
+	return (1);
 }
 
 
-static int wd7000_adapter_reset(Adapter *host)
+static int wd7000_adapter_reset(Adapter * host)
 {
-    InitCmd init_cmd =
-    {
-	INITIALIZATION,
- 	7,
-	host->bus_on,
-	host->bus_off,
-	0,
-	{ 0, 0, 0 },
-	OGMB_CNT,
-	ICMB_CNT
-    };
-    int diag;
-    /*
-     *  Reset the adapter - only.  The SCSI bus was initialized at power-up,
-     *  and we need to do this just so we control the mailboxes, etc.
-     */
-    outb (ASC_RES, host->iobase + ASC_CONTROL);
-    udelay(40);			/* reset pulse: this is 40us, only need 25us */
-    outb (0, host->iobase + ASC_CONTROL);
-    host->control = 0;		/* this must always shadow ASC_CONTROL */
-
-    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
-	printk ("wd7000_init: WAIT timed out.\n");
-	return -1;		/* -1 = not ok */
-    }
-
-    if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) {
-	printk ("wd7000_init: ");
-
-	switch (diag) {
-	    case 2:  printk ("RAM failure.\n");
-		     break;
-	    case 3:  printk ("FIFO R/W failed\n");
-		     break;
-	    case 4:  printk ("SBIC register R/W failed\n");
-		     break;
-	    case 5:  printk ("Initialization D-FF failed.\n");
-		     break;
-	    case 6:  printk ("Host IRQ D-FF failed.\n");
-		     break;
-	    case 7:  printk ("ROM checksum error.\n");
-		     break;
-	    default: printk ("diagnostic code 0x%02Xh received.\n", diag);
-	}
-	return -1;
-    }
-   /* Clear mailboxes */
-    memset (&(host->mb), 0, sizeof (host->mb));
-
-    /* Execute init command */
-    any2scsi ((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
-    if (!command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) {
-	printk (KERN_ERR "wd7000_adapter_reset: adapter initialization failed.\n");
-	return -1;
-    }
-
-    if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
-	printk ("wd7000_adapter_reset: WAIT timed out.\n");
-	return -1;
-    }
-    return 0;
-}
-
-static int wd7000_init (Adapter *host)
-{
-    if(wd7000_adapter_reset(host) == -1)
-    	return 0;
-
- 
-    if (request_irq (host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", host)) {
-	printk ("wd7000_init: can't get IRQ %d.\n", host->irq);
-	return (0);
-    }
-    if (request_dma (host->dma, "wd7000")) {
-	printk ("wd7000_init: can't get DMA channel %d.\n", host->dma);
-	free_irq (host->irq, host);
-	return (0);
-    }
-    wd7000_enable_dma (host);
-    wd7000_enable_intr (host);
-
-    if (!wd7000_diagnostics (host, ICB_DIAG_FULL)) {
-	free_dma (host->dma);
-	free_irq (host->irq, NULL);
-	return (0);
-    }
+	InitCmd init_cmd = {
+		INITIALIZATION,
+		7,
+		host->bus_on,
+		host->bus_off,
+		0,
+		{0, 0, 0},
+		OGMB_CNT,
+		ICMB_CNT
+	};
+	int diag;
+	/*
+	 *  Reset the adapter - only.  The SCSI bus was initialized at power-up,
+	 *  and we need to do this just so we control the mailboxes, etc.
+	 */
+	outb(ASC_RES, host->iobase + ASC_CONTROL);
+	udelay(40);		/* reset pulse: this is 40us, only need 25us */
+	outb(0, host->iobase + ASC_CONTROL);
+	host->control = 0;	/* this must always shadow ASC_CONTROL */
+
+	if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+		printk("wd7000_init: WAIT timed out.\n");
+		return -1;	/* -1 = not ok */
+	}
+
+	if ((diag = inb(host->iobase + ASC_INTR_STAT)) != 1) {
+		printk("wd7000_init: ");
+
+		switch (diag) {
+		case 2:
+			printk("RAM failure.\n");
+			break;
+		case 3:
+			printk("FIFO R/W failed\n");
+			break;
+		case 4:
+			printk("SBIC register R/W failed\n");
+			break;
+		case 5:
+			printk("Initialization D-FF failed.\n");
+			break;
+		case 6:
+			printk("Host IRQ D-FF failed.\n");
+			break;
+		case 7:
+			printk("ROM checksum error.\n");
+			break;
+		default:
+			printk("diagnostic code 0x%02Xh received.\n", diag);
+		}
+		return -1;
+	}
+	/* Clear mailboxes */
+	memset(&(host->mb), 0, sizeof(host->mb));
+
+	/* Execute init command */
+	any2scsi((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
+	if (!command_out(host, (unchar *) & init_cmd, sizeof(init_cmd))) {
+		printk(KERN_ERR "wd7000_adapter_reset: adapter initialization failed.\n");
+		return -1;
+	}
+
+	if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
+		printk("wd7000_adapter_reset: WAIT timed out.\n");
+		return -1;
+	}
+	return 0;
+}
 
-    return (1);
+static int wd7000_init(Adapter * host)
+{
+	if (wd7000_adapter_reset(host) == -1)
+		return 0;
+
+
+	if (request_irq(host->irq, do_wd7000_intr_handle, SA_INTERRUPT, "wd7000", host)) {
+		printk("wd7000_init: can't get IRQ %d.\n", host->irq);
+		return (0);
+	}
+	if (request_dma(host->dma, "wd7000")) {
+		printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
+		free_irq(host->irq, host);
+		return (0);
+	}
+	wd7000_enable_dma(host);
+	wd7000_enable_intr(host);
+
+	if (!wd7000_diagnostics(host, ICB_DIAG_FULL)) {
+		free_dma(host->dma);
+		free_irq(host->irq, NULL);
+		return (0);
+	}
+
+	return (1);
 }
 
 
-static void wd7000_revision (Adapter *host)
+static void wd7000_revision(Adapter * host)
 {
-    static IcbRevLvl icb =
-    {ICB_OP_GET_REVISION};
-
-    icb.phase = 1;
-    /*
-     * Like diagnostics, this is only done at init time, in fact, from
-     * wd7000_detect, so there should be OGMBs available.  If it fails,
-     * the only damage will be that the revision will show up as 0.0,
-     * which in turn means that scatter/gather will be disabled.
-     */
-    mail_out (host, (struct scb *) &icb);
-    while (icb.phase)
-    {
-	cpu_relax();		/* wait for completion */
-	barrier();
-    }
-    host->rev1 = icb.primary;
-    host->rev2 = icb.secondary;
+	static IcbRevLvl icb = { ICB_OP_GET_REVISION };
+
+	icb.phase = 1;
+	/*
+	 * Like diagnostics, this is only done at init time, in fact, from
+	 * wd7000_detect, so there should be OGMBs available.  If it fails,
+	 * the only damage will be that the revision will show up as 0.0,
+	 * which in turn means that scatter/gather will be disabled.
+	 */
+	mail_out(host, (struct scb *) &icb);
+	while (icb.phase) {
+		cpu_relax();	/* wait for completion */
+		barrier();
+	}
+	host->rev1 = icb.primary;
+	host->rev2 = icb.secondary;
 }
 
 
 #undef SPRINTF
 #define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
 
-static int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host)
+static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host)
 {
-    dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
+	dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
 
-    /*
-     * Currently this is a no-op
-     */
-    dprintk("Sorry, this function is currently out of order...\n");
-    return (length);
+	/*
+	 * Currently this is a no-op
+	 */
+	dprintk("Sorry, this function is currently out of order...\n");
+	return (length);
 }
 
 
-static int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+static int wd7000_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
 {
-    struct Scsi_Host *host = NULL;
-    Scsi_Device *scd;
-    Adapter *adapter;
-    unsigned long flags;
-    char *pos = buffer;
-    short i;
+	struct Scsi_Host *host = NULL;
+	Scsi_Device *scd;
+	Adapter *adapter;
+	unsigned long flags;
+	char *pos = buffer;
+	short i;
 
 #ifdef WD7000_DEBUG
-    Mailbox *ogmbs, *icmbs;
-    short count;
+	Mailbox *ogmbs, *icmbs;
+	short count;
 #endif
 
-    /*
-     * Find the specified host board.
-     */
-    for (i = 0; i < UNITS; i++)
-	if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
-	    host = wd7000_host[i];
-
-	    break;
-	}
-
-    /*
-     * Host not found!
-     */
-    if (! host)
-	return (-ESRCH);
-
-    /*
-     * Has data been written to the file ?
-     */
-    if (inout)
-	return (wd7000_set_info (buffer, length, host));
-
-    adapter = (Adapter *) host->hostdata;
-
-    spin_lock_irqsave(host->host_lock, flags);
-    SPRINTF ("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2);
-    SPRINTF ("  IO base:      0x%x\n", adapter->iobase);
-    SPRINTF ("  IRQ:          %d\n", adapter->irq);
-    SPRINTF ("  DMA channel:  %d\n", adapter->dma);
-    SPRINTF ("  Interrupts:   %d\n", adapter->int_counter);
-    SPRINTF ("  BUS_ON time:  %d nanoseconds\n", adapter->bus_on * 125);
-    SPRINTF ("  BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
+	/*
+	 * Find the specified host board.
+	 */
+	for (i = 0; i < UNITS; i++)
+		if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
+			host = wd7000_host[i];
 
-#ifdef WD7000_DEBUG
-    ogmbs = adapter->mb.ogmb;
-    icmbs = adapter->mb.icmb;
+			break;
+		}
 
-    SPRINTF ("\nControl port value: 0x%x\n", adapter->control);
-    SPRINTF ("Incoming mailbox:\n");
-    SPRINTF ("  size: %d\n", ICMB_CNT);
-    SPRINTF ("  queued messages: ");
+	/*
+	 * Host not found!
+	 */
+	if (!host)
+		return (-ESRCH);
 
-    for (i = count = 0; i < ICMB_CNT; i++)
-	if (icmbs[i].status) {
-	    count++;
-	    SPRINTF ("0x%x ", i);
-	}
+	/*
+	 * Has data been written to the file ?
+	 */
+	if (inout)
+		return (wd7000_set_info(buffer, length, host));
 
-    SPRINTF (count ? "\n" : "none\n");
+	adapter = (Adapter *) host->hostdata;
 
-    SPRINTF ("Outgoing mailbox:\n");
-    SPRINTF ("  size: %d\n", OGMB_CNT);
-    SPRINTF ("  next message: 0x%x\n", adapter->next_ogmb);
-    SPRINTF ("  queued messages: ");
+	spin_lock_irqsave(host->host_lock, flags);
+	SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2);
+	SPRINTF("  IO base:      0x%x\n", adapter->iobase);
+	SPRINTF("  IRQ:          %d\n", adapter->irq);
+	SPRINTF("  DMA channel:  %d\n", adapter->dma);
+	SPRINTF("  Interrupts:   %d\n", adapter->int_counter);
+	SPRINTF("  BUS_ON time:  %d nanoseconds\n", adapter->bus_on * 125);
+	SPRINTF("  BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
 
-    for (i = count = 0; i < OGMB_CNT; i++)
-	if (ogmbs[i].status) {
-	    count++;
-	    SPRINTF ("0x%x ", i);
-	}
+#ifdef WD7000_DEBUG
+	ogmbs = adapter->mb.ogmb;
+	icmbs = adapter->mb.icmb;
+
+	SPRINTF("\nControl port value: 0x%x\n", adapter->control);
+	SPRINTF("Incoming mailbox:\n");
+	SPRINTF("  size: %d\n", ICMB_CNT);
+	SPRINTF("  queued messages: ");
+
+	for (i = count = 0; i < ICMB_CNT; i++)
+		if (icmbs[i].status) {
+			count++;
+			SPRINTF("0x%x ", i);
+		}
+
+	SPRINTF(count ? "\n" : "none\n");
 
-    SPRINTF (count ? "\n" : "none\n");
+	SPRINTF("Outgoing mailbox:\n");
+	SPRINTF("  size: %d\n", OGMB_CNT);
+	SPRINTF("  next message: 0x%x\n", adapter->next_ogmb);
+	SPRINTF("  queued messages: ");
+
+	for (i = count = 0; i < OGMB_CNT; i++)
+		if (ogmbs[i].status) {
+			count++;
+			SPRINTF("0x%x ", i);
+		}
+
+	SPRINTF(count ? "\n" : "none\n");
 #endif
 
-    /*
-     * Display driver information for each device attached to the board.
-     */
-    scd = host->host_queue;
-   
-    SPRINTF ("\nAttached devices: %s\n", scd ? "" : "none");
-
-    for ( ; scd; scd = scd->next)
-	if (scd->host->host_no == hostno) {
-	    SPRINTF ("  [Channel: %02d, Id: %02d, Lun: %02d]  ",
-		     scd->channel, scd->id, scd->lun);
-	    SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
-		     scsi_device_types[(short) scd->type] : "Unknown device");
-
-	    for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
-		SPRINTF ("%c", scd->vendor[i]);
-	    SPRINTF (" ");
-
-	    for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
-		SPRINTF ("%c", scd->model[i]);
-	    SPRINTF ("\n");
-	}
-
-    SPRINTF ("\n");
-
-    spin_unlock_irqrestore(host->host_lock, flags);
-
-    /*
-     * Calculate start of next buffer, and return value.
-     */
-    *start = buffer + offset;
+	/*
+	 * Display driver information for each device attached to the board.
+	 */
+	scd = host->host_queue;
 
-    if ((pos - buffer) < offset)
-	return (0);
-    else if ((pos - buffer - offset) < length)
-	return (pos - buffer - offset);
-    else
-	return (length);
+	SPRINTF("\nAttached devices: %s\n", scd ? "" : "none");
+
+	for (; scd; scd = scd->next)
+		if (scd->host->host_no == hostno) {
+			SPRINTF("  [Channel: %02d, Id: %02d, Lun: %02d]  ", scd->channel, scd->id, scd->lun);
+			SPRINTF("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(short) scd->type] : "Unknown device");
+
+			for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
+				SPRINTF("%c", scd->vendor[i]);
+			SPRINTF(" ");
+
+			for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
+				SPRINTF("%c", scd->model[i]);
+			SPRINTF("\n");
+		}
+
+	SPRINTF("\n");
+
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	/*
+	 * Calculate start of next buffer, and return value.
+	 */
+	*start = buffer + offset;
+
+	if ((pos - buffer) < offset)
+		return (0);
+	else if ((pos - buffer - offset) < length)
+		return (pos - buffer - offset);
+	else
+		return (length);
 }
 
 
@@ -1515,191 +1481,181 @@
  *
  */
 
-static int wd7000_detect (Scsi_Host_Template *tpnt)
+static int wd7000_detect(Scsi_Host_Template * tpnt)
 {
-    short present = 0, biosaddr_ptr, sig_ptr, i, pass;
-    short biosptr[NUM_CONFIGS];
-    unsigned iobase;
-    Adapter *host = NULL;
-    struct Scsi_Host *sh;
-    int unit = 0;
+	short present = 0, biosaddr_ptr, sig_ptr, i, pass;
+	short biosptr[NUM_CONFIGS];
+	unsigned iobase;
+	Adapter *host = NULL;
+	struct Scsi_Host *sh;
+	int unit = 0;
 
-    dprintk("wd7000_detect: started\n");
+	dprintk("wd7000_detect: started\n");
 
 #ifdef MODULE
 	if (wd7000)
-		wd7000_setup(wd7000);     
+		wd7000_setup(wd7000);
 #endif
 
-    for (i = 0; i < UNITS; wd7000_host[i++] = NULL) ;
-    for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1) ;
-
-    tpnt->proc_name = "wd7000";
-    tpnt->proc_info = &wd7000_proc_info;
+	for (i = 0; i < UNITS; wd7000_host[i++] = NULL);
+	for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
 
-    /*
-     * Set up SCB free list, which is shared by all adapters
-     */
-    init_scbs ();
+	tpnt->proc_name = "wd7000";
+	tpnt->proc_info = &wd7000_proc_info;
 
-    for (pass = 0; pass < NUM_CONFIGS; pass++) {
 	/*
-	 * First, search for BIOS SIGNATURE...
+	 * Set up SCB free list, which is shared by all adapters
 	 */
-	for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
-	    for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
-		for (i = 0; i < pass; i++)
-		    if (biosptr[i] == biosaddr_ptr)
-			break;
-
-		if (i == pass) {
-		    void *biosaddr = ioremap (wd7000_biosaddr[biosaddr_ptr] +
-			                      signatures[sig_ptr].ofs,
-					      signatures[sig_ptr].len);
-		    short bios_match=0;
-		    
-		    if(biosaddr)
-		    	bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig,
-			                       signatures[sig_ptr].len);
-
-		    iounmap (biosaddr);
+	init_scbs();
 
-		    if (! bios_match)
-		        goto bios_matched;
-		}
-	    }
+	for (pass = 0; pass < NUM_CONFIGS; pass++) {
+		/*
+		 * First, search for BIOS SIGNATURE...
+		 */
+		for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
+			for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
+				for (i = 0; i < pass; i++)
+					if (biosptr[i] == biosaddr_ptr)
+						break;
+
+				if (i == pass) {
+					void *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs,
+								 signatures[sig_ptr].len);
+					short bios_match = 0;
+
+					if (biosaddr)
+						bios_match = memcmp((char *) biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len);
+
+					iounmap(biosaddr);
+
+					if (!bios_match)
+						goto bios_matched;
+				}
+			}
 
-      bios_matched:
-	/*
-	 * BIOS SIGNATURE has been found.
-	 */
+	      bios_matched:
+		/*
+		 * BIOS SIGNATURE has been found.
+		 */
 #ifdef WD7000_DEBUG
-	dprintk("wd7000_detect: pass %d\n", pass + 1);
+		dprintk("wd7000_detect: pass %d\n", pass + 1);
 
-	if (biosaddr_ptr == NUM_ADDRS)
-	    dprintk("WD-7000 SST BIOS not detected...\n");
-	else
-	    dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
-		    wd7000_biosaddr[biosaddr_ptr]);
+		if (biosaddr_ptr == NUM_ADDRS)
+			dprintk("WD-7000 SST BIOS not detected...\n");
+		else
+			dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]);
 #endif
 
-	if (configs[pass].irq < 0)
-	    continue;
-	    
-	if (unit == UNITS)
-	    continue;
-
-	iobase = configs[pass].iobase;
-
-	dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
-
-	if (request_region (iobase, 4, "wd7000")) {
-
-	    dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
-	    /*
-	     * ASC reset...
-	     */
-	    outb (ASC_RES, iobase + ASC_CONTROL);
-	    set_current_state(TASK_UNINTERRUPTIBLE);
-	    schedule_timeout(HZ/100);
-	    outb (0, iobase + ASC_CONTROL);
-
-	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
-		dprintk("failed!\n");
-		goto err_release;
-	    } else 
-		dprintk("ok!\n");
+		if (configs[pass].irq < 0)
+			continue;
 
-	    if (inb (iobase + ASC_INTR_STAT) == 1) {
-		/*
-		 *  We register here, to get a pointer to the extra space,
-		 *  which we'll use as the Adapter structure (host) for
-		 *  this adapter.  It is located just after the registered
-		 *  Scsi_Host structure (sh), and is located by the empty
-		 *  array hostdata.
-		 */
-		sh = scsi_register (tpnt, sizeof (Adapter));
-		if(sh==NULL)
-		    goto err_release;
-
-		host = (Adapter *) sh->hostdata;
-
-		dprintk("wd7000_detect: adapter allocated at 0x%x\n",
-			(int)host);
-		memset (host, 0, sizeof (Adapter));
-
-		host->irq = configs[pass].irq;
-		host->dma = configs[pass].dma;
-		host->iobase = iobase;
-		host->int_counter = 0;
-		host->bus_on = configs[pass].bus_on;
-		host->bus_off = configs[pass].bus_off;
-		host->sh = wd7000_host[unit] = sh;
-		unit++;
-
-		dprintk("wd7000_detect: Trying init WD-7000 card at IO "
-			"0x%x, IRQ %d, DMA %d...\n",
-			host->iobase, host->irq, host->dma);
+		if (unit == UNITS)
+			continue;
 
-		if (!wd7000_init (host)) 	/* Initialization failed */
-		    goto err_unregister;
+		iobase = configs[pass].iobase;
 
-		/*
-		 *  OK from here - we'll use this adapter/configuration.
-		 */
-		wd7000_revision (host);		/* important for scatter/gather */
-
-		/*
-		 *  For boards before rev 6.0, scatter/gather isn't supported.
-		 */
-		if (host->rev1 < 6)
-		    sh->sg_tablesize = SG_NONE;
+		dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
+
+		if (request_region(iobase, 4, "wd7000")) {
+
+			dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
+			/*
+			 * ASC reset...
+			 */
+			outb(ASC_RES, iobase + ASC_CONTROL);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ / 100);
+			outb(0, iobase + ASC_CONTROL);
+
+			if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+				dprintk("failed!\n");
+				goto err_release;
+			} else
+				dprintk("ok!\n");
 
-		present++;	/* count it */
+			if (inb(iobase + ASC_INTR_STAT) == 1) {
+				/*
+				 *  We register here, to get a pointer to the extra space,
+				 *  which we'll use as the Adapter structure (host) for
+				 *  this adapter.  It is located just after the registered
+				 *  Scsi_Host structure (sh), and is located by the empty
+				 *  array hostdata.
+				 */
+				sh = scsi_register(tpnt, sizeof(Adapter));
+				if (sh == NULL)
+					goto err_release;
+
+				host = (Adapter *) sh->hostdata;
+
+				dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
+				memset(host, 0, sizeof(Adapter));
+
+				host->irq = configs[pass].irq;
+				host->dma = configs[pass].dma;
+				host->iobase = iobase;
+				host->int_counter = 0;
+				host->bus_on = configs[pass].bus_on;
+				host->bus_off = configs[pass].bus_off;
+				host->sh = wd7000_host[unit] = sh;
+				unit++;
+
+				dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma);
+
+				if (!wd7000_init(host))	/* Initialization failed */
+					goto err_unregister;
+
+				/*
+				 *  OK from here - we'll use this adapter/configuration.
+				 */
+				wd7000_revision(host);	/* important for scatter/gather */
+
+				/*
+				 *  For boards before rev 6.0, scatter/gather isn't supported.
+				 */
+				if (host->rev1 < 6)
+					sh->sg_tablesize = SG_NONE;
+
+				present++;	/* count it */
+
+				if (biosaddr_ptr != NUM_ADDRS)
+					biosptr[pass] = biosaddr_ptr;
+
+				printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2);
+				printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma);
+				printk("  BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125);
+			}
+		} else
+			dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
 
-		if (biosaddr_ptr != NUM_ADDRS)
-		    biosptr[pass] = biosaddr_ptr;
+		continue;
 
-		printk (KERN_INFO "Western Digital WD-7000 (rev %d.%d) ",
-			host->rev1, host->rev2);
-		printk ("using IO 0x%x, IRQ %d, DMA %d.\n",
-			host->iobase, host->irq, host->dma);
-                printk ("  BUS_ON time: %dns, BUS_OFF time: %dns\n",
-                        host->bus_on * 125, host->bus_off * 125);
-	    }
-	} else
-		dprintk("wd7000_detect: IO 0x%x region already allocated!\n",
-			iobase);
-
-	continue;
-
-    err_unregister:
-	scsi_unregister (sh);
-    err_release:
-	release_region(iobase, 4);
+	      err_unregister:
+		scsi_unregister(sh);
+	      err_release:
+		release_region(iobase, 4);
 
-    }
+	}
 
-    if (!present)
-	printk ("Failed initialization of WD-7000 SCSI card!\n");
+	if (!present)
+		printk("Failed initialization of WD-7000 SCSI card!\n");
 
-    return (present);
+	return (present);
 }
 
 
 /*
  *  I have absolutely NO idea how to do an abort with the WD7000...
  */
-static int wd7000_abort (Scsi_Cmnd *SCpnt)
+static int wd7000_abort(Scsi_Cmnd * SCpnt)
 {
-    Adapter *host = (Adapter *) SCpnt->host->hostdata;
+	Adapter *host = (Adapter *) SCpnt->host->hostdata;
 
-    if (inb (host->iobase + ASC_STAT) & INT_IM) {
-	printk ("wd7000_abort: lost interrupt\n");
-	wd7000_intr_handle (host->irq, NULL, NULL);
+	if (inb(host->iobase + ASC_STAT) & INT_IM) {
+		printk("wd7000_abort: lost interrupt\n");
+		wd7000_intr_handle(host->irq, NULL, NULL);
+		return FAILED;
+	}
 	return FAILED;
-    }
-    return FAILED;
 }
 
 
@@ -1707,28 +1663,28 @@
  *  I also have no idea how to do a reset...
  */
 
-static int wd7000_bus_reset (Scsi_Cmnd *SCpnt)
+static int wd7000_bus_reset(Scsi_Cmnd * SCpnt)
 {
-    return FAILED;
+	return FAILED;
 }
 
-static int wd7000_device_reset (Scsi_Cmnd *SCpnt)
+static int wd7000_device_reset(Scsi_Cmnd * SCpnt)
 {
-    return FAILED;
+	return FAILED;
 }
 
 /*
  *  Last resort. Reinitialize the board.
  */
- 
-static int wd7000_host_reset (Scsi_Cmnd *SCpnt)
+
+static int wd7000_host_reset(Scsi_Cmnd * SCpnt)
 {
-    Adapter *host = (Adapter *) SCpnt->host->hostdata;
-    
-    if(wd7000_adapter_reset(host)<0)
-	    return FAILED;
-    wd7000_enable_intr (host);
-    return SUCCESS;
+	Adapter *host = (Adapter *) SCpnt->host->hostdata;
+
+	if (wd7000_adapter_reset(host) < 0)
+		return FAILED;
+	wd7000_enable_intr(host);
+	return SUCCESS;
 }
 
 
@@ -1736,52 +1692,46 @@
  *  This was borrowed directly from aha1542.c. (Zaga)
  */
 
-static int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip)
+static int wd7000_biosparam(Disk * disk, struct block_device *bdev, int *ip)
 {
-    dprintk("wd7000_biosparam: dev=%s, size=%d, ", bdevname(bdev),
-	    disk->capacity);
+	dprintk("wd7000_biosparam: dev=%s, size=%d, ", bdevname(bdev), disk->capacity);
 
-    /*
-     * try default translation
-     */
-    ip[0] = 64;
-    ip[1] = 32;
-    ip[2] = disk->capacity / (64 * 32);
-
-    /*
-     * for disks >1GB do some guessing
-     */
-    if (ip[2] >= 1024) {
-	int info[3];
+	/*
+	 * try default translation
+	 */
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = disk->capacity >> 11;
 
 	/*
-	 * try to figure out the geometry from the partition table
+	 * for disks >1GB do some guessing
 	 */
-	if ((scsicam_bios_param (disk, bdev, info) < 0) ||
-	    !(((info[0] == 64) && (info[1] == 32)) ||
-	      ((info[0] == 255) && (info[1] == 63)))) {
-	    printk ("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n"
-		    "                  using extended translation.\n");
-
-	    ip[0] = 255;
-	    ip[1] = 63;
-	    ip[2] = disk->capacity / (255 * 63);
-	}
-	else {
-	    ip[0] = info[0];
-	    ip[1] = info[1];
-	    ip[2] = info[2];
-
-	    if (info[0] == 255)
-		printk(KERN_INFO "%s: current partition table is "
-			"using extended translation.\n", __FUNCTION__);
+	if (ip[2] >= 1024) {
+		int info[3];
+
+		/*
+		 * try to figure out the geometry from the partition table
+		 */
+		if ((scsicam_bios_param(disk, bdev, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) {
+			printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" "                  using extended translation.\n");
+
+			ip[0] = 255;
+			ip[1] = 63;
+			ip[2] = (unsigned long) disk->capacity / (255 * 63);
+		} else {
+			ip[0] = info[0];
+			ip[1] = info[1];
+			ip[2] = info[2];
+
+			if (info[0] == 255)
+				printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __FUNCTION__);
+		}
 	}
-    }
 
-    dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
-    dprintk("WARNING: check, if the bios geometry is correct.\n");
+	dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
+	dprintk("WARNING: check, if the bios geometry is correct.\n");
 
-    return (0);
+	return (0);
 }
 
 MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
diff -Nru a/drivers/scsi/wd7000.h b/drivers/scsi/wd7000.h
--- a/drivers/scsi/wd7000.h	Fri Oct 11 21:23:04 2002
+++ b/drivers/scsi/wd7000.h	Fri Oct 11 21:23:04 2002
@@ -13,16 +13,16 @@
 
 #include <linux/types.h>
 
-static int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host);
-static int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout);
-static int wd7000_detect (Scsi_Host_Template *);
-static int wd7000_command (Scsi_Cmnd *);
-static int wd7000_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-static int wd7000_abort (Scsi_Cmnd *);
-static int wd7000_bus_reset (Scsi_Cmnd *);
-static int wd7000_host_reset (Scsi_Cmnd *);
-static int wd7000_device_reset (Scsi_Cmnd *);
-static int wd7000_biosparam (Disk *, struct block_device *, int *);
+static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host);
+static int wd7000_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+static int wd7000_detect(Scsi_Host_Template *);
+static int wd7000_command(Scsi_Cmnd *);
+static int wd7000_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int wd7000_abort(Scsi_Cmnd *);
+static int wd7000_bus_reset(Scsi_Cmnd *);
+static int wd7000_host_reset(Scsi_Cmnd *);
+static int wd7000_device_reset(Scsi_Cmnd *);
+static int wd7000_biosparam(Disk *, struct block_device *, int *);
 
 #ifndef NULL
 #define NULL 0L
diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c
--- a/drivers/serial/8250.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/serial/8250.c	Fri Oct 11 21:22:52 2002
@@ -31,8 +31,8 @@
 #include <linux/console.h>
 #include <linux/sysrq.h>
 #include <linux/serial_reg.h>
-#include <linux/serialP.h>
 #include <linux/serial.h>
+#include <linux/serialP.h>
 #include <linux/delay.h>
 
 #include <asm/io.h>
@@ -1635,7 +1635,7 @@
 	if (up->port.type != PORT_RSA && res_rsa)
 		release_resource(res_rsa);
 
-	if (up->port.type == PORT_UNKNOWN)
+	if (up->port.type == PORT_UNKNOWN && res_std)
 		release_resource(res_std);
 }
 
diff -Nru a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
--- a/drivers/serial/8250_pci.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/serial/8250_pci.c	Fri Oct 11 21:23:02 2002
@@ -22,10 +22,7 @@
 #include <linux/slab.h>
 #include <linux/serial.h>
 
-/* 2.4.6 compatibility cruft - to be removed with the old serial.c code */
-#define pci_board __pci_board
 #include <linux/serialP.h>
-#undef pci_board
 
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
@@ -771,7 +768,8 @@
 		for (i = 0; i < priv->nr; i++)
 			unregister_serial(priv->line[i]);
 
-		priv->board->init_fn(dev, priv->board, 0);
+		if (priv->board->init_fn)
+			priv->board->init_fn(dev, priv->board, 0);
 
 		pci_disable_device(dev);
 
diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c
--- a/drivers/serial/core.c	Fri Oct 11 21:22:54 2002
+++ b/drivers/serial/core.c	Fri Oct 11 21:22:54 2002
@@ -1604,8 +1604,6 @@
 	return retval;
 }
 
-#ifdef CONFIG_PROC_FS
-
 static const char *uart_type(struct uart_port *port)
 {
 	const char *str = NULL;
@@ -1618,6 +1616,8 @@
 
 	return str;
 }
+
+#ifdef CONFIG_PROC_FS
 
 static int uart_line_info(char *buf, struct uart_driver *drv, int i)
 {
diff -Nru a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
--- a/drivers/sgi/char/sgiserial.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/sgi/char/sgiserial.c	Fri Oct 11 21:22:55 2002
@@ -673,7 +673,7 @@
 		return 0;
 
 	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
 		if (!info->xmit_buf)
 			return -ENOMEM;
 	}
diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c
--- a/drivers/tc/zs.c	Fri Oct 11 21:23:03 2002
+++ b/drivers/tc/zs.c	Fri Oct 11 21:23:03 2002
@@ -705,7 +705,7 @@
 		return 0;
 
 	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
 		if (!info->xmit_buf)
 			return -ENOMEM;
 	}
diff -Nru a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
--- a/drivers/telephony/ixj.c	Fri Oct 11 21:22:51 2002
+++ b/drivers/telephony/ixj.c	Fri Oct 11 21:22:52 2002
@@ -260,7 +260,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/tqueue.h>
 #include <linux/proc_fs.h>
 #include <linux/poll.h>
 #include <linux/timer.h>
diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
--- a/drivers/usb/class/audio.c	Fri Oct 11 21:23:05 2002
+++ b/drivers/usb/class/audio.c	Fri Oct 11 21:23:05 2002
@@ -487,7 +487,7 @@
 	db->dmasize = db->numfrag << db->fragshift;
 	for(nr = 0; nr < NRSGBUF; nr++) {
 		if (!db->sgbuf[nr]) {
-			p = (void *)get_free_page(GFP_KERNEL);
+			p = (void *)get_zeroed_page(GFP_KERNEL);
 			if (!p)
 				return -ENOMEM;
 			db->sgbuf[nr] = p;
@@ -3841,8 +3841,7 @@
 		return;
 	}
 	down(&open_sem);
-	list_del(&s->audiodev);
-	INIT_LIST_HEAD(&s->audiodev);
+	list_del_init(&s->audiodev);
 	s->usbdev = NULL;
 	dev_set_drvdata (&intf->dev, NULL);
 
diff -Nru a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c
--- a/drivers/usb/core/driverfs.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/usb/core/driverfs.c	Fri Oct 11 21:22:55 2002
@@ -99,6 +99,34 @@
 }
 static DEVICE_ATTR(serial,S_IRUGO,show_serial,NULL);
 
+static ssize_t
+show_speed (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device *udev;
+	char *speed;
+
+	if (off)
+		return 0;
+	udev = to_usb_device (dev);
+
+	switch (udev->speed) {
+	case USB_SPEED_LOW:
+		speed = "1.5";
+		break;
+	case USB_SPEED_UNKNOWN:
+	case USB_SPEED_FULL:
+		speed = "12";
+		break;
+	case USB_SPEED_HIGH:
+		speed = "480";
+		break;
+	default:
+		speed = "unknown";
+	}
+	return sprintf (buf, "%s\n", speed);
+}
+static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
+
 /* Descriptor fields */
 #define usb_descriptor_attr(field, format_string)			\
 static ssize_t								\
@@ -136,6 +164,7 @@
 	device_create_file (dev, &dev_attr_bDeviceClass);
 	device_create_file (dev, &dev_attr_bDeviceSubClass);
 	device_create_file (dev, &dev_attr_bDeviceProtocol);
+	device_create_file (dev, &dev_attr_speed);
 
 	if (udev->descriptor.iManufacturer)
 		device_create_file (dev, &dev_attr_manufacturer);
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/usb/core/hub.c	Fri Oct 11 21:22:58 2002
@@ -941,8 +941,7 @@
 		hub = list_entry(tmp, struct usb_hub, event_list);
 		dev = interface_to_usbdev(hub->intf);
 
-		list_del(tmp);
-		INIT_LIST_HEAD(tmp);
+		list_del_init(tmp);
 
 		down(&hub->khubd_sem); /* never blocks, we were on list */
 		spin_unlock_irqrestore(&hub_event_lock, flags);
diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/usb/core/inode.c	Fri Oct 11 21:22:52 2002
@@ -755,8 +755,7 @@
 	}
 	while (!list_empty(&dev->filelist)) {
 		ds = list_entry(dev->filelist.next, struct dev_state, list);
-		list_del(&ds->list);
-		INIT_LIST_HEAD(&ds->list);
+		list_del_init(&ds->list);
 		down_write(&ds->devsem);
 		ds->dev = NULL;
 		up_write(&ds->devsem);
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Fri Oct 11 21:22:58 2002
+++ b/drivers/usb/core/usb.c	Fri Oct 11 21:22:58 2002
@@ -558,14 +558,6 @@
 	 */
 	envp [i++] = scratch;
 	length += snprintf (scratch, buffer_size - length,
-			    "%s", "DEVFS=/proc/bus/usb");
-	if ((buffer_size - length <= 0) || (i >= num_envp))
-		return -ENOMEM;
-	++length;
-	scratch += length;
-
-	envp [i++] = scratch;
-	length += snprintf (scratch, buffer_size - length,
 			    "DEVICE=/proc/bus/usb/%03d/%03d",
 			    usb_dev->bus->busnum, usb_dev->devnum);
 	if ((buffer_size - length <= 0) || (i >= num_envp))
@@ -797,7 +789,7 @@
 			struct usb_interface *interface = &dev->actconfig->interface[i];
 
 			/* remove this interface */
-			put_device(&interface->dev);
+			device_unregister(&interface->dev);
 		}
 	}
 
@@ -805,7 +797,7 @@
 	if (dev->devnum > 0) {
 		clear_bit(dev->devnum, dev->bus->devmap.devicemap);
 		usbfs_remove_device(dev);
-		put_device(&dev->dev);
+		device_unregister(&dev->dev);
 	}
 
 	/* Decrement the reference count, it'll auto free everything when */
diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c
--- a/drivers/usb/host/hc_sl811.c	Fri Oct 11 21:23:02 2002
+++ b/drivers/usb/host/hc_sl811.c	Fri Oct 11 21:23:02 2002
@@ -1207,8 +1207,7 @@
 	usb_deregister_bus (hci->bus);
 	usb_free_bus (hci->bus);
 
-	list_del (&hci->hci_hcd_list);
-	INIT_LIST_HEAD (&hci->hci_hcd_list);
+	list_del_init (&hci->hci_hcd_list);
 
 	kfree (hci);
 }
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/usb/input/hid-core.c	Fri Oct 11 21:23:00 2002
@@ -1284,8 +1284,14 @@
 }
 
 #define USB_VENDOR_ID_WACOM		0x056a
+#define USB_DEVICE_ID_WACOM_PENPARTNER	0x0000
 #define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010
 #define USB_DEVICE_ID_WACOM_INTUOS	0x0020
+#define USB_DEVICE_ID_WACOM_PL		0x0030
+#define USB_DEVICE_ID_WACOM_INTUOS2	0x0040
+
+#define USB_VENDOR_ID_AIPTEK		0x08ca
+#define USB_DEVICE_ID_AIPTEK_6000	0x0020
 
 #define USB_VENDOR_ID_GRIFFIN		0x077d
 #define USB_DEVICE_ID_POWERMATE		0x0410
@@ -1306,14 +1312,29 @@
 	__u16 idProduct;
 	unsigned quirks;
 } hid_blacklist[] = {
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE  },
-	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE  },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@@ -1469,6 +1490,8 @@
 		strcat(hid->name, buf);
 		if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0)
 			snprintf(hid->name, 64, "%s %s", hid->name, buf);
+	} else if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0) {
+			snprintf(hid->name, 128, "%s", buf);
 	} else
 		snprintf(hid->name, 128, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
 
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c	Fri Oct 11 21:22:56 2002
+++ b/drivers/usb/input/hid-input.c	Fri Oct 11 21:22:56 2002
@@ -348,7 +348,7 @@
 	set_bit(usage->type, input->evbit);
 
 	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
-		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
+		usage->code = find_next_zero_bit(bit, usage->code, max + 1);
 	}
 
 	if (usage->code > max) return;
diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
--- a/drivers/usb/input/powermate.c	Fri Oct 11 21:23:00 2002
+++ b/drivers/usb/input/powermate.c	Fri Oct 11 21:23:00 2002
@@ -317,6 +317,7 @@
 	}
 
 	init_MUTEX(&pm->lock);
+	init_input_dev(&pm->input);
 
 	/* get a handle to the interrupt data pipe */
 	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
--- a/drivers/usb/input/wacom.c	Fri Oct 11 21:22:52 2002
+++ b/drivers/usb/input/wacom.c	Fri Oct 11 21:22:52 2002
@@ -1,15 +1,14 @@
 /*
- * $Id: wacom.c,v 1.28 2001/09/25 10:12:07 vojtech Exp $
+ *  USB Wacom Graphire and Wacom Intuos tablet support
  *
- *  Copyright (c) 2000-2001 Vojtech Pavlik	<vojtech@ucw.cz>
+ *  Copyright (c) 2000-2002 Vojtech Pavlik	<vojtech@ucw.cz>
  *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
  *  Copyright (c) 2000 Clifford Wolf		<clifford@clifford.at>
  *  Copyright (c) 2000 Sam Mosel		<sam.mosel@computer.org>
  *  Copyright (c) 2000 James E. Blair		<corvus@gnu.org>
  *  Copyright (c) 2000 Daniel Egger		<egger@suse.de>
  *  Copyright (c) 2001 Frederic Lepied		<flepied@mandrakesoft.com>
- *
- *  USB Wacom Graphire and Wacom Intuos tablet support
+ *  Copyright (c) 2002 Ping Cheng		<pingc@wacom.com>
  *
  *  ChangeLog:
  *      v0.1 (vp)  - Initial release
@@ -37,6 +36,18 @@
  *	v1.21 (vp) - Removed protocol descriptions
  *		   - Added MISC_SERIAL for tool serial numbers
  *	      (gb) - Identify version on module load.
+ *    v1.21.1 (fl) - added Graphire2 support
+ *    v1.21.2 (fl) - added Intuos2 support
+ *                 - added all the PL ids
+ *    v1.21.3 (fl) - added another eraser id from Neil Okamoto
+ *                 - added smooth filter for Graphire from Peri Hankey
+ *                 - added PenPartner support from Olaf van Es
+ *                 - new tool ids from Ole Martin Bjoerndalen
+ *	v1.29 (pc) - Add support for more tablets
+ *		   - Fix pressure reporting
+ *	v1.30 (vp) - Merge 2.4 and 2.5 drivers
+ *		   - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
+ *		   - Cleanups here and there
  */
 
 /*
@@ -44,19 +55,6 @@
  * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -69,7 +67,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.21"
+#define DRIVER_VERSION "v1.30"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -87,12 +85,8 @@
 	int y_max;
 	int pressure_max;
 	int distance_max;
+	int type;
 	void (*irq)(struct urb *urb);
-	unsigned long evbit;
-	unsigned long absbit;
-	unsigned long relbit;
-	unsigned long btnbit;
-	unsigned long digibit;
 };
 
 struct wacom {
@@ -104,7 +98,6 @@
 	struct wacom_features *features;
 	int tool[2];
 	int open;
-	int x, y;
 	__u32 serial[2];
 	char phys[32];
 };
@@ -114,29 +107,50 @@
 	struct wacom *wacom = urb->context;
 	unsigned char *data = wacom->data;
 	struct input_dev *dev = &wacom->dev;
-	int prox;
+	int prox, pressure;
 
 	if (urb->status) return;
 
 	if (data[0] != 2)
 		dbg("received unknown report #%d", data[0]);
 
-	prox = data[1] & 0x20;
+	prox = data[1] & 0x40;
 	
 	input_report_key(dev, BTN_TOOL_PEN, prox);
 	
 	if (prox) {
-		int pressure = (data[4] & 0x04) >> 2 | ((__u32)(data[7] & 0x7f) << 1);
 
-		input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 8) | ((__u32)(data[1] & 0x03) << 16));
-		input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 8) | ((__u32)(data[4] & 0x03) << 8));
-		input_report_abs(dev, ABS_PRESSURE, (data[7] & 0x80) ? (255 - pressure) : (pressure + 255));
+		pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+		if (wacom->features->pressure_max > 255)
+			pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+		pressure += (wacom->features->pressure_max + 1) / 2;
+
+		input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14));
+		input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14));
+		input_report_abs(dev, ABS_PRESSURE, pressure);
+
 		input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
 		input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
 		input_report_key(dev, BTN_STYLUS2, data[4] & 0x20);
 	}
 	
-	input_event(dev, EV_MSC, MSC_SERIAL, 0);
+	input_sync(dev);
+}
+
+static void wacom_penpartner_irq(struct urb *urb)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+
+	if (urb->status) return;
+
+	input_report_key(dev, BTN_TOOL_PEN, 1);
+	input_report_abs(dev, ABS_X, data[2] << 8 | data[1]);
+	input_report_abs(dev, ABS_Y, data[4] << 8 | data[3]);
+	input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
+	input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
+	input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
 	input_sync(dev);
 }
 
@@ -176,13 +190,13 @@
 			input_report_abs(dev, ABS_X, x);
 			input_report_abs(dev, ABS_Y, y);
 
-			input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
+			input_sync(dev);
 			return;
 	}
 
 	if (data[1] & 0x80) {
-		input_report_abs(dev, ABS_X, wacom->x = x);
-		input_report_abs(dev, ABS_Y, wacom->y = y);
+		input_report_abs(dev, ABS_X, x);
+		input_report_abs(dev, ABS_Y, y);
 	}
 
 	input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
@@ -190,8 +204,6 @@
 	input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
 	input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
 
-	input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
-
 	input_sync(dev);
 }
 
@@ -221,27 +233,32 @@
 			case 0x832:
 			case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL;		break;	/* Inking pen */
 			case 0x822:
+			case 0x842:
+			case 0x852:
 			case 0x022: wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Pen */
 			case 0x812:
 			case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH;		break;	/* Stroke pen */
+			case 0x007:
 		        case 0x09c:
-			case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE;		break;	/* Mouse 4D */
+			case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE;		break;	/* Mouse 4D and 2D */
 			case 0x096: wacom->tool[idx] = BTN_TOOL_LENS;		break;	/* Lens cursor */
 			case 0x82a:
+			case 0x85a:
 		        case 0x91a:
 			case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER;		break;	/* Eraser */
 			case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH;	break;	/* Airbrush */
 			default:    wacom->tool[idx] = BTN_TOOL_PEN;		break;	/* Unknown tool */
-		}	
+		}
 
 		input_report_key(dev, wacom->tool[idx], 1);
 		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+		input_sync(dev);
 		return;
 	}
 
 	if ((data[1] & 0xfe) == 0x80) {						/* Exit report */
 		input_report_key(dev, wacom->tool[idx], 0);
-		input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+		input_sync(dev);
 		return;
 	}
 
@@ -274,61 +291,85 @@
 
 		} else {
 
-			input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
-			input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
-			input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
-
 	 		if ((data[1] & 0x10) == 0) {				/* 4D mouse packets */
 
+				input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
+				input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+				input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
+
 				input_report_key(dev, BTN_SIDE,   data[8] & 0x20);
 				input_report_key(dev, BTN_EXTRA,  data[8] & 0x10);
 				input_report_abs(dev, ABS_THROTTLE,  (data[8] & 0x08) ?
 						 ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
 						 -((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
 
-			} else {						/* Lens cursor packets */
-
-				input_report_key(dev, BTN_SIDE,   data[8] & 0x10);
-				input_report_key(dev, BTN_EXTRA,  data[8] & 0x08);
+			} else {
+				if (wacom->tool[idx] == BTN_TOOL_MOUSE) {	/* 2D mouse packets */	
+					input_report_key(dev, BTN_LEFT,   data[8] & 0x04);
+					input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
+					input_report_key(dev, BTN_RIGHT,  data[8] & 0x10);
+					input_report_abs(dev, REL_WHEEL, 
+					    ((__u32)(data[8] & 0x01) - (__u32)((data[8] & 0x02) >> 1)));
+				}
+				else {     /* Lens cursor packets */
+					input_report_key(dev, BTN_LEFT,   data[8] & 0x01);
+					input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+					input_report_key(dev, BTN_RIGHT,  data[8] & 0x04);
+					input_report_key(dev, BTN_SIDE,   data[8] & 0x10);
+					input_report_key(dev, BTN_EXTRA,  data[8] & 0x08);
+				}
 			}
 		}
 	}
 	
-	input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-
 	input_sync(dev);
 }
 
-#define WACOM_INTUOS_TOOLS	(BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
-#define WACOM_INTUOS_BUTTONS	(BIT(BTN_SIDE) | BIT(BTN_EXTRA))
-#define WACOM_INTUOS_ABS	(BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE))
-
 struct wacom_features wacom_features[] = {
-	{ "Wacom Graphire",      8, 10206,  7422,  511, 32, wacom_graphire_irq,
-		BIT(EV_REL), 0, BIT(REL_WHEEL), 0 },
-	{ "Wacom Intuos 4x5",   10, 12700, 10360, 1023, 15, wacom_intuos_irq,
-		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
-	{ "Wacom Intuos 6x8",   10, 20320, 15040, 1023, 15, wacom_intuos_irq,
-		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
-	{ "Wacom Intuos 9x12",  10, 30480, 23060, 1023, 15, wacom_intuos_irq,
-		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
-	{ "Wacom Intuos 12x12", 10, 30480, 30480, 1023, 15, wacom_intuos_irq,
-		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
-	{ "Wacom Intuos 12x18", 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
-		0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
-	{ "Wacom PL500",        8,  12328, 9256,   511, 32, wacom_pl_irq,
-		0,  0, 0, 0 },
-	{ NULL , 0 }
+	{ "Wacom Penpartner",    7,   5040,  3780,  255, 32, 0, wacom_penpartner_irq },
+        { "Wacom Graphire",      8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
+	{ "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 32, 1, wacom_graphire_irq },
+ 	{ "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, 1, wacom_graphire_irq },
+  	{ "Wacom Intuos 4x5",   10,  12700, 10360, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 6x8",   10,  20600, 16450, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 9x12",  10,  30670, 24130, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 12x12", 10,  30670, 31040, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom Intuos 12x18", 10,  45860, 31040, 1023, 15, 2, wacom_intuos_irq },
+ 	{ "Wacom PL400",         8,   5408,  4056,  255, 32, 3, wacom_pl_irq },
+ 	{ "Wacom PL500",         8,   6144,  4608,  255, 32, 3, wacom_pl_irq },
+ 	{ "Wacom PL600",         8,   6126,  4604,  255, 32, 3, wacom_pl_irq },
+ 	{ "Wacom PL600SX",       8,   6260,  5016,  255, 32, 3, wacom_pl_irq },
+ 	{ "Wacom PL550",         8,   6144,  4608,  511, 32, 3, wacom_pl_irq },
+ 	{ "Wacom PL800",         8,   7220,  5780,  511, 32, 3, wacom_pl_irq },
+	{ "Wacom Intuos2 4x5",   10, 12700, 10360, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 6x8",   10, 20600, 16450, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 9x12",  10, 30670, 24130, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 12x12", 10, 30670, 31040, 1023, 15, 2, wacom_intuos_irq },
+	{ "Wacom Intuos2 12x18", 10, 45860, 31040, 1023, 15, 2, wacom_intuos_irq },
+ 	{ }
 };
 
 struct usb_device_id wacom_ids[] = {
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10), .driver_info = 0 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20), .driver_info = 1 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21), .driver_info = 2 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22), .driver_info = 3 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23), .driver_info = 4 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24), .driver_info = 5 },
-	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31), .driver_info = 6 },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
 	{ }
 };
 
@@ -358,9 +399,10 @@
 
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-	struct usb_device *dev = interface_to_usbdev (intf);
+	struct usb_device *dev = interface_to_usbdev(intf);
 	struct usb_endpoint_descriptor *endpoint;
 	struct wacom *wacom;
+	char rep_data[2] = {0x02, 0x02};
 	char path[64];
 
 	if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL)))
@@ -380,15 +422,34 @@
 		return -ENOMEM;
 	}
 
-	wacom->features = wacom_features + id->driver_info;
+	wacom->features = wacom_features + (id - wacom_ids);
 
-	wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) | wacom->features->evbit;
-	wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | wacom->features->absbit;
-	wacom->dev.relbit[0] |= wacom->features->relbit;
-	wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | wacom->features->btnbit;
-	wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) |
-		BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | wacom->features->digibit;
-	wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
+	wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
+	wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+	wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
+
+	switch (wacom->features->type) {
+		case 1:
+			wacom->dev.evbit[0] |= BIT(EV_REL);
+			wacom->dev.relbit[0] |= BIT(REL_WHEEL);
+			wacom->dev.absbit[0] |= BIT(ABS_DISTANCE);
+			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+			break;
+
+		case 2:
+			wacom->dev.evbit[0] |= BIT(EV_MSC);
+			wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
+			wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+ 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE)	| BIT(BTN_TOOL_BRUSH)
+							  | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
+			wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE);
+			break;
+
+		case 3:
+ 			wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2);
+			break;
+	}
 
 	wacom->dev.absmax[ABS_X] = wacom->features->x_max;
 	wacom->dev.absmax[ABS_Y] = wacom->features->y_max;
@@ -435,9 +496,16 @@
 
 	input_register_device(&wacom->dev);
 
+#if 0	/* Missing usb_set_report() */
+	usb_set_report(intf, 3, 2, rep_data, 2);
+	usb_set_report(intf, 3, 5, rep_data, 0);
+	usb_set_report(intf, 3, 6, rep_data, 0);
+#endif
+
 	printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path);
 
 	dev_set_drvdata(&intf->dev, wacom);
+
 	return 0;
 }
 
diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
--- a/drivers/usb/misc/usbtest.c	Fri Oct 11 21:23:04 2002
+++ b/drivers/usb/misc/usbtest.c	Fri Oct 11 21:23:04 2002
@@ -5,7 +5,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/module.h>
-//#include <linux/time.h>
 #include <asm/scatterlist.h>
 
 #if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
@@ -33,21 +32,43 @@
 
 /*-------------------------------------------------------------------------*/
 
+#define	GENERIC		/* let probe() bind using module params */
+
+/* Some devices that can be used for testing will have "real" drivers.
+ * Entries for those need to be enabled here by hand, after disabling
+ * that "real" driver.
+ */
+//#define	IBOT2		/* grab iBOT2 webcams */
+//#define	KEYSPAN_19Qi	/* grab un-renumerated serial adapter */
+
+/*-------------------------------------------------------------------------*/
+
+struct usbtest_info {
+	const char		*name;
+	u8			ep_in;		/* bulk/intr source */
+	u8			ep_out;		/* bulk/intr sink */
+	int			alt;
+};
+
 /* this is accessed only through usbfs ioctl calls.
  * one ioctl to issue a test ... no locking needed!!!
  * tests create other threads if they need them.
  * urbs and buffers are allocated dynamically,
  * and data generated deterministically.
  *
- * there's a minor complication on disconnect(), since
+ * there's a minor complication on rmmod, since
  * usbfs.disconnect() waits till our ioctl completes.
+ * unplug works fine since we'll see real i/o errors.
  */
 struct usbtest_dev {
 	struct usb_interface	*intf;
-	struct testdev_info	*info;
+	struct usbtest_info	*info;
 	char			id [32];
 	int			in_pipe;
 	int			out_pipe;
+
+#define TBUF_SIZE	256
+	u8			*buf;
 };
 
 static struct usb_device *testdev_to_usbdev (struct usbtest_dev *test)
@@ -90,6 +111,8 @@
 			? (INTERRUPT_RATE << 3)
 			: INTERRUPT_RATE,
 	urb->transfer_flags = URB_NO_DMA_MAP;
+	if (usb_pipein (pipe))
+		urb->transfer_flags |= URB_SHORT_NOT_OK;
 	urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL,
 			&urb->transfer_dma);
 	if (!urb->transfer_buffer) {
@@ -247,6 +270,279 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* unqueued control message testing
+ *
+ * there's a nice set of device functional requirements in chapter 9 of the
+ * usb 2.0 spec, which we can apply to ANY device, even ones that don't use
+ * special test firmware.
+ *
+ * we know the device is configured (or suspended) by the time it's visible
+ * through usbfs.  we can't change that, so we won't test enumeration (which
+ * worked 'well enough' to get here, this time), power management (ditto),
+ * or remote wakeup (which needs human interaction).
+ */
+
+static int get_altsetting (struct usbtest_dev *dev)
+{
+	struct usb_interface	*iface = dev->intf;
+	struct usb_device	*udev = interface_to_usbdev (iface);
+	int			retval;
+
+	retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
+			USB_REQ_GET_INTERFACE, USB_DIR_IN|USB_RECIP_INTERFACE,
+			0, iface->altsetting [0].bInterfaceNumber,
+			dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
+	switch (retval) {
+	case 1:
+		return dev->buf [0];
+	case 0:
+		retval = -ERANGE;
+		// FALLTHROUGH
+	default:
+		return retval;
+	}
+}
+
+/* this is usb_set_interface(), with no 'only one altsetting' case */
+static int set_altsetting (struct usbtest_dev *dev, int alternate)
+{
+	struct usb_interface		*iface = dev->intf;
+	struct usb_device		*udev;
+	struct usb_interface_descriptor	*iface_as;
+	int				i, ret;
+
+	if (alternate < 0 || alternate >= iface->num_altsetting)
+		return -EINVAL;
+
+	udev = interface_to_usbdev (iface);
+	if ((ret = usb_control_msg (udev, usb_sndctrlpipe (udev, 0),
+			USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE,
+			iface->altsetting [alternate].bAlternateSetting,
+			iface->altsetting [alternate].bInterfaceNumber,
+			NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
+		return ret;
+
+	// FIXME usbcore should be more like this:
+	// - remove that special casing in usbcore.
+	// - fix usbcore signature to take interface
+
+	/* prevent requests using previous endpoint settings */
+	iface_as = iface->altsetting + iface->act_altsetting;
+	for (i = 0; i < iface_as->bNumEndpoints; i++) {
+		u8	ep = iface_as->endpoint [i].bEndpointAddress;
+		int	out = !(ep & USB_DIR_IN);
+
+		ep &= USB_ENDPOINT_NUMBER_MASK;
+		(out ? udev->epmaxpacketout : udev->epmaxpacketin ) [ep] = 0;
+		// FIXME want hcd hook here, "forget this endpoint"
+	}
+	iface->act_altsetting = alternate;
+
+	/* reset toggles and maxpacket for all endpoints affected */
+	iface_as = iface->altsetting + iface->act_altsetting;
+	for (i = 0; i < iface_as->bNumEndpoints; i++) {
+		u8	ep = iface_as->endpoint [i].bEndpointAddress;
+		int	out = !(ep & USB_DIR_IN);
+
+		ep &= USB_ENDPOINT_NUMBER_MASK;
+		usb_settoggle (udev, ep, out, 0);
+		(out ? udev->epmaxpacketout : udev->epmaxpacketin ) [ep]
+			= iface_as->endpoint [ep].wMaxPacketSize;
+	}
+
+	return 0;
+}
+
+static int is_good_config (char *buf, int len)
+{
+	struct usb_config_descriptor	*config;
+	
+	if (len < sizeof *config)
+		return 0;
+	config = (struct usb_config_descriptor *) buf;
+
+	switch (config->bDescriptorType) {
+	case USB_DT_CONFIG:
+	case USB_DT_OTHER_SPEED_CONFIG:
+		if (config->bLength != 9)
+			return 0;
+#if 0
+		/* this bit 'must be 1' but often isn't */
+		if (!(config->bmAttributes & 0x80)) {
+			dbg ("high bit of config attributes not set");
+			return 0;
+		}
+#endif
+		if (config->bmAttributes & 0x1f)	/* reserved == 0 */
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+
+	le32_to_cpus (&config->wTotalLength);
+	if (config->wTotalLength == len)		/* read it all */
+		return 1;
+	return config->wTotalLength >= TBUF_SIZE;	/* max partial read */
+}
+
+/* sanity test for standard requests working with usb_control_mesg() and some
+ * of the utility functions which use it.
+ *
+ * this doesn't test how endpoint halts behave or data toggles get set, since
+ * we won't do I/O to bulk/interrupt endpoints here (which is how to change
+ * halt or toggle).  toggle testing is impractical without support from hcds.
+ *
+ * this avoids failing devices linux would normally work with, by not testing
+ * config/altsetting operations for devices that only support their defaults.
+ * such devices rarely support those needless operations.
+ *
+ * NOTE that since this is a sanity test, it's not examining boundary cases
+ * to see if usbcore, hcd, and device all behave right.  such testing would
+ * involve varied read sizes and other operation sequences.
+ */
+static int ch9_postconfig (struct usbtest_dev *dev)
+{
+	struct usb_interface	*iface = dev->intf;
+	struct usb_device	*udev = interface_to_usbdev (iface);
+	int			i, retval;
+
+	/* [9.2.3] if there's more than one altsetting, we need to be able to
+	 * set and get each one.  mostly trusts the descriptors from usbcore.
+	 */
+	for (i = 0; i < iface->num_altsetting; i++) {
+
+		/* 9.2.3 constrains the range here, and Linux ensures
+		 * they're ordered meaningfully in this array
+		 */
+		if (iface->altsetting [i].bAlternateSetting != i) {
+			dbg ("%s, illegal alt [%d].bAltSetting = %d",
+					dev->id, i, 
+					iface->altsetting [i]
+						.bAlternateSetting);
+			return -EDOM;
+		}
+
+		/* [real world] get/set unimplemented if there's only one */
+		if (iface->num_altsetting == 1)
+			continue;
+
+		/* [9.4.10] set_interface */
+		retval = set_altsetting (dev, i);
+		if (retval) {
+			dbg ("%s can't set_interface = %d, %d",
+					dev->id, i, retval);
+			return retval;
+		}
+
+		/* [9.4.4] get_interface always works */
+		retval = get_altsetting (dev);
+		if (retval != i) {
+			dbg ("%s get alt should be %d, was %d",
+					dev->id, i, retval);
+			return (retval < 0) ? retval : -EDOM;
+		}
+
+	}
+
+	/* [real world] get_config unimplemented if there's only one */
+	if (udev->descriptor.bNumConfigurations != 1) {
+		int	expected = udev->actconfig->bConfigurationValue;
+
+		/* [9.4.2] get_configuration always works */
+		retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
+				USB_REQ_GET_CONFIGURATION, USB_RECIP_DEVICE,
+				0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
+		if (retval != 1 || dev->buf [0] != expected) {
+			dbg ("%s get config --> %d (%d)", dev->id, retval,
+				expected);
+			return (retval < 0) ? retval : -EDOM;
+		}
+	}
+
+	/* there's always [9.4.3] a device descriptor [9.6.1] */
+	retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0,
+			dev->buf, sizeof udev->descriptor);
+	if (retval != sizeof udev->descriptor) {
+		dbg ("%s dev descriptor --> %d", dev->id, retval);
+		return (retval < 0) ? retval : -EDOM;
+	}
+
+	/* there's always [9.4.3] at least one config descriptor [9.6.3] */
+	for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
+		retval = usb_get_descriptor (udev, USB_DT_CONFIG, i,
+				dev->buf, TBUF_SIZE);
+		if (!is_good_config (dev->buf, retval)) {
+			dbg ("%s config [%d] descriptor --> %d",
+					dev->id, i, retval);
+			return (retval < 0) ? retval : -EDOM;
+		}
+
+		// FIXME cross-checking udev->config[i] to make sure usbcore
+		// parsed it right (etc) would be good testing paranoia
+	}
+
+	/* and sometimes [9.2.6.6] speed dependent descriptors */
+	if (udev->descriptor.bcdUSB == 0x0200) {	/* pre-swapped */
+		struct usb_qualifier_descriptor		*d = 0;
+
+		/* device qualifier [9.6.2] */
+		retval = usb_get_descriptor (udev,
+				USB_DT_DEVICE_QUALIFIER, 0, dev->buf,
+				sizeof (struct usb_qualifier_descriptor));
+		if (retval == -EPIPE) {
+			if (udev->speed == USB_SPEED_HIGH) {
+				dbg ("%s hs dev qualifier --> %d",
+						dev->id, retval);
+				return (retval < 0) ? retval : -EDOM;
+			}
+			/* usb2.0 but not high-speed capable; fine */
+		} else if (retval != sizeof (struct usb_qualifier_descriptor)) {
+			dbg ("%s dev qualifier --> %d", dev->id, retval);
+			return (retval < 0) ? retval : -EDOM;
+		} else
+			d = (struct usb_qualifier_descriptor *) dev->buf;
+
+		/* might not have [9.6.2] any other-speed configs [9.6.4] */
+		if (d) {
+			unsigned max = d->bNumConfigurations;
+			for (i = 0; i < max; i++) {
+				retval = usb_get_descriptor (udev,
+					USB_DT_OTHER_SPEED_CONFIG, i,
+					dev->buf, TBUF_SIZE);
+				if (!is_good_config (dev->buf, retval)) {
+					dbg ("%s other speed config --> %d",
+							dev->id, retval);
+					return (retval < 0) ? retval : -EDOM;
+				}
+			}
+		}
+	}
+	// FIXME fetch strings from at least the device descriptor
+
+	/* [9.4.5] get_status always works */
+	retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);
+	if (retval != 2) {
+		dbg ("%s get dev status --> %d", dev->id, retval);
+		return (retval < 0) ? retval : -EDOM;
+	}
+
+	// FIXME configuration.bmAttributes says if we could try to set/clear
+	// the device's remote wakeup feature ... if we can, test that here
+
+	retval = usb_get_status (udev, USB_RECIP_INTERFACE,
+			iface->altsetting [0].bInterfaceNumber, dev->buf);
+	if (retval != 2) {
+		dbg ("%s get interface status --> %d", dev->id, retval);
+		return (retval < 0) ? retval : -EDOM;
+	}
+	// FIXME get status for each endpoint in the interface
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
 /* We only have this one interface to user space, through usbfs.
  * User mode code can scan usbfs to find N different devices (maybe on
  * different busses) to use when testing, and allocate one thread per
@@ -270,6 +566,7 @@
 	struct scatterlist	*sg;
 	struct usb_sg_request	req;
 	struct timeval		start;
+	unsigned		i;
 
 	// FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is.
 
@@ -280,6 +577,23 @@
 			|| param->sglen < 0 || param->vary < 0)
 		return -EINVAL;
 
+	/* some devices, like ez-usb default devices, need a non-default
+	 * altsetting to have any active endpoints.  some tests change
+	 * altsettings; force a default so most tests don't need to check.
+	 */
+	if (dev->info->alt >= 0) {
+	    	int	res;
+
+		if (intf->altsetting->bInterfaceNumber)
+			return -ENODEV;
+		res = set_altsetting (dev, dev->info->alt);
+		if (res) {
+			err ("%s: set altsetting to %d failed, %d",
+					dev->id, dev->info->alt, res);
+			return res;
+		}
+	}
+
 	/*
 	 * Just a bunch of test cases that every HCD is expected to handle.
 	 *
@@ -287,7 +601,7 @@
 	 * one firmware image to handle all the test cases.
 	 *
 	 * FIXME add more tests!  cancel requests, verify the data, control
-	 * requests, and so on.
+	 * queueing, concurrent read+write threads, and so on.
 	 */
 	do_gettimeofday (&start);
 	switch (param->test_num) {
@@ -343,7 +657,7 @@
 	case 4:
 		if (dev->in_pipe == 0 || param->vary == 0)
 			break;
-		dbg ("%s TEST 3:  read/%d 0..%d bytes %u times", dev->id,
+		dbg ("%s TEST 4:  read/%d 0..%d bytes %u times", dev->id,
 				param->vary, param->length, param->iterations);
 		urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
 		if (!urb) {
@@ -422,6 +736,17 @@
 		free_sglist (sg, param->sglen);
 		break;
 
+	/* non-queued sanity tests for control (chapter 9 subset) */
+	case 9:
+		retval = 0;
+		dbg ("%s TEST 9:  ch9 (subset) control tests, %d times",
+				dev->id, param->iterations);
+		for (i = param->iterations; retval == 0 && i--; /* NOP */)
+			retval = ch9_postconfig (dev);
+		if (retval)
+			dbg ("ch9 subset failed, iterations left %d", i);
+		break;
+
 	/* test cases for the unlink/cancel codepaths need a thread to
 	 * usb_unlink_urb() or usg_sg_cancel(), and a way to check if
 	 * the urb/sg_request was properly canceled.
@@ -443,48 +768,77 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* most programmable USB devices can be given firmware that will support the
- * test cases above.  one basic question is which endpoints to use for
- * testing; endpoint numbers are not always firmware-selectable.
- *
- * for now, the driver_info in the device_id table entry just encodes the
- * endpoint info for a pair of bulk-capable endpoints, which we can use
- * for some interrupt transfer tests too.  later this could get fancier.
- */
-#define EP_PAIR(in,out) (((in)<<4)|(out))
-
 static int force_interrupt = 0;
 MODULE_PARM (force_interrupt, "i");
 MODULE_PARM_DESC (force_interrupt, "0 = test bulk (default), else interrupt");
 
+#ifdef	GENERIC
+static int vendor;
+MODULE_PARM (vendor, "h");
+MODULE_PARM_DESC (vendor, "vendor code (from usb-if)");
+
+static int product;
+MODULE_PARM (product, "h");
+MODULE_PARM_DESC (product, "product code (from vendor)");
+#endif
+
 static int
 usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device	*udev;
 	struct usbtest_dev	*dev;
-	unsigned long		driver_info = id->driver_info;
+	struct usbtest_info	*info;
+	char			*rtest, *wtest;
 
 	udev = interface_to_usbdev (intf);
 
+#ifdef	GENERIC
+	/* specify devices by module parameters? */
+	if (id->match_flags == 0) {
+		/* vendor match required, product match optional */
+		if (!vendor || udev->descriptor.idVendor != (u16)vendor)
+			return -ENODEV;
+		if (product && udev->descriptor.idProduct != (u16)product)
+			return -ENODEV;
+		dbg ("matched module params, vend=0x%04x prod=0x%04x",
+				udev->descriptor.idVendor,
+				udev->descriptor.idProduct);
+	}
+#endif
+
 	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
 	if (!dev)
 		return -ENOMEM;
 	memset (dev, 0, sizeof *dev);
-	snprintf (dev->id, sizeof dev->id, "%s-%s",
-			udev->bus->bus_name, udev->devpath);
+	info = (struct usbtest_info *) id->driver_info;
+	dev->info = info;
+
+	/* use the same kind of id the hid driver shows */
+	snprintf (dev->id, sizeof dev->id, "%s-%s:%d",
+			udev->bus->bus_name, udev->devpath,
+			intf->altsetting [0].bInterfaceNumber);
 	dev->intf = intf;
 
+	/* cacheline-aligned scratch for i/o */
+	if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == 0) {
+		kfree (dev);
+		return -ENOMEM;
+	}
+
 	/* NOTE this doesn't yet test the handful of difference that are
-	 * visible with high speed devices:  bigger maxpacket (1K) and
+	 * visible with high speed interrupts:  bigger maxpacket (1K) and
 	 * "high bandwidth" modes (up to 3 packets/uframe).
 	 */
+	rtest = wtest = "";
 	if (force_interrupt || udev->speed == USB_SPEED_LOW) {
-		if (driver_info & 0xf0)
-			dev->in_pipe = usb_rcvintpipe (udev,
-				(driver_info >> 4) & 0x0f);
-		if (driver_info & 0x0f)
-			dev->out_pipe = usb_sndintpipe (udev,
-				driver_info & 0x0f);
+		if (info->ep_in) {
+			dev->in_pipe = usb_rcvintpipe (udev, info->ep_in);
+			rtest = " intr-in";
+		}
+		if (info->ep_out) {
+			dev->out_pipe = usb_sndintpipe (udev, info->ep_out);
+			wtest = " intr-out";
+		}
 
 #if 1
 		// FIXME disabling this until we finally get rid of
@@ -494,18 +848,26 @@
 		return -ENODEV;
 #endif
 	} else {
-		if (driver_info & 0xf0)
-			dev->in_pipe = usb_rcvbulkpipe (udev,
-				(driver_info >> 4) & 0x0f);
-		if (driver_info & 0x0f)
-			dev->out_pipe = usb_sndbulkpipe (udev,
-				driver_info & 0x0f);
+		if (info->ep_in) {
+			dev->in_pipe = usb_rcvbulkpipe (udev, info->ep_in);
+			rtest = " bulk-in";
+		}
+		if (info->ep_out) {
+			dev->out_pipe = usb_sndbulkpipe (udev, info->ep_out);
+			wtest = " bulk-out";
+		}
 	}
 
 	dev_set_drvdata (&intf->dev, dev);
-	info ("bound to %s ...%s%s", dev->id,
-			dev->out_pipe ? " writes" : "",
-			dev->in_pipe ? " reads" : "");
+	info ("%s at %s ... %s speed {control%s%s} tests",
+			info->name, dev->id,
+			({ char *tmp;
+			switch (udev->speed) {
+			case USB_SPEED_LOW: tmp = "low"; break;
+			case USB_SPEED_FULL: tmp = "full"; break;
+			case USB_SPEED_HIGH: tmp = "high"; break;
+			default: tmp = "unknown"; break;
+			}; tmp; }), rtest, wtest);
 	return 0;
 }
 
@@ -519,24 +881,113 @@
 }
 
 /* Basic testing only needs a device that can source or sink bulk traffic.
+ * Any device can test control transfers (default with GENERIC binding).
+ *
+ * Several entries work with the default EP0 implementation that's built
+ * into EZ-USB chips.  There's a default vendor ID which can be overridden
+ * by (very) small config EEPROMS, but otherwise all these devices act
+ * identically until firmware is loaded:  only EP0 works.  It turns out
+ * to be easy to make other endpoints work, without modifying that EP0
+ * behavior.  For now, we expect that kind of firmware.
  */
+
+/* an21xx or fx versions of ez-usb */
+static struct usbtest_info ez1_info = {
+	.name		= "EZ-USB device",
+	.ep_in		= 2,
+	.ep_out		= 2,
+	.alt		= 1,
+};
+
+/* fx2 version of ez-usb */
+static struct usbtest_info ez2_info = {
+	.name		= "FX2 device",
+	.ep_in		= 6,
+	.ep_out		= 2,
+	.alt		= 1,
+};
+
+#ifdef IBOT2
+/* this is a nice source of high speed bulk data;
+ * uses an FX2, with firmware provided in the device
+ */
+static struct usbtest_info ibot2_info = {
+	.name		= "iBOT2 webcam",
+	.ep_in		= 2,
+	.alt		= -1,
+};
+#endif
+
+#ifdef GENERIC
+/* we can use any device to test control traffic */
+static struct usbtest_info generic_info = {
+	.name		= "Generic USB device",
+	.alt		= -1,
+};
+#endif
+
+// FIXME remove this 
+static struct usbtest_info hact_info = {
+	.name		= "FX2/hact",
+	//.ep_in		= 6,
+	.ep_out		= 2,
+	.alt		= -1,
+};
+
+
 static struct usb_device_id id_table [] = {
 
-	/* EZ-USB FX2 "bulksrc" or "bulkloop" firmware from Cypress
-	 * reads disabled on this one, my version has some problem there
-	 */
 	{ USB_DEVICE (0x0547, 0x1002),
-		.driver_info = EP_PAIR (0, 2),
+		.driver_info = (unsigned long) &hact_info,
 		},
-#if 1
+
+	/*-------------------------------------------------------------*/
+
+	/* EZ-USB devices which download firmware to replace (or in our
+	 * case augment) the default device implementation.
+	 */
+
+	/* generic EZ-USB FX controller */
+	{ USB_DEVICE (0x0547, 0x2235),
+		.driver_info = (unsigned long) &ez1_info,
+		},
+
+	/* CY3671 development board with EZ-USB FX */
+	{ USB_DEVICE (0x0547, 0x0080),
+		.driver_info = (unsigned long) &ez1_info,
+		},
+
+	/* generic EZ-USB FX2 controller (or development board) */
+	{ USB_DEVICE (0x04b4, 0x8613),
+		.driver_info = (unsigned long) &ez2_info,
+		},
+
+#ifdef KEYSPAN_19Qi
+	/* Keyspan 19qi uses an21xx (original EZ-USB) */
+	// this does not coexist with the real Keyspan 19qi driver!
+	{ USB_DEVICE (0x06cd, 0x010b),
+		.driver_info = (unsigned long) &ez1_info,
+		},
+#endif
+
+	/*-------------------------------------------------------------*/
+
+#ifdef IBOT2
+	/* iBOT2 makes a nice source of high speed bulk-in data */
 	// this does not coexist with a real iBOT2 driver!
-	// it makes a nice source of high speed bulk-in data
 	{ USB_DEVICE (0x0b62, 0x0059),
-		.driver_info = EP_PAIR (2, 0),
+		.driver_info = (unsigned long) &ibot2_info,
 		},
 #endif
 
-	/* can that old "usbstress-0.3" firmware be used with this? */
+	/*-------------------------------------------------------------*/
+
+#ifdef GENERIC
+	/* module params can specify devices to use for control tests */
+	{ .driver_info = (unsigned long) &generic_info, },
+#endif
+
+	/*-------------------------------------------------------------*/
 
 	{ }
 };
@@ -555,6 +1006,10 @@
 
 static int __init usbtest_init (void)
 {
+#ifdef GENERIC
+	if (vendor)
+		dbg ("params: vend=0x%04x prod=0x%04x", vendor, product);
+#endif
 	return usb_register (&usbtest_driver);
 }
 module_init (usbtest_init);
@@ -565,6 +1020,6 @@
 }
 module_exit (usbtest_exit);
 
-MODULE_DESCRIPTION ("USB HCD Testing Driver");
+MODULE_DESCRIPTION ("USB Core/HCD Testing Driver");
 MODULE_LICENSE ("GPL");
 
diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
--- a/drivers/usb/serial/keyspan.c	Fri Oct 11 21:22:53 2002
+++ b/drivers/usb/serial/keyspan.c	Fri Oct 11 21:22:53 2002
@@ -530,7 +530,7 @@
 	if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
-exit:
+exit: ;
 }
 
 static void	usa26_glocont_callback(struct urb *urb)
@@ -665,7 +665,7 @@
 	if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
-exit:	
+exit: ;
 }
 
 static void	usa28_glocont_callback(struct urb *urb)
@@ -758,7 +758,7 @@
 	if ((err = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
-exit:	
+exit:	;
 }
 
 static void	usa49_inack_callback(struct urb *urb)
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Fri Oct 11 21:22:57 2002
+++ b/drivers/usb/serial/pl2303.c	Fri Oct 11 21:22:57 2002
@@ -358,7 +358,7 @@
 
 	if (cflag & CRTSCTS) {
 		i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-				     VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST_TYPE,
+				     VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
 				     0x0, 0x41, NULL, 0, 100);
 		dbg ("0x40:0x1:0x0:0x41  %d", i);
 	}
diff -Nru a/drivers/video/Config.in b/drivers/video/Config.in
--- a/drivers/video/Config.in	Fri Oct 11 21:22:59 2002
+++ b/drivers/video/Config.in	Fri Oct 11 21:22:59 2002
@@ -254,7 +254,7 @@
 	 define_tristate CONFIG_FBCON_CFB2 y
 	 define_tristate CONFIG_FBCON_CFB4 y
       else
-	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_SA1100" = "m"]; then 
+	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_SA1100" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_CFB2 m
 	    define_tristate CONFIG_FBCON_CFB4 m
 	 fi
diff -Nru a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
--- a/drivers/video/tdfxfb.c	Fri Oct 11 21:22:55 2002
+++ b/drivers/video/tdfxfb.c	Fri Oct 11 21:22:55 2002
@@ -146,7 +146,7 @@
 	.name =		"tdfxfb",
 	.id_table =	tdfxfb_id_table,
 	.probe =	tdfxfb_probe,
-	.remove =	tdfxfb_remove,
+	.remove =	__devexit_p(tdfxfb_remove),
 };
 
 MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
diff -Nru a/fs/Config.help b/fs/Config.help
--- a/fs/Config.help	Fri Oct 11 21:23:02 2002
+++ b/fs/Config.help	Fri Oct 11 21:23:03 2002
@@ -576,6 +576,12 @@
   If you would like to include the NFSv3 server as well as the NFSv2
   server, say Y here.  If unsure, say Y.
 
+CONFIG_NFSD_V4
+  If you would like to include the NFSv4 server as well as the NFSv2
+  and NFSv3 servers, say Y here.  This feature is experimental, and
+  should only be used if you are interested in helping to test NFSv4.
+  If unsure, say N.
+
 CONFIG_NFSD_TCP
   Enable NFS service over TCP connections.  This the officially
   still experimental, but seems to work well.
@@ -949,6 +955,33 @@
   The module is called freevxfs.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.  If
   unsure, say N.
+
+CIFS (Common Internet File System) support
+CONFIG_CIFS
+  This is the client VFS module for the Common Internet File System
+  (CIFS) protocol which is the successor to the Server Message Block 
+  (SMB) protocol, the native file sharing mechanism for most early
+  PC operating systems.  CIFS is fully supported by current network
+  file servers such as Windows 2000 (including Windows NT version 4 
+  and Windows XP) as well by Samba (which provides excellent CIFS
+  server support for Linux and many other operating systems).  For
+  production systems the smbfs module may be used instead of this
+  cifs module since smbfs is currently more stable and provides
+  support for older servers.  The intent of this module is to provide the
+  most advanced network file system function for CIFS compliant servers, 
+  including support for dfs (heirarchical name space), secure per-user
+  session establishment, safe distributed caching (oplock), optional
+  packet signing, Unicode and other internationalization improvements, and
+  optional Winbind (nsswitch) integration.  This module is in an early
+  development stage, so unless you are specifically interested in this
+  filesystem, just say N.
+
+CIFS Debugging
+CONFIG_CIFS_DEBUG
+  If you are experiencing any problems with the CIFS filesystem, say
+  Y here.  This will result in additional debugging messages to be
+  written to the system log.  Under normal circumstances, this
+  results in very little overhead.  
 
 CONFIG_SMB_FS
   SMB (Server Message Block) is the protocol Windows for Workgroups
diff -Nru a/fs/Config.in b/fs/Config.in
--- a/fs/Config.in	Fri Oct 11 21:23:00 2002
+++ b/fs/Config.in	Fri Oct 11 21:23:00 2002
@@ -121,6 +121,7 @@
 
    dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
    dep_mbool '  Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD
+   dep_mbool '  Provide NFSv4 server support (EXPERIMENTAL)' CONFIG_NFSD_V4 $CONFIG_NFSD_V3 $CONFIG_EXPERIMENTAL
    dep_mbool '  Provide NFS server over TCP support (EXPERIMENTAL)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL
 
    if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
@@ -139,6 +140,8 @@
      define_bool CONFIG_LOCKD_V4 y
    fi
    define_tristate CONFIG_EXPORTFS $CONFIG_NFSD
+
+   dep_tristate 'CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)(EXPERIMENTAL)' CONFIG_CIFS $CONFIG_INET
 
    dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
    if [ "$CONFIG_SMB_FS" != "n" ]; then
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Fri Oct 11 21:22:59 2002
+++ b/fs/Makefile	Fri Oct 11 21:22:59 2002
@@ -6,7 +6,7 @@
 # 
 
 export-objs :=	open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \
-                fcntl.o
+                fcntl.o read_write.o
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
 		bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \
@@ -65,6 +65,7 @@
 obj-$(CONFIG_NLS)		+= nls/
 obj-$(CONFIG_SYSV_FS)		+= sysv/
 obj-$(CONFIG_SMB_FS)		+= smbfs/
+obj-$(CONFIG_CIFS)             += cifs/
 obj-$(CONFIG_NCP_FS)		+= ncpfs/
 obj-$(CONFIG_HPFS_FS)		+= hpfs/
 obj-$(CONFIG_NTFS_FS)		+= ntfs/
diff -Nru a/fs/adfs/inode.c b/fs/adfs/inode.c
--- a/fs/adfs/inode.c	Fri Oct 11 21:22:55 2002
+++ b/fs/adfs/inode.c	Fri Oct 11 21:22:55 2002
@@ -67,7 +67,7 @@
 		&ADFS_I(page->mapping->host)->mmu_private);
 }
 
-static int _adfs_bmap(struct address_space *mapping, long block)
+static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping, block, adfs_get_block);
 }
diff -Nru a/fs/adfs/super.c b/fs/adfs/super.c
--- a/fs/adfs/super.c	Fri Oct 11 21:22:50 2002
+++ b/fs/adfs/super.c	Fri Oct 11 21:22:50 2002
@@ -130,7 +130,7 @@
 		brelse(asb->s_map[i].dm_bh);
 	kfree(asb->s_map);
 	kfree(asb);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 }
 
 static int parse_options(struct super_block *sb, char *options)
@@ -330,7 +330,7 @@
 	asb = kmalloc(sizeof(*asb), GFP_KERNEL);
 	if (!asb)
 		return -ENOMEM;
-	sb->u.generic_sbp = asb;
+	sb->s_fs_info = asb;
 	memset(asb, 0, sizeof(*asb));
 
 	/* set default options */
@@ -452,7 +452,7 @@
 error_free_bh:
 	brelse(bh);
 error:
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(asb);
 	return -EINVAL;
 }
diff -Nru a/fs/affs/file.c b/fs/affs/file.c
--- a/fs/affs/file.c	Fri Oct 11 21:22:58 2002
+++ b/fs/affs/file.c	Fri Oct 11 21:22:58 2002
@@ -338,10 +338,11 @@
 	struct buffer_head	*ext_bh;
 	u32			 ext;
 
-	pr_debug("AFFS: get_block(%u, %ld)\n", (u32)inode->i_ino, block);
+	pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
 
-	if (block < 0)
-		goto err_small;
+
+	if (block > (sector_t)0x7fffffffUL)
+		BUG();
 
 	if (block >= AFFS_I(inode)->i_blkcnt) {
 		if (block > AFFS_I(inode)->i_blkcnt || !create)
@@ -352,12 +353,12 @@
 	//lock cache
 	affs_lock_ext(inode);
 
-	ext = block / AFFS_SB(sb)->s_hashsize;
+	ext = (u32)block / AFFS_SB(sb)->s_hashsize;
 	block -= ext * AFFS_SB(sb)->s_hashsize;
 	ext_bh = affs_get_extblock(inode, ext);
 	if (IS_ERR(ext_bh))
 		goto err_ext;
-	map_bh(bh_result, sb, be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block)));
+	map_bh(bh_result, sb, (sector_t)be32_to_cpu(AFFS_BLOCK(sb, ext_bh, block)));
 
 	if (create) {
 		u32 blocknr = affs_alloc_block(inode, ext_bh->b_blocknr);
@@ -422,7 +423,7 @@
 	return cont_prepare_write(page, from, to, affs_get_block,
 		&AFFS_I(page->mapping->host)->mmu_private);
 }
-static int _affs_bmap(struct address_space *mapping, long block)
+static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,affs_get_block);
 }
diff -Nru a/fs/affs/inode.c b/fs/affs/inode.c
--- a/fs/affs/inode.c	Fri Oct 11 21:22:57 2002
+++ b/fs/affs/inode.c	Fri Oct 11 21:22:57 2002
@@ -416,7 +416,7 @@
 	}
 	affs_fix_checksum(sb, bh);
 	mark_buffer_dirty_inode(bh, inode);
-	dentry->d_fsdata = (void *)bh->b_blocknr;
+	dentry->d_fsdata = (void *)(long)bh->b_blocknr;
 
 	affs_lock_dir(dir);
 	retval = affs_insert_hash(dir, bh);
diff -Nru a/fs/affs/super.c b/fs/affs/super.c
--- a/fs/affs/super.c	Fri Oct 11 21:23:02 2002
+++ b/fs/affs/super.c	Fri Oct 11 21:23:02 2002
@@ -56,7 +56,7 @@
 	kfree(sbi->s_bitmap);
 	affs_brelse(sbi->s_root_bh);
 	kfree(sbi);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	unlock_kernel();
 	return;
 }
@@ -130,17 +130,17 @@
 }
 
 static struct super_operations affs_sops = {
-	alloc_inode:	affs_alloc_inode,
-	destroy_inode:	affs_destroy_inode,
-	read_inode:	affs_read_inode,
-	write_inode:	affs_write_inode,
-	put_inode:	affs_put_inode,
-	delete_inode:	affs_delete_inode,
-	clear_inode:	affs_clear_inode,
-	put_super:	affs_put_super,
-	write_super:	affs_write_super,
-	statfs:		affs_statfs,
-	remount_fs:	affs_remount,
+	.alloc_inode	= affs_alloc_inode,
+	.destroy_inode	= affs_destroy_inode,
+	.read_inode	= affs_read_inode,
+	.write_inode	= affs_write_inode,
+	.put_inode	= affs_put_inode,
+	.delete_inode	= affs_delete_inode,
+	.clear_inode	= affs_clear_inode,
+	.put_super	= affs_put_super,
+	.write_super	= affs_write_super,
+	.statfs		= affs_statfs,
+	.remount_fs	= affs_remount,
 };
 
 static int
@@ -298,7 +298,7 @@
 	sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(*AFFS_SB));
 	init_MUTEX(&sbi->s_bmlock);
 
@@ -483,7 +483,7 @@
 	if (sbi->s_prefix)
 		kfree(sbi->s_prefix);
 	kfree(sbi);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	return -EINVAL;
 }
 
@@ -550,11 +550,11 @@
 }
 
 static struct file_system_type affs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"affs",
-	get_sb:		affs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "affs",
+	.get_sb		= affs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_affs_fs(void)
diff -Nru a/fs/aio.c b/fs/aio.c
--- a/fs/aio.c	Fri Oct 11 21:22:57 2002
+++ b/fs/aio.c	Fri Oct 11 21:22:57 2002
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/aio_abi.h>
+#include <linux/module.h>
 
 //#define DEBUG 1
 
@@ -35,6 +36,7 @@
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
+#include <asm/mmu_context.h>
 
 #if DEBUG > 1
 #define dprintk		printk
@@ -59,6 +61,8 @@
 static spinlock_t	fput_lock = SPIN_LOCK_UNLOCKED;
 LIST_HEAD(fput_head);
 
+static void aio_kick_handler(void *);
+
 /* aio_setup
  *	Creates the slab caches used by the aio routines, panic on
  *	failure as this is done early during the boot sequence.
@@ -175,31 +179,28 @@
 	return 0;
 }
 
+
 /* aio_ring_event: returns a pointer to the event at the given index from
  * kmap_atomic(, km).  Release the pointer with put_aio_ring_event();
  */
-static inline struct io_event *aio_ring_event(struct aio_ring_info *info, int nr, enum km_type km)
-{
-	struct io_event *events;
 #define AIO_EVENTS_PER_PAGE	(PAGE_SIZE / sizeof(struct io_event))
 #define AIO_EVENTS_FIRST_PAGE	((PAGE_SIZE - sizeof(struct aio_ring)) / sizeof(struct io_event))
+#define AIO_EVENTS_OFFSET	(AIO_EVENTS_PER_PAGE - AIO_EVENTS_FIRST_PAGE)
 
-	if (nr < AIO_EVENTS_FIRST_PAGE) {
-		struct aio_ring *ring;
-		ring = kmap_atomic(info->ring_pages[0], km);
-		return &ring->io_events[nr];
-	}
-	nr -= AIO_EVENTS_FIRST_PAGE;
-
-	events = kmap_atomic(info->ring_pages[1 + nr / AIO_EVENTS_PER_PAGE], km);
-
-	return events + (nr % AIO_EVENTS_PER_PAGE);
-}
-
-static inline void put_aio_ring_event(struct io_event *event, enum km_type km)
-{
-	kunmap_atomic((void *)((unsigned long)event & PAGE_MASK), km);
-}
+#define aio_ring_event(info, nr, km) ({					\
+	unsigned pos = (nr) + AIO_EVENTS_OFFSET;			\
+	struct io_event *__event;					\
+	__event = kmap_atomic(						\
+			(info)->ring_pages[pos / AIO_EVENTS_PER_PAGE], km); \
+	__event += pos % AIO_EVENTS_PER_PAGE;				\
+	__event;							\
+})
+
+#define put_aio_ring_event(event, km) do {	\
+	struct io_event *__event = (event);	\
+	(void)__event;				\
+	kunmap_atomic((void *)((unsigned long)__event & PAGE_MASK), km); \
+} while(0)
 
 /* ioctx_alloc
  *	Allocates and initializes an ioctx.  Returns an ERR_PTR if it failed.
@@ -234,14 +235,18 @@
 	init_waitqueue_head(&ctx->wait);
 
 	INIT_LIST_HEAD(&ctx->active_reqs);
+	INIT_LIST_HEAD(&ctx->run_list);
+	INIT_WORK(&ctx->wq, aio_kick_handler, ctx);
 
 	if (aio_setup_ring(ctx) < 0)
 		goto out_freectx;
 
-	/* now link into global list.  kludge.  FIXME */
+	/* limit the number of system wide aios */
 	atomic_add(ctx->max_reqs, &aio_nr);	/* undone by __put_ioctx */
 	if (unlikely(atomic_read(&aio_nr) > aio_max_nr))
 		goto out_cleanup;
+
+	/* now link into global list.  kludge.  FIXME */
 	write_lock(&mm->ioctx_list_lock);
 	ctx->next = mm->ioctx_list;
 	mm->ioctx_list = ctx;
@@ -383,17 +388,26 @@
 {
 	struct kiocb *req = NULL;
 	struct aio_ring *ring;
+	int okay = 0;
 
 	req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL);
 	if (unlikely(!req))
 		return NULL;
 
+	req->ki_flags = 1 << KIF_LOCKED;
+	req->ki_users = 1;
+	req->ki_key = 0;
+	req->ki_ctx = ctx;
+	req->ki_cancel = NULL;
+	req->ki_retry = NULL;
+	req->ki_user_obj = NULL;
+
 	/* Check if the completion queue has enough free space to
 	 * accept an event from this io.
 	 */
 	spin_lock_irq(&ctx->ctx_lock);
 	ring = kmap_atomic(ctx->ring_info.ring_pages[0], KM_USER0);
-	if (likely(ctx->reqs_active < aio_ring_avail(&ctx->ring_info, ring))) {
+	if (ctx->reqs_active < aio_ring_avail(&ctx->ring_info, ring)) {
 		list_add(&req->ki_list, &ctx->active_reqs);
 		get_ioctx(ctx);
 		ctx->reqs_active++;
@@ -402,11 +416,16 @@
 		req->ki_users = 1;
 	} else {
 		kmem_cache_free(kiocb_cachep, req);
-		req = NULL;
+		okay = 1;
 	}
 	kunmap_atomic(ring, KM_USER0);
 	spin_unlock_irq(&ctx->ctx_lock);
 
+	if (!okay) {
+		kmem_cache_free(kiocb_cachep, req);
+		req = NULL;
+	}
+
 	return req;
 }
 
@@ -476,6 +495,7 @@
 		return 0;
 	list_del(&req->ki_list);		/* remove from active_reqs */
 	req->ki_cancel = NULL;
+	req->ki_retry = NULL;
 
 	/* Must be done under the lock to serialise against cancellation.
 	 * Call this aio_fput as it duplicates fput via the fput_work.
@@ -527,6 +547,82 @@
 	return ioctx;
 }
 
+static void use_mm(struct mm_struct *mm)
+{
+	struct mm_struct *active_mm = current->active_mm;
+	atomic_inc(&mm->mm_count);
+	current->mm = mm;
+	if (mm != active_mm) {
+		current->active_mm = mm;
+		activate_mm(active_mm, mm);
+	}
+	mmdrop(active_mm);
+}
+
+static void unuse_mm(struct mm_struct *mm)
+{
+	current->mm = NULL;
+	/* active_mm is still 'mm' */
+	enter_lazy_tlb(mm, current, smp_processor_id());
+}
+
+/* Run on kevent's context.  FIXME: needs to be per-cpu and warn if an
+ * operation blocks.
+ */
+static void aio_kick_handler(void *data)
+{
+	struct kioctx *ctx = data;
+
+	use_mm(ctx->mm);
+
+	spin_lock_irq(&ctx->ctx_lock);
+	while (!list_empty(&ctx->run_list)) {
+		struct kiocb *iocb;
+		long ret;
+
+		iocb = list_entry(ctx->run_list.next, struct kiocb,
+				  ki_run_list);
+		list_del(&iocb->ki_run_list);
+		iocb->ki_users ++;
+		spin_unlock_irq(&ctx->ctx_lock);
+
+		kiocbClearKicked(iocb);
+		ret = iocb->ki_retry(iocb);
+		if (-EIOCBQUEUED != ret) {
+			aio_complete(iocb, ret, 0);
+			iocb = NULL;
+		}
+
+		spin_lock_irq(&ctx->ctx_lock);
+		if (NULL != iocb)
+			__aio_put_req(ctx, iocb);
+	}
+	spin_unlock_irq(&ctx->ctx_lock);
+
+	unuse_mm(ctx->mm);
+}
+
+void kick_iocb(struct kiocb *iocb)
+{
+	struct kioctx	*ctx = iocb->ki_ctx;
+
+	/* sync iocbs are easy: they can only ever be executing from a 
+	 * single context. */
+	if (is_sync_kiocb(iocb)) {
+		kiocbSetKicked(iocb);
+		wake_up_process(iocb->ki_user_obj);
+		return;
+	}
+
+	if (!kiocbTryKick(iocb)) {
+		long flags;
+		spin_lock_irqsave(&ctx->ctx_lock, flags);
+		list_add_tail(&iocb->ki_run_list, &ctx->run_list);
+		spin_unlock_irqrestore(&ctx->ctx_lock, flags);
+		schedule_work(&ctx->wq);
+	}
+}
+
 /* aio_complete
  *	Called when the io request on the given iocb is complete.
  *	Returns true if this is the last user of the request.  The 
@@ -548,7 +644,7 @@
 	 * case the usage count checks will have to move under ctx_lock
 	 * for all cases.
 	 */
-	if (ctx == &ctx->mm->default_kioctx) {
+	if (is_sync_kiocb(iocb)) {
 		int ret;
 
 		iocb->ki_user_data = res;
@@ -560,7 +656,10 @@
 		iocb->ki_users--;
 		ret = (0 == iocb->ki_users);
 		spin_unlock_irq(&ctx->ctx_lock);
-		return 0;
+
+		/* sync iocbs put the task here for us */
+		wake_up_process(iocb->ki_user_obj);
+		return ret;
 	}
 
 	info = &ctx->ring_info;
@@ -940,6 +1039,7 @@
 
 	req->ki_user_obj = user_iocb;
 	req->ki_user_data = iocb->aio_data;
+	req->ki_pos = iocb->aio_offset;
 
 	buf = (char *)(unsigned long)iocb->aio_buf;
 
@@ -954,7 +1054,7 @@
 		ret = -EINVAL;
 		if (file->f_op->aio_read)
 			ret = file->f_op->aio_read(req, buf,
-					iocb->aio_nbytes, iocb->aio_offset);
+					iocb->aio_nbytes, req->ki_pos);
 		break;
 	case IOCB_CMD_PWRITE:
 		ret = -EBADF;
@@ -966,7 +1066,7 @@
 		ret = -EINVAL;
 		if (file->f_op->aio_write)
 			ret = file->f_op->aio_write(req, buf,
-					iocb->aio_nbytes, iocb->aio_offset);
+					iocb->aio_nbytes, req->ki_pos);
 		break;
 	case IOCB_CMD_FDSYNC:
 		ret = -EINVAL;
@@ -983,12 +1083,10 @@
 		ret = -EINVAL;
 	}
 
-	if (likely(EIOCBQUEUED == ret))
+	if (likely(-EIOCBQUEUED == ret))
 		return 0;
-	if (ret >= 0) {
-		aio_complete(req, ret, 0);
-		return 0;
-	}
+	aio_complete(req, ret, 0);
+	return 0;
 
 out_put_req:
 	aio_put_req(req);
diff -Nru a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
--- a/fs/autofs/autofs_i.h	Fri Oct 11 21:23:02 2002
+++ b/fs/autofs/autofs_i.h	Fri Oct 11 21:23:02 2002
@@ -111,7 +111,7 @@
 
 static inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
 {
-	return (struct autofs_sb_info *)(sb->u.generic_sbp);
+	return (struct autofs_sb_info *)(sb->s_fs_info);
 }
 
 /* autofs_oz_mode(): do we see the man behind the curtain?  (The
diff -Nru a/fs/autofs/init.c b/fs/autofs/init.c
--- a/fs/autofs/init.c	Fri Oct 11 21:23:00 2002
+++ b/fs/autofs/init.c	Fri Oct 11 21:23:00 2002
@@ -21,10 +21,10 @@
 }
 
 static struct file_system_type autofs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"autofs",
-	get_sb:		autofs_get_sb,
-	kill_sb:	kill_anon_super,
+	.owner		= THIS_MODULE,
+	.name		= "autofs",
+	.get_sb		= autofs_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 static int __init init_autofs_fs(void)
diff -Nru a/fs/autofs/inode.c b/fs/autofs/inode.c
--- a/fs/autofs/inode.c	Fri Oct 11 21:23:02 2002
+++ b/fs/autofs/inode.c	Fri Oct 11 21:23:02 2002
@@ -33,7 +33,7 @@
 			kfree(sbi->symlink[n].data);
 	}
 
-	kfree(sb->u.generic_sbp);
+	kfree(sb->s_fs_info);
 
 	DPRINTK(("autofs: shutting down\n"));
 }
@@ -41,9 +41,9 @@
 static void autofs_read_inode(struct inode *inode);
 
 static struct super_operations autofs_sops = {
-	read_inode:	autofs_read_inode,
-	put_super:	autofs_put_super,
-	statfs:		simple_statfs,
+	.read_inode	= autofs_read_inode,
+	.put_super	= autofs_put_super,
+	.statfs		= simple_statfs,
 };
 
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
@@ -126,7 +126,7 @@
 	memset(sbi, 0, sizeof(*sbi));
 	DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
 
-	s->u.generic_sbp = sbi;
+	s->s_fs_info = sbi;
 	sbi->magic = AUTOFS_SBI_MAGIC;
 	sbi->catatonic = 0;
 	sbi->exp_timeout = 0;
diff -Nru a/fs/autofs/root.c b/fs/autofs/root.c
--- a/fs/autofs/root.c	Fri Oct 11 21:22:58 2002
+++ b/fs/autofs/root.c	Fri Oct 11 21:22:58 2002
@@ -26,17 +26,17 @@
 static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 
 struct file_operations autofs_root_operations = {
-	read:		generic_read_dir,
-	readdir:	autofs_root_readdir,
-	ioctl:		autofs_root_ioctl,
+	.read		= generic_read_dir,
+	.readdir	= autofs_root_readdir,
+	.ioctl		= autofs_root_ioctl,
 };
 
 struct inode_operations autofs_root_inode_operations = {
-        lookup:		autofs_root_lookup,
-        unlink:		autofs_root_unlink,
-        symlink:	autofs_root_symlink,
-        mkdir:		autofs_root_mkdir,
-        rmdir:		autofs_root_rmdir,
+        .lookup		= autofs_root_lookup,
+        .unlink		= autofs_root_unlink,
+        .symlink	= autofs_root_symlink,
+        .mkdir		= autofs_root_mkdir,
+        .rmdir		= autofs_root_rmdir,
 };
 
 static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
@@ -192,7 +192,7 @@
 }
 
 static struct dentry_operations autofs_dentry_operations = {
-	d_revalidate:	autofs_revalidate,
+	.d_revalidate	= autofs_revalidate,
 };
 
 static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry)
diff -Nru a/fs/autofs/symlink.c b/fs/autofs/symlink.c
--- a/fs/autofs/symlink.c	Fri Oct 11 21:23:03 2002
+++ b/fs/autofs/symlink.c	Fri Oct 11 21:23:03 2002
@@ -25,6 +25,6 @@
 }
 
 struct inode_operations autofs_symlink_inode_operations = {
-	readlink:	autofs_readlink,
-	follow_link:	autofs_follow_link
+	.readlink	= autofs_readlink,
+	.follow_link	= autofs_follow_link
 };
diff -Nru a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
--- a/fs/autofs4/autofs_i.h	Fri Oct 11 21:23:01 2002
+++ b/fs/autofs4/autofs_i.h	Fri Oct 11 21:23:01 2002
@@ -98,7 +98,7 @@
 
 static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb)
 {
-	return (struct autofs_sb_info *)(sb->u.generic_sbp);
+	return (struct autofs_sb_info *)(sb->s_fs_info);
 }
 
 static inline struct autofs_info *autofs4_dentry_ino(struct dentry *dentry)
diff -Nru a/fs/autofs4/init.c b/fs/autofs4/init.c
--- a/fs/autofs4/init.c	Fri Oct 11 21:22:54 2002
+++ b/fs/autofs4/init.c	Fri Oct 11 21:22:54 2002
@@ -21,10 +21,10 @@
 }
 
 static struct file_system_type autofs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"autofs",
-	get_sb:		autofs_get_sb,
-	kill_sb:	kill_anon_super,
+	.owner		= THIS_MODULE,
+	.name		= "autofs",
+	.get_sb		= autofs_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 static int __init init_autofs4_fs(void)
diff -Nru a/fs/autofs4/inode.c b/fs/autofs4/inode.c
--- a/fs/autofs4/inode.c	Fri Oct 11 21:23:02 2002
+++ b/fs/autofs4/inode.c	Fri Oct 11 21:23:02 2002
@@ -80,7 +80,7 @@
 {
 	struct autofs_sb_info *sbi = autofs4_sbi(sb);
 
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 
 	if ( !sbi->catatonic )
 		autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */
@@ -91,8 +91,8 @@
 }
 
 static struct super_operations autofs4_sops = {
-	put_super:	autofs4_put_super,
-	statfs:		simple_statfs,
+	.put_super	= autofs4_put_super,
+	.statfs		= simple_statfs,
 };
 
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
@@ -189,7 +189,7 @@
 
 	memset(sbi, 0, sizeof(*sbi));
 
-	s->u.generic_sbp = sbi;
+	s->s_fs_info = sbi;
 	sbi->magic = AUTOFS_SBI_MAGIC;
 	sbi->catatonic = 0;
 	sbi->exp_timeout = 0;
diff -Nru a/fs/autofs4/root.c b/fs/autofs4/root.c
--- a/fs/autofs4/root.c	Fri Oct 11 21:22:51 2002
+++ b/fs/autofs4/root.c	Fri Oct 11 21:22:51 2002
@@ -27,28 +27,28 @@
 static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *);
 
 struct file_operations autofs4_root_operations = {
-	open:		dcache_dir_open,
-	release:	dcache_dir_close,
-	llseek:		dcache_dir_lseek,
-	read:		generic_read_dir,
-	readdir:	dcache_readdir,
-	ioctl:		autofs4_root_ioctl,
+	.open		= dcache_dir_open,
+	.release	= dcache_dir_close,
+	.llseek		= dcache_dir_lseek,
+	.read		= generic_read_dir,
+	.readdir	= dcache_readdir,
+	.ioctl		= autofs4_root_ioctl,
 };
 
 struct inode_operations autofs4_root_inode_operations = {
-	lookup:		autofs4_root_lookup,
-	unlink:		autofs4_dir_unlink,
-	symlink:	autofs4_dir_symlink,
-	mkdir:		autofs4_dir_mkdir,
-	rmdir:		autofs4_dir_rmdir,
+	.lookup		= autofs4_root_lookup,
+	.unlink		= autofs4_dir_unlink,
+	.symlink	= autofs4_dir_symlink,
+	.mkdir		= autofs4_dir_mkdir,
+	.rmdir		= autofs4_dir_rmdir,
 };
 
 struct inode_operations autofs4_dir_inode_operations = {
-	lookup:		autofs4_dir_lookup,
-	unlink:		autofs4_dir_unlink,
-	symlink:	autofs4_dir_symlink,
-	mkdir:		autofs4_dir_mkdir,
-	rmdir:		autofs4_dir_rmdir,
+	.lookup		= autofs4_dir_lookup,
+	.unlink		= autofs4_dir_unlink,
+	.symlink	= autofs4_dir_symlink,
+	.mkdir		= autofs4_dir_mkdir,
+	.rmdir		= autofs4_dir_rmdir,
 };
 
 /* Update usage from here to top of tree, so that scan of
@@ -215,14 +215,14 @@
 
 /* For dentries of directories in the root dir */
 static struct dentry_operations autofs4_root_dentry_operations = {
-	d_revalidate:	autofs4_root_revalidate,
-	d_release:	autofs4_dentry_release,
+	.d_revalidate	= autofs4_root_revalidate,
+	.d_release	= autofs4_dentry_release,
 };
 
 /* For other dentries */
 static struct dentry_operations autofs4_dentry_operations = {
-	d_revalidate:	autofs4_revalidate,
-	d_release:	autofs4_dentry_release,
+	.d_revalidate	= autofs4_revalidate,
+	.d_release	= autofs4_dentry_release,
 };
 
 /* Lookups in non-root dirs never find anything - if it's there, it's
diff -Nru a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
--- a/fs/autofs4/symlink.c	Fri Oct 11 21:23:00 2002
+++ b/fs/autofs4/symlink.c	Fri Oct 11 21:23:00 2002
@@ -27,6 +27,6 @@
 }
 
 struct inode_operations autofs4_symlink_inode_operations = {
-	readlink:	autofs4_readlink,
-	follow_link:	autofs4_follow_link
+	.readlink	= autofs4_readlink,
+	.follow_link	= autofs4_follow_link
 };
diff -Nru a/fs/bfs/bfs.h b/fs/bfs/bfs.h
--- a/fs/bfs/bfs.h	Fri Oct 11 21:22:50 2002
+++ b/fs/bfs/bfs.h	Fri Oct 11 21:22:50 2002
@@ -35,7 +35,7 @@
 
 static inline struct bfs_sb_info *BFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct bfs_inode_info *BFS_I(struct inode *inode)
diff -Nru a/fs/bfs/file.c b/fs/bfs/file.c
--- a/fs/bfs/file.c	Fri Oct 11 21:22:54 2002
+++ b/fs/bfs/file.c	Fri Oct 11 21:22:54 2002
@@ -145,7 +145,7 @@
 	return block_prepare_write(page, from, to, bfs_get_block);
 }
 
-static int bfs_bmap(struct address_space *mapping, long block)
+static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping, block, bfs_get_block);
 }
diff -Nru a/fs/bfs/inode.c b/fs/bfs/inode.c
--- a/fs/bfs/inode.c	Fri Oct 11 21:22:55 2002
+++ b/fs/bfs/inode.c	Fri Oct 11 21:22:55 2002
@@ -184,7 +184,7 @@
 	brelse(info->si_sbh);
 	kfree(info->si_imap);
 	kfree(info);
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 }
 
 static int bfs_statfs(struct super_block *s, struct statfs *buf)
@@ -267,7 +267,7 @@
 {
 #if 0
 	int i;
-	char *tmpbuf = (char *)get_free_page(GFP_KERNEL);
+	char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL);
 
 	if (!tmpbuf)
 		return;
@@ -294,7 +294,7 @@
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
-	s->u.generic_sbp = info;
+	s->s_fs_info = info;
 	memset(info, 0, sizeof(*info));
 
 	sb_set_blocksize(s, BFS_BSIZE);
@@ -370,7 +370,7 @@
 out:
 	brelse(bh);
 	kfree(info);
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	return -EINVAL;
 }
 
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Fri Oct 11 21:23:00 2002
+++ b/fs/bio.c	Fri Oct 11 21:23:00 2002
@@ -61,7 +61,7 @@
 	kmem_cache_free(data, ptr);
 }
 
-static inline struct bio_vec *bvec_alloc(int gfp_mask, int nr, int *idx)
+static inline struct bio_vec *bvec_alloc(int gfp_mask, int nr, unsigned long *idx)
 {
 	struct biovec_pool *bp;
 	struct bio_vec *bvl;
@@ -95,9 +95,11 @@
  */
 void bio_destructor(struct bio *bio)
 {
-	struct biovec_pool *bp = bvec_array + bio->bi_max;
+	const int pool_idx = BIO_POOL_IDX(bio);
+	struct biovec_pool *bp = bvec_array + pool_idx;
+
+	BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS);
 
-	BIO_BUG_ON(bio->bi_max >= BIOVEC_NR_POOLS);
 	/*
 	 * cloned bio doesn't own the veclist
 	 */
@@ -117,6 +119,7 @@
 	bio->bi_phys_segments = 0;
 	bio->bi_hw_segments = 0;
 	bio->bi_size = 0;
+	bio->bi_max_vecs = 0;
 	bio->bi_end_io = NULL;
 	atomic_set(&bio->bi_cnt, 1);
 }
@@ -133,27 +136,35 @@
  **/
 struct bio *bio_alloc(int gfp_mask, int nr_iovecs)
 {
-	struct bio *bio;
-	struct bio_vec *bvl = NULL;
 	int pf_flags = current->flags;
+	struct bio_vec *bvl = NULL;
+	unsigned long idx;
+	struct bio *bio;
 
 	current->flags |= PF_NOWARN;
 	bio = mempool_alloc(bio_pool, gfp_mask);
 	if (unlikely(!bio))
 		goto out;
 
-	if (!nr_iovecs || (bvl = bvec_alloc(gfp_mask,nr_iovecs,&bio->bi_max))) {
-		bio_init(bio);
-		bio->bi_destructor = bio_destructor;
-		bio->bi_io_vec = bvl;
+	bio_init(bio);
+
+	if (unlikely(!nr_iovecs))
 		goto out;
+
+	bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
+	if (bvl) {
+		bio->bi_flags |= idx << BIO_POOL_OFFSET;
+		bio->bi_max_vecs = bvec_array[idx].nr_vecs;
+		bio->bi_io_vec = bvl;
+		bio->bi_destructor = bio_destructor;
+out:
+		current->flags = pf_flags;
+		return bio;
 	}
 
 	mempool_free(bio, bio_pool);
 	bio = NULL;
-out:
-	current->flags = pf_flags;
-	return bio;
+	goto out;
 }
 
 /**
@@ -212,8 +223,8 @@
 	bio->bi_rw = bio_src->bi_rw;
 
 	/*
-	 * notes -- maybe just leave bi_idx alone. bi_max has no use
-	 * on a cloned bio. assume identical mapping for the clone
+	 * notes -- maybe just leave bi_idx alone. assume identical mapping
+	 * for the clone
 	 */
 	bio->bi_vcnt = bio_src->bi_vcnt;
 	bio->bi_idx = bio_src->bi_idx;
@@ -223,7 +234,14 @@
 		bio->bi_flags |= (1 << BIO_SEG_VALID);
 	}
 	bio->bi_size = bio_src->bi_size;
-	bio->bi_max = bio_src->bi_max;
+
+	/*
+	 * cloned bio does not own the bio_vec, so users cannot fiddle with
+	 * it. clear bi_max_vecs and clear the BIO_POOL_BITS to make this
+	 * apparent
+	 */
+	bio->bi_max_vecs = 0;
+	bio->bi_flags &= (BIO_POOL_MASK - 1);
 }
 
 /**
@@ -368,12 +386,7 @@
 	if (unlikely(bio_flagged(bio, BIO_CLONED)))
 		return 1;
 
-	/*
-	 * FIXME: change bi_max?
-	 */
-	BUG_ON(bio->bi_max > BIOVEC_NR_POOLS);
-
-	if (bio->bi_vcnt >= bvec_array[bio->bi_max].nr_vecs)
+	if (bio->bi_vcnt >= bio->bi_max_vecs)
 		return 1;
 
 	if (((bio->bi_size + len) >> 9) > q->max_sectors)
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Fri Oct 11 21:22:59 2002
+++ b/fs/buffer.c	Fri Oct 11 21:22:59 2002
@@ -29,6 +29,7 @@
 #include <linux/file.h>
 #include <linux/quotaops.h>
 #include <linux/iobuf.h>
+#include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/writeback.h>
 #include <linux/mempool.h>
@@ -461,12 +462,17 @@
 static void free_more_memory(void)
 {
 	struct zone *zone;
+	pg_data_t *pgdat;
 
-	zone = contig_page_data.node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones[0];
 	wakeup_bdflush(1024);
 	blk_run_queues();
 	yield();
-	try_to_free_pages(zone, GFP_NOFS, 0);
+
+	for_each_pgdat(pgdat) {
+		zone = pgdat->node_zonelists[GFP_NOFS&GFP_ZONEMASK].zones[0];
+		if (zone)
+			try_to_free_pages(zone, GFP_NOFS, 0);
+	}
 }
 
 /*
@@ -1770,7 +1776,7 @@
 		unsigned from, unsigned to, get_block_t *get_block)
 {
 	unsigned block_start, block_end;
-	unsigned long block;
+	sector_t block;
 	int err = 0;
 	unsigned blocksize, bbits;
 	struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
@@ -1786,7 +1792,7 @@
 	head = page_buffers(page);
 
 	bbits = inode->i_blkbits;
-	block = page->index << (PAGE_CACHE_SHIFT - bbits);
+	block = (sector_t)page->index << (PAGE_CACHE_SHIFT - bbits);
 
 	for(bh = head, block_start = 0; bh != head || !block_start;
 	    block++, block_start=block_end, bh = bh->b_this_page) {
@@ -1927,7 +1933,7 @@
 int block_read_full_page(struct page *page, get_block_t *get_block)
 {
 	struct inode *inode = page->mapping->host;
-	unsigned long iblock, lblock;
+	sector_t iblock, lblock;
 	struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
 	unsigned int blocksize, blocks;
 	int nr, i;
@@ -1942,7 +1948,7 @@
 	head = page_buffers(page);
 
 	blocks = PAGE_CACHE_SIZE >> inode->i_blkbits;
-	iblock = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+	iblock = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
 	lblock = (inode->i_size+blocksize-1) >> inode->i_blkbits;
 	bh = head;
 	nr = 0;
@@ -2448,7 +2454,7 @@
 			}
 		} else {
 			if (!buffer_uptodate(bh)) {
-				submit_bh(READ, bh);
+				submit_bh(rw, bh);
 				continue;
 			}
 		}
diff -Nru a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/AUTHORS	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,16 @@
+Original Author
+===============
+Steve French (sfrench@samba.org)
+
+The author wishes to express his appreciation and thanks to:
+Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
+improvements. Thanks to IBM for allowing me the time and test resources to pursue
+this project. Jim McDonough from IBM (and the Samba Team) for his help.
+The IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
+for proving years ago that a very good smb/cifs client could be done on a Unix like 
+operating system.  Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin 
+and others for their work on the Linux smbfs module over the years. Thanks to
+the other members of the Storage Network Industry Association CIFS Technical
+Workgroup for their work specifying this highly complex protocol and finally
+thanks to the Samba team for their technical advice and encouragement.
diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/CHANGES	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,142 @@
+Version 0.54
+------------
+Fix problem with captive thread hanging around at unmount time.  Adjust to 2.5.42-pre
+changes to superblock layout.   Remove wasteful allocation of smb buffers (now the send 
+buffer is reused for responses).  Add more oplock handling. Additional minor cleanup.
+
+Version 0.53
+------------
+More stylistic updates to better match kernel style.  Add additional statistics
+for filesystem which can be viewed via /proc/fs/cifs.  Add more pieces of NTLMv2
+and CIFS Packet Signing enablement.
+
+Version 0.52
+------------
+Replace call to sleep_on with safer wait_on_event.
+Make stylistic changes to better match kernel style recommendations.
+Remove most typedef usage (except for the PDUs themselves).
+
+Version 0.51
+------------
+Update mount so the -unc mount option is no longer required (the ip address can be specified
+in a UNC style device name.   Implementation of readpage/writepage started.
+
+Version 0.50
+------------
+Fix intermittent problem with incorrect smb header checking on badly 
+fragmented tcp responses
+
+Version 0.49
+------------
+Fixes to setting of allocation size and file size.
+
+Version 0.48
+------------
+Various 2.5.38 fixes.  Now works on 2.5.38
+
+Version 0.47
+------------
+Prepare for 2.5 kernel merge.  Remove ifdefs.
+
+Version 0.46
+------------
+Socket buffer management fixes.  Fix dual free.
+
+Version 0.45
+------------
+Various big endian fixes for hardlinks and symlinks and also for dfs.
+
+Version 0.44
+------------
+Various big endian fixes for servers with Unix extensions such as Samba
+
+Version 0.43
+------------
+Various FindNext fixes for incorrect filenames on large directory searches on big endian
+clients.  basic posix file i/o tests now work on big endian machines, not just le
+
+Version 0.42
+------------
+SessionSetup and NegotiateProtocol now work from Big Endian machines.
+Various Big Endian fixes found during testing on the Linux on 390.  Various fixes for compatability with older
+versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7).
+
+Version 0.41
+------------
+Various minor fixes for Connectathon Posix "basic" file i/o test suite.  Directory caching fixed so hardlinked
+files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked.
+
+Version 0.40
+------------
+Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate
+session advanced session authentication).  Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP.
+Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs
+(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos).
+
+Version 0.38
+------------
+Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable
+it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU).
+
+Version 0.37
+------------
+Rewrote much of connection and mount/unmount logic to handle bugs with
+multiple uses to same share, multiple users to same server etc.
+
+Version 0.36
+------------
+Fixed major problem with dentry corruption (missing call to dput)
+
+Version 0.35
+------------
+Rewrite of readdir code to fix bug. Various fixes for bigendian machines.
+Begin adding oplock support.  Multiusermount and oplockEnabled flags added to /proc/fs/cifs
+although corresponding function not fully implemented in the vfs yet
+
+Version 0.34
+------------
+Fixed dentry caching bug, misc. cleanup 
+
+Version 0.33
+------------
+Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes.  Now can build
+on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels.
+Support for STATUS codes (newer 32 bit NT error codes) added.  DFS support begun to be added.
+
+Version 0.32
+------------
+Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented
+and tested against Samba 2.2.5
+
+
+Version 0.31
+------------
+1) Fixed lockrange to be correct (it was one byte too short)
+
+2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly 
+show range as locked when there is a conflict with an existing lock.
+
+3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories
+in most cases.  Eventually will offer optional ability to query server for the correct perms.
+
+3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded 
+but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb
+session) 
+
+4) Fixed error logging of valid mount options
+
+5) Removed logging of password field.
+
+6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c
+and cleaned them up and made them more consistent with other cifs functions. 
+
+7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways 
+(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
+nor is the symlink support using the Unix extensions
+
+8) Started adding the readlink and follow_link code 
+
+Version 0.3 
+-----------
+Initial drop
+
diff -Nru a/fs/cifs/Makefile b/fs/cifs/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/Makefile	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,8 @@
+#
+# Makefile for Linux CIFS VFS client 
+#
+obj-$(CONFIG_CIFS) += cifs.o
+
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/fs/cifs/README b/fs/cifs/README
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/README	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,94 @@
+This is the CIFS VFS support for Linux.  It supports many advanced network filesystem
+features such as heirarchical dfs like filesystem, hardlinks, locking and more.
+It was designed to comply with the SNIA CIFS Technical Reference (which supersedes
+the 1992 X/Open SMB Standard) as well as to perform best practice practical
+interoperability with Windows 2000, Windows XP, Samba and equivalent 
+servers.  
+
+For questions or bug reports please contact sfrench@samba.org (sfrench@us.ibm.com)
+
+Build instructions:
+==================
+extract the kernel from http://www.cifs.bkbits.net/linux-2.5 or 
+http://www.cifs.bkbits.net/linux-2.4  
+make menuconfig (or make xconfig)
+select cifs from within the network filesystem choices
+save and exit
+make dep
+make modules  (or "make" if you did not select CIFS VFS to be built as a module)
+
+Installation instructions:
+=========================
+If you have built the CIFS vfs as module (successfully)you
+simply type "make modules_install" (or if you prefer manually copy the file to
+the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
+
+If you have built the CIFS vfs into the kernel itself, follow the instructions
+for your distribution on how to install a new kernel (usually you
+would simply type "make install").
+
+If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on the
+CIFS VFS web site) copy it to the directory /sbin (or the same directory in which 
+mount.smbfs resides).  Although no helper software is required, the installation
+of mount.cifs is recommended.  Eventually the Samba 3.0 utility program "net" 
+may also be helpful since it may someday provide easier mount syntax for users used 
+to Windows e.g.
+	 net use <mount point> <UNC name or cifs URL> 	 
+and there will likely be other helper programs available ala smbmount to provide
+additional optional function in the future.  Note that running Winbind on all
+of your Linux clients is useful in mapping Uids and Gids consistently to the
+proper network user.	
+
+Samba Considerations
+====================
+To get the maximum benefit from the CIFS VFS, we recommend using a server that
+supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or Samba 3.0)
+but the CIFS vfs works fine with a wide variety of CIFS servers.  Note that the
+uid, gid and file permissions will display default values if you do not have
+a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or
+later).   To enable the Unix CIFS Extensions in the Samba server, add the line:
+	unix extensions = yes
+to your smb.conf file on the server.  Note that the following smb.conf settings are
+also useful (on the Samba server) when the majority of clients are Unix
+or Linux:
+	case sensitive = yes
+	delete readonly = yes
+Some administrators also change the "map archive" and the "create mask" parameters
+from their defaults. For more information on these see the manual pages 
+("man smb.conf") on the Samba server system.  Note that the cifs vfs, unlike the
+smbfs vfs, does not read the smb.conf on the client system (the few optional settings
+are passed in on mount via -o parameters instead).
+
+Use instructions:
+================
+Once the CIFS VFS support is built into the kernel or installed as a module (cifs.o),
+you can use mount syntax like the following to access Samba or Windows servers:
+  mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword
+after -o the following cifs vfs specific options are supported:
+  user=<username>
+  pass=<password>
+  domain=<domain name>
+TCP names (in addition to ip addresses) will be available when the mount helper
+(mount.cifs) is complete
+
+Restrictions
+============
+Servers must support the NTLM SMB dialect (which is the most recent, supported by Samba
+and Windows NT, 2000 and XP and many other SMB/CIFS servers) and servers must support
+either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 1001/1002 support for
+"Netbios-Over-TCP/IP."  Neither of these is likely to be a problem as most servers
+support this.  IPv6 support is planned for the future.
+
+Misc /proc/fs/cifs Flags and Debug Info
+=======================================
+Various experimental features and tracing can be enabled by changing flags in /proc/fs/cifs (after
+the cifs module has been installed or built into the kernel, e.g. insmod cifs).  To enable
+a feature you can set it to 1 e.g. to enable tracing to the kernel message log you can do
+"echo 1 > /proc/fs/cifs/cifsFYI" and "echo 1 > /proc/fs/cifs/traceSMB"
+Also note that "cat /proc/fs/cifs/DebugData" will display some information about the currently
+active sessions and the shares that are mounted. Currently the ntlmv2 enablement and packet
+signing will not work since they the implementation is not quite complete, so do not enable
+these flags unless you are doing specific testing.  Enabling extended security works to
+Windows 2000 Workstations and XP but not to Windows 2000 server or Samba since it does not
+usually send "raw NTLMSSP" (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which
+support is not complete in the CIFS VFS yet).
diff -Nru a/fs/cifs/TODO b/fs/cifs/TODO
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/TODO	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,55 @@
+version 0.5.3 October 8th, 2002
+
+A Partial List of Known Problems and Missing Features
+=====================================================
+
+Contributions are welcome.  There are plenty of opportunities
+for visible, important contributions to this module.  Here
+is a partial list of the known problems and missing features:
+
+a) Support for SecurityDescriptors for chmod/chgrp/chown
+
+b) Better pam/winbind integration
+
+c) multi-user mounts - multiplexed sessionsetups over single vc
+(ie tcp session) - prettying up needed
+
+d) Kerberos/SPNEGO session setup support - (started)
+
+e)NTLMv2 authentication and MD5-HMAC signing of SMB PDUs - (mostly implemented)
+
+f) oplock support (ie safe CIFS distributed file caching) is not complete.
+In addition Directory entry caching relies on a 1 second timer, rather than 
+using FindNotify or equivalent.  - (started)
+
+g) There may be a few additional changes that could be done to take advantage
+of recent 2.5 kernel improvements in byte-range locking
+
+h) quota support
+
+i) support for the Linux 2.5 kernel new feature get_xattr and set_xattr
+
+j) finish off the mount helper, mount.cifs - (started)
+
+k) support for memory mapped files only partially works until support for
+MS_INVALIDATE implemented.  readpage and writepage code not finished (started)
+
+KNOWN BUGS (updated October 8nd, 2002)
+====================================
+1) symbolic links (Windows reparse points) are recognized but
+can not be created remotely. They are implemented for Samba and those that
+support the CIFS Unix extensions but Samba has a bug currently handling
+symlink text beginning with slash
+2) delete of file with read-only attribute set will fail (may be ok)
+3) autoreconnection logic is only partially complete.
+
+Misc testing to do
+=================
+1) check out max path names and max path name components against various server
+types.
+
+2) Run POSIX bencharks against cifs
+
+3) Run dbench
+
+4) Finish FSX testing on SMP now that we workaround the Samba bug
diff -Nru a/fs/cifs/asn1.c b/fs/cifs/asn1.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/asn1.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,615 @@
+/* 
+ * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
+ * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
+ *      
+ * Copyright (c) 2000 RP Internet (www.rpi.net.au).
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifs_debug.h"
+
+/*****************************************************************************
+ *
+ * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse)
+ *
+ *****************************************************************************/
+
+/* Class */
+#define ASN1_UNI	0	/* Universal */
+#define ASN1_APL	1	/* Application */
+#define ASN1_CTX	2	/* Context */
+#define ASN1_PRV	3	/* Private */
+
+/* Tag */
+#define ASN1_EOC	0	/* End Of Contents or N/A */
+#define ASN1_BOL	1	/* Boolean */
+#define ASN1_INT	2	/* Integer */
+#define ASN1_BTS	3	/* Bit String */
+#define ASN1_OTS	4	/* Octet String */
+#define ASN1_NUL	5	/* Null */
+#define ASN1_OJI	6	/* Object Identifier  */
+#define ASN1_OJD	7	/* Object Description */
+#define ASN1_EXT	8	/* External */
+#define ASN1_SEQ	16	/* Sequence */
+#define ASN1_SET	17	/* Set */
+#define ASN1_NUMSTR	18	/* Numerical String */
+#define ASN1_PRNSTR	19	/* Printable String */
+#define ASN1_TEXSTR	20	/* Teletext String */
+#define ASN1_VIDSTR	21	/* Video String */
+#define ASN1_IA5STR	22	/* IA5 String */
+#define ASN1_UNITIM	23	/* Universal Time */
+#define ASN1_GENTIM	24	/* General Time */
+#define ASN1_GRASTR	25	/* Graphical String */
+#define ASN1_VISSTR	26	/* Visible String */
+#define ASN1_GENSTR	27	/* General String */
+
+/* Primitive / Constructed methods*/
+#define ASN1_PRI	0	/* Primitive */
+#define ASN1_CON	1	/* Constructed */
+
+/*
+ * Error codes.
+ */
+#define ASN1_ERR_NOERROR		0
+#define ASN1_ERR_DEC_EMPTY		2
+#define ASN1_ERR_DEC_EOC_MISMATCH	3
+#define ASN1_ERR_DEC_LENGTH_MISMATCH	4
+#define ASN1_ERR_DEC_BADVALUE		5
+
+#define SPNEGO_OID_LEN 7
+#define NTLMSSP_OID_LEN  10
+unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
+unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
+
+/* 
+ * ASN.1 context.
+ */
+struct asn1_ctx {
+	int error;		/* Error condition */
+	unsigned char *pointer;	/* Octet just to be decoded */
+	unsigned char *begin;	/* First octet */
+	unsigned char *end;	/* Octet after last octet */
+};
+
+/*
+ * Octet string (not null terminated)
+ */
+struct asn1_octstr {
+	unsigned char *data;
+	unsigned int len;
+};
+
+static void
+asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len)
+{
+	ctx->begin = buf;
+	ctx->end = buf + len;
+	ctx->pointer = buf;
+	ctx->error = ASN1_ERR_NOERROR;
+}
+
+static unsigned char
+asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
+{
+	if (ctx->pointer >= ctx->end) {
+		ctx->error = ASN1_ERR_DEC_EMPTY;
+		return 0;
+	}
+	*ch = *(ctx->pointer)++;
+	return 1;
+}
+
+static unsigned char
+asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
+{
+	unsigned char ch;
+
+	*tag = 0;
+
+	do {
+		if (!asn1_octet_decode(ctx, &ch))
+			return 0;
+		*tag <<= 7;
+		*tag |= ch & 0x7F;
+	} while ((ch & 0x80) == 0x80);
+	return 1;
+}
+
+static unsigned char
+asn1_id_decode(struct asn1_ctx *ctx,
+	       unsigned int *cls, unsigned int *con, unsigned int *tag)
+{
+	unsigned char ch;
+
+	if (!asn1_octet_decode(ctx, &ch))
+		return 0;
+
+	*cls = (ch & 0xC0) >> 6;
+	*con = (ch & 0x20) >> 5;
+	*tag = (ch & 0x1F);
+
+	if (*tag == 0x1F) {
+		if (!asn1_tag_decode(ctx, tag))
+			return 0;
+	}
+	return 1;
+}
+
+static unsigned char
+asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len)
+{
+	unsigned char ch, cnt;
+
+	if (!asn1_octet_decode(ctx, &ch))
+		return 0;
+
+	if (ch == 0x80)
+		*def = 0;
+	else {
+		*def = 1;
+
+		if (ch < 0x80)
+			*len = ch;
+		else {
+			cnt = (unsigned char) (ch & 0x7F);
+			*len = 0;
+
+			while (cnt > 0) {
+				if (!asn1_octet_decode(ctx, &ch))
+					return 0;
+				*len <<= 8;
+				*len |= ch;
+				cnt--;
+			}
+		}
+	}
+	return 1;
+}
+
+static unsigned char
+asn1_header_decode(struct asn1_ctx *ctx,
+		   unsigned char **eoc,
+		   unsigned int *cls, unsigned int *con, unsigned int *tag)
+{
+	unsigned int def, len;
+
+	if (!asn1_id_decode(ctx, cls, con, tag))
+		return 0;
+
+	if (!asn1_length_decode(ctx, &def, &len))
+		return 0;
+
+	if (def)
+		*eoc = ctx->pointer + len;
+	else
+		*eoc = 0;
+	return 1;
+}
+
+static unsigned char
+asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
+{
+	unsigned char ch;
+
+	if (eoc == 0) {
+		if (!asn1_octet_decode(ctx, &ch))
+			return 0;
+
+		if (ch != 0x00) {
+			ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
+			return 0;
+		}
+
+		if (!asn1_octet_decode(ctx, &ch))
+			return 0;
+
+		if (ch != 0x00) {
+			ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
+			return 0;
+		}
+		return 1;
+	} else {
+		if (ctx->pointer != eoc) {
+			ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH;
+			return 0;
+		}
+		return 1;
+	}
+}
+
+/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx,
+				      unsigned char *eoc)
+{
+	ctx->pointer = eoc;
+	return 1;
+}
+
+static unsigned char asn1_long_decode(struct asn1_ctx *ctx,
+				      unsigned char *eoc, long *integer)
+{
+	unsigned char ch;
+	unsigned int len;
+
+	if (!asn1_octet_decode(ctx, &ch))
+		return 0;
+
+	*integer = (signed char) ch;
+	len = 1;
+
+	while (ctx->pointer < eoc) {
+		if (++len > sizeof(long)) {
+			ctx->error = ASN1_ERR_DEC_BADVALUE;
+			return 0;
+		}
+
+		if (!asn1_octet_decode(ctx, &ch))
+			return 0;
+
+		*integer <<= 8;
+		*integer |= ch;
+	}
+	return 1;
+}
+
+static unsigned char asn1_uint_decode(struct asn1_ctx *ctx,
+				      unsigned char *eoc,
+				      unsigned int *integer)
+{
+	unsigned char ch;
+	unsigned int len;
+
+	if (!asn1_octet_decode(ctx, &ch))
+		return 0;
+
+	*integer = ch;
+	if (ch == 0)
+		len = 0;
+	else
+		len = 1;
+
+	while (ctx->pointer < eoc) {
+		if (++len > sizeof(unsigned int)) {
+			ctx->error = ASN1_ERR_DEC_BADVALUE;
+			return 0;
+		}
+
+		if (!asn1_octet_decode(ctx, &ch))
+			return 0;
+
+		*integer <<= 8;
+		*integer |= ch;
+	}
+	return 1;
+}
+
+static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx,
+				       unsigned char *eoc,
+				       unsigned long *integer)
+{
+	unsigned char ch;
+	unsigned int len;
+
+	if (!asn1_octet_decode(ctx, &ch))
+		return 0;
+
+	*integer = ch;
+	if (ch == 0)
+		len = 0;
+	else
+		len = 1;
+
+	while (ctx->pointer < eoc) {
+		if (++len > sizeof(unsigned long)) {
+			ctx->error = ASN1_ERR_DEC_BADVALUE;
+			return 0;
+		}
+
+		if (!asn1_octet_decode(ctx, &ch))
+			return 0;
+
+		*integer <<= 8;
+		*integer |= ch;
+	}
+	return 1;
+} 
+
+static unsigned char
+asn1_octets_decode(struct asn1_ctx *ctx,
+		   unsigned char *eoc,
+		   unsigned char **octets, unsigned int *len)
+{
+	unsigned char *ptr;
+
+	*len = 0;
+
+	*octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC);
+	if (*octets == NULL) {
+		return 0;
+	}
+
+	ptr = *octets;
+	while (ctx->pointer < eoc) {
+		if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) {
+			kfree(*octets);
+			*octets = NULL;
+			return 0;
+		}
+		(*len)++;
+	}
+	return 1;
+} */
+
+static unsigned char
+asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid)
+{
+	unsigned char ch;
+
+	*subid = 0;
+
+	do {
+		if (!asn1_octet_decode(ctx, &ch))
+			return 0;
+
+		*subid <<= 7;
+		*subid |= ch & 0x7F;
+	} while ((ch & 0x80) == 0x80);
+	return 1;
+}
+
+static unsigned char
+asn1_oid_decode(struct asn1_ctx *ctx,
+		unsigned char *eoc, unsigned long **oid, unsigned int *len)
+{
+	unsigned long subid;
+	unsigned int size;
+	unsigned long *optr;
+
+	size = eoc - ctx->pointer + 1;
+	*oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC);
+	if (*oid == NULL) {
+		return 0;
+	}
+
+	optr = *oid;
+
+	if (!asn1_subid_decode(ctx, &subid)) {
+		kfree(*oid);
+		*oid = NULL;
+		return 0;
+	}
+
+	if (subid < 40) {
+		optr[0] = 0;
+		optr[1] = subid;
+	} else if (subid < 80) {
+		optr[0] = 1;
+		optr[1] = subid - 40;
+	} else {
+		optr[0] = 2;
+		optr[1] = subid - 80;
+	}
+
+	*len = 2;
+	optr += 2;
+
+	while (ctx->pointer < eoc) {
+		if (++(*len) > size) {
+			ctx->error = ASN1_ERR_DEC_BADVALUE;
+			kfree(*oid);
+			*oid = NULL;
+			return 0;
+		}
+
+		if (!asn1_subid_decode(ctx, optr++)) {
+			kfree(*oid);
+			*oid = NULL;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int
+compare_oid(unsigned long *oid1, unsigned int oid1len,
+	    unsigned long *oid2, unsigned int oid2len)
+{
+	int i;
+
+	if (oid1len != oid2len)
+		return 0;
+	else {
+		for (i = 0; i < oid1len; i++) {
+			if (oid1[i] != oid2[i])
+				return 0;
+		}
+		return 1;
+	}
+}
+
+	/* BB check for endian conversion issues here */
+
+int
+decode_negTokenInit(unsigned char *security_blob, int length,
+		    enum securityEnum *secType)
+{
+	struct asn1_ctx ctx;
+	unsigned char *end;
+	unsigned char *sequence_end;
+	unsigned long *oid;
+	unsigned int cls, con, tag, oidlen, rc;
+	int use_ntlmssp = FALSE;
+
+	dump_mem(" Received SecBlob ", security_blob, length);
+
+	asn1_open(&ctx, security_blob, length);
+
+	if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+		cFYI(1, ("\nError decoding negTokenInit header "));
+		return 0;
+	} else if ((cls != ASN1_APL) || (con != ASN1_CON)
+		   || (tag != ASN1_EOC)) {
+		cFYI(1, ("\ncls = %d con = %d tag = %d", cls, con, tag));
+		return 0;
+	} else {
+		/*      remember to free obj->oid */
+		rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+		if (rc) {
+			if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) {
+				rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
+				if (rc) {
+					rc = compare_oid(oid, oidlen,
+							 SPNEGO_OID,
+							 SPNEGO_OID_LEN);
+					kfree(oid);
+				}
+			} else
+				rc = 0;
+		}
+
+		if (!rc) {
+			cFYI(1, ("\nError decoding negTokenInit header"));
+			return 0;
+		}
+
+		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+			cFYI(1, ("\nError decoding negTokenInit "));
+			return 0;
+		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
+			   || (tag != ASN1_EOC)) {
+			cFYI(1,
+			     ("\ncls = %d con = %d tag = %d end = %p (%d) exit 0",
+			      cls, con, tag, end, *end));
+			return 0;
+		}
+
+		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+			cFYI(1, ("\nError decoding negTokenInit "));
+			return 0;
+		} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+			   || (tag != ASN1_SEQ)) {
+			cFYI(1,
+			     ("\ncls = %d con = %d tag = %d end = %p (%d) exit 1",
+			      cls, con, tag, end, *end));
+			return 0;
+		}
+
+		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+			cFYI(1, ("\nError decoding 2nd part of negTokenInit "));
+			return 0;
+		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
+			   || (tag != ASN1_EOC)) {
+			cFYI(1,
+			     ("\ncls = %d con = %d tag = %d end = %p (%d) exit 0",
+			      cls, con, tag, end, *end));
+			return 0;
+		}
+
+		if (asn1_header_decode
+		    (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
+			cFYI(1, ("\nError decoding 2nd part of negTokenInit "));
+			return 0;
+		} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+			   || (tag != ASN1_SEQ)) {
+			cFYI(1,
+			     ("\ncls = %d con = %d tag = %d end = %p (%d) exit 1",
+			      cls, con, tag, end, *end));
+			return 0;
+		}
+
+		while (!asn1_eoc_decode(&ctx, sequence_end)) {
+			rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+			if (!rc) {
+				cFYI(1,
+				     ("\nError 1 decoding negTokenInit header exit 2"));
+				return 0;
+			}
+			if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
+				asn1_oid_decode(&ctx, end, &oid, &oidlen);
+				cFYI(1,
+				     ("\nOID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx",
+				      oidlen, *oid, *(oid + 1), *(oid + 2),
+				      *(oid + 3)));
+				rc = compare_oid(oid, oidlen, NTLMSSP_OID,
+						 NTLMSSP_OID_LEN);
+				kfree(oid);
+				if (rc)
+					use_ntlmssp = TRUE;
+			} else {
+				cFYI(1,
+				     ("\nThis should be an oid what is going on? "));
+			}
+		}
+
+		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+			cFYI(1,
+			     ("\nError decoding last part of negTokenInit exit 3"));
+			return 0;
+		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {	/* tag = 3 indicating mechListMIC */
+			cFYI(1,
+			     ("\nExit 4 cls = %d con = %d tag = %d end = %p (%d)",
+			      cls, con, tag, end, *end));
+			return 0;
+		}
+		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+			cFYI(1,
+			     ("\nError decoding last part of negTokenInit exit 5"));
+			return 0;
+		} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+			   || (tag != ASN1_SEQ)) {
+			cFYI(1,
+			     ("\nExit 6 cls = %d con = %d tag = %d end = %p (%d)",
+			      cls, con, tag, end, *end));
+		}
+
+		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+			cFYI(1,
+			     ("\nError decoding last part of negTokenInit exit 7"));
+			return 0;
+		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
+			cFYI(1,
+			     ("\nExit 8 cls = %d con = %d tag = %d end = %p (%d)",
+			      cls, con, tag, end, *end));
+			return 0;
+		}
+		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+			cFYI(1,
+			     ("\nError decoding last part of negTokenInit exit 9"));
+			return 0;
+		} else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
+			   || (tag != ASN1_GENSTR)) {
+			cFYI(1,
+			     ("\nExit 10 cls = %d con = %d tag = %d end = %p (%d)",
+			      cls, con, tag, end, *end));
+			return 0;
+		}
+		cFYI(1, ("\nNeed to call asn1_octets_decode() function for this %s", ctx.pointer));	/* is this UTF-8 or ASCII? */
+	}
+
+	/* if (use_kerberos) 
+	   *secType = Kerberos 
+	   else */
+	if (use_ntlmssp) {
+		*secType = NTLMSSP;
+	}
+
+	return 1;
+}
diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifs_debug.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,546 @@
+/*
+ *   fs/cifs_debug.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000,2002
+ *
+ *   Modified by Steve French (sfrench@us.ibm.com)
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+
+void
+dump_mem(char *label, void *data, int length)
+{
+	int i, j;
+	int *intptr = data;
+	char *charptr = data;
+	char buf[10], line[80];
+
+	printk("%s: dump of %d bytes of data at 0x%p\n\n", label, length, data);
+	for (i = 0; i < length; i += 16) {
+		line[0] = 0;
+		for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
+			sprintf(buf, " %08x", intptr[i / 4 + j]);
+			strcat(line, buf);
+		}
+		buf[0] = ' ';
+		buf[2] = 0;
+		for (j = 0; (j < 16) && (i + j < length); j++) {
+			buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.';
+			strcat(line, buf);
+		}
+		printk("%s\n", line);
+	}
+}
+
+#if CONFIG_PROC_FS
+int
+cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
+		     int count, int *eof, void *data)
+{
+	struct list_head *tmp;
+	struct cifsSesInfo *ses;
+	struct cifsTconInfo *tcon;
+	int i;
+	int length = 0;
+	char *buf_start = buf;
+
+	printk("\n\nEntering cifs_debug_data_read:  buf=0x%p, beginBuffer=0x%p, offset=%ld, count=%d, eof=%d, data=0x%p\n", buf, *beginBuffer, offset, count, *eof, data);	/* BB remove */
+	length =
+	    sprintf(buf,
+		    "Display Internal CIFS Data Structures for Debugging\n"
+		    "---------------------------------------------------\n");
+	buf += length;
+
+	length = sprintf(buf, "Servers: \n");
+	buf += length;
+
+	i = 0;
+	list_for_each(tmp, &GlobalSMBSessionList) {
+		i++;
+		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+		length =
+		    sprintf(buf,
+			    "\n%d) Name: %s  Domain: %s HowManyMounts: %d LocalUsersToSameServer: %d\n\t ServerOS: %s  ServerNOS: %s  Capabilities: 0x%x ",
+			    i, ses->serverName, ses->serverDomain,
+			    atomic_read(&ses->inUse),
+			    atomic_read(&ses->server->socketUseCount),
+			    ses->serverOS, ses->serverNOS, ses->capabilities);
+		buf += length;
+	}
+	sprintf(buf, "\n");
+	buf++;
+	printk("\nTotal Buffer so far: %s\n", buf_start);
+
+	length = sprintf(buf, "\nShares: \n");
+	buf += length;
+
+	i = 0;
+	list_for_each(tmp, &GlobalTreeConnectionList) {
+		i++;
+		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+		length =
+		    sprintf(buf,
+			    "\n%d) %s UseCount: %d on FS: %s with characteristics: 0x%x Attributes: 0x%x and PathComponentLengthMax: %d",
+			    i, tcon->treeName,
+			    atomic_read(&tcon->useCount),
+			    tcon->nativeFileSystem,
+			    tcon->fsDevInfo.DeviceCharacteristics,
+			    tcon->fsAttrInfo.Attributes,
+			    tcon->fsAttrInfo.MaxPathNameComponentLength);
+		buf += length;        
+		if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_DISK)
+			length = sprintf(buf, " type: DISK ");
+		else if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_CD_ROM)
+			length = sprintf(buf, " type: CDROM ");
+		else
+			length =
+			    sprintf(buf, " type: %d ",
+				    tcon->fsDevInfo.DeviceType);
+		buf += length;
+	}
+	length = sprintf(buf, "\n");
+	buf += length;
+	*eof = 1;
+	/* BB add code to dump additional info such as TCP session info now */
+	/*
+	   if (offset >= (buf - buf_start)) 
+	   {
+	   *beginBuffer = buf;
+	   return 0;
+	   }
+	   *beginBuffer = buf + offset;
+	   if ((buf - buf_start - offset) > count)
+	   return count;
+   else */
+	return (buf - buf_start - offset);
+}
+
+int
+cifs_total_xid_read(char *buf, char **beginBuffer, off_t offset,
+		    int length, int *eof, void *data)
+{
+
+	length =
+	    sprintf(buf,
+		    "Total vfs operations: %d and maximum simultaneous serviced by this filesystem: %d\n",
+		    GlobalCurrentXid,GlobalMaxActiveXid);
+
+	return length;
+}
+
+int
+cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
+		  int length, int *eof, void *data)
+{
+   int item_length;
+	length =
+	    sprintf(buf,
+		    "Currently Allocated structures\nCIFS Sessions: %d\n",sesInfoAllocCount.counter);
+    buf += length;
+    item_length = 
+        sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter);
+    length += item_length;
+    buf += item_length;      
+    item_length = 
+        sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter);
+    length += item_length;
+    buf += item_length;      
+    item_length = 
+        sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter);
+    length += item_length;
+
+	return length;
+}
+
+struct proc_dir_entry *proc_fs_cifs;
+read_proc_t cifs_txanchor_read;
+static read_proc_t cifsFYI_read;
+static write_proc_t cifsFYI_write;
+static read_proc_t oplockEnabled_read;
+static write_proc_t oplockEnabled_write;
+static read_proc_t traceSMB_read;
+static write_proc_t traceSMB_write;
+static read_proc_t multiuser_mount_read;
+static write_proc_t multiuser_mount_write;
+static read_proc_t extended_security_read;
+static write_proc_t extended_security_write;
+static read_proc_t ntlmv2_enabled_read;
+static write_proc_t ntlmv2_enabled_write;
+static read_proc_t packet_signing_enabled_read;
+static write_proc_t packet_signing_enabled_write;
+
+void
+cifs_proc_init(void)
+{
+	struct proc_dir_entry *pde;
+
+	proc_fs_cifs = proc_mkdir("cifs", proc_root_fs);
+	if (proc_fs_cifs == NULL)
+		return;
+
+	proc_fs_cifs->owner = THIS_MODULE;
+	create_proc_read_entry("DebugData", 0, proc_fs_cifs,
+			       cifs_debug_data_read, 0);
+
+	create_proc_read_entry("SimultaneousOps", 0, proc_fs_cifs,
+			       cifs_total_xid_read, 0);
+
+	create_proc_read_entry("Stats", 0, proc_fs_cifs,
+			       cifs_stats_read, 0);
+
+	pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
+				     cifsFYI_read, 0);
+	if (pde)
+		pde->write_proc = cifsFYI_write;
+
+	pde =
+	    create_proc_read_entry("traceSMB", 0, proc_fs_cifs,
+				   traceSMB_read, 0);
+	if (pde)
+		pde->write_proc = traceSMB_write;
+
+	pde = create_proc_read_entry("oplockEnabled", 0, proc_fs_cifs,
+				     oplockEnabled_read, 0);
+	if (pde)
+		pde->write_proc = oplockEnabled_write;
+
+	pde =
+	    create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs,
+				   multiuser_mount_read, 0);
+	if (pde)
+		pde->write_proc = multiuser_mount_write;
+
+	pde =
+	    create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
+				   extended_security_read, 0);
+	if (pde)
+		pde->write_proc = extended_security_write;
+
+	pde =
+	    create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
+				   ntlmv2_enabled_read, 0);
+	if (pde)
+		pde->write_proc = ntlmv2_enabled_write;
+
+	pde =
+	    create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
+				   packet_signing_enabled_read, 0);
+	if (pde)
+		pde->write_proc = packet_signing_enabled_write;
+}
+
+void
+cifs_proc_clean(void)
+{
+	if (proc_fs_cifs == NULL)
+		return;
+
+	remove_proc_entry("DebugData", proc_fs_cifs);
+	remove_proc_entry("cifsFYI", proc_fs_cifs);
+	remove_proc_entry("TraceSMB", proc_fs_cifs);
+	remove_proc_entry("MaxSimultaneousOps", proc_fs_cifs);
+	remove_proc_entry("TotalOps", proc_fs_cifs);
+	remove_proc_entry("MultiuserMount", proc_fs_cifs);
+	remove_proc_entry("oplockEnabled", proc_fs_cifs);
+	remove_proc_entry("cifs", proc_root_fs);
+}
+
+static int
+cifsFYI_read(char *page, char **start, off_t off, int count,
+	     int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", cifsFYI);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+static int
+cifsFYI_write(struct file *file, const char *buffer,
+	      unsigned long count, void *data)
+{
+	char c;
+	int rc;
+
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		cifsFYI = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		cifsFYI = 1;
+
+	return count;
+}
+
+static int
+oplockEnabled_read(char *page, char **start, off_t off,
+		   int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", oplockEnabled);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+static int
+oplockEnabled_write(struct file *file, const char *buffer,
+		    unsigned long count, void *data)
+{
+	char c;
+	int rc;
+
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		oplockEnabled = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		oplockEnabled = 1;
+
+	return count;
+}
+
+static int
+traceSMB_read(char *page, char **start, off_t off, int count,
+	      int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", traceSMB);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+static int
+traceSMB_write(struct file *file, const char *buffer,
+	       unsigned long count, void *data)
+{
+	char c;
+	int rc;
+
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		traceSMB = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		traceSMB = 1;
+
+	return count;
+}
+
+static int
+multiuser_mount_read(char *page, char **start, off_t off,
+		     int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", multiuser_mount);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+static int
+multiuser_mount_write(struct file *file, const char *buffer,
+		      unsigned long count, void *data)
+{
+	char c;
+	int rc;
+
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		multiuser_mount = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		multiuser_mount = 1;
+
+	return count;
+}
+
+static int
+extended_security_read(char *page, char **start, off_t off,
+		       int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", extended_security);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+static int
+extended_security_write(struct file *file, const char *buffer,
+			unsigned long count, void *data)
+{
+	char c;
+	int rc;
+
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		extended_security = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		extended_security = 1;
+
+	return count;
+}
+
+static int
+ntlmv2_enabled_read(char *page, char **start, off_t off,
+		       int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", ntlmv2_support);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+static int
+ntlmv2_enabled_write(struct file *file, const char *buffer,
+			unsigned long count, void *data)
+{
+	char c;
+	int rc;
+
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		ntlmv2_support = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		ntlmv2_support = 1;
+
+	return count;
+}
+
+static int
+packet_signing_enabled_read(char *page, char **start, off_t off,
+		       int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", sign_CIFS_PDUs);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+static int
+packet_signing_enabled_write(struct file *file, const char *buffer,
+			unsigned long count, void *data)
+{
+	char c;
+	int rc;
+
+	rc = get_user(c, buffer);
+	if (rc)
+		return rc;
+	if (c == '0' || c == 'n' || c == 'N')
+		sign_CIFS_PDUs = 0;
+	else if (c == '1' || c == 'y' || c == 'Y')
+		sign_CIFS_PDUs = 1;
+
+	return count;
+}
+
+
+#endif
diff -Nru a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifs_debug.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,74 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000,2002
+ *   Modified by Steve French (sfrench@us.ibm.com)
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+#define CIFS_DEBUG		/* BB temporary */
+
+#ifndef _H_CIFS_DEBUG
+#define _H_CIFS_DEBUG
+
+void dump_mem(char *label, void *data, int length);
+extern int traceSMB;		/* flag which enables the function below */
+void dump_smb(struct smb_hdr *, int);
+
+/*
+ *	debug ON
+ *	--------
+ */
+#ifdef CIFS_DEBUG
+
+/* information message: e.g., configuration, major event */
+extern int cifsFYI;
+#define cFYI(button,prspec)\
+{ if (button && cifsFYI) printk prspec; }
+
+/* debug event message: */
+#define cEVENT(button,prspec)\
+{ if (button) printk prspec; }
+
+/* error event message: e.g., i/o error */
+extern int cifsERROR;
+#define cERROR(button, prspec)\
+{ if (button && cifsERROR) { printk prspec; if (button > 1) BUG(); } }
+
+/*
+ *	debug OFF
+ *	---------
+ */
+#else				/* _CIFS_DEBUG */
+#define cERROR(button,prspec)
+#define cEVENT(button,prspec)
+#define cFYI(button, prspec)
+#endif				/* _CIFS_DEBUG */
+
+/*
+ *	statistics
+ *	----------
+ */
+#ifdef	_CIFS_STATISTICS
+#define	INCREMENT(x)	((x)++)
+#define	DECREMENT(x)	((x)--)
+#define	HIGHWATERMARK(x,y)	x = MAX((x), (y))
+#else
+#define	INCREMENT(x)
+#define	DECREMENT(x)
+#define	HIGHWATERMARK(x,y)
+#endif				/* _CIFS_STATISTICS */
+
+#endif				/* _H_CIFS_DEBUG */
diff -Nru a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifs_fs_sb.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,27 @@
+/*
+ *   fs/cifs/cifs_fs_sb.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ */
+#ifndef _CIFS_FS_SB_H
+#define _CIFS_FS_SB_H
+
+struct cifs_sb_info {
+	struct cifsTconInfo *tcon;	/* primary mount */
+	/* list of implicit mounts beneath this mount point - needed in dfs case */
+	struct list_head nested_tcon_q;
+	struct nls_table *local_nls;
+};
+#endif				/* _CIFS_FS_SB_H */
diff -Nru a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifs_unicode.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,136 @@
+/*
+ *   fs/cifs/cifs_unicode.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000,2002
+ *   Modified by Steve French (sfrench@us.ibm.com)
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include "cifs_unicode.h"
+#include "cifs_uniupr.h"
+#include "cifspdu.h"
+#include "cifs_debug.h"
+
+/*
+ * NAME:	toUpper()
+ *
+ * FUNCTION:	Upper case ASCII string (in place) using the current codepage
+ *
+ */
+
+void
+toUpper(const struct nls_table *n, char *mixed_string)
+{
+	int i;
+	char temp;
+
+	for (i = 0; i < strlen(mixed_string); i++) {
+		temp = mixed_string[i];
+		mixed_string[i] = n->charset2upper[(int) temp];
+	}
+}
+
+/*
+ * NAME:	cifs_strfromUCS()
+ *
+ * FUNCTION:	Convert little-endian unicode string to character string
+ *
+ */
+int
+cifs_strfromUCS_le(char *to, const wchar_t * from,	/* LITTLE ENDIAN */
+		   int len, const struct nls_table *codepage)
+{
+	int i;
+	int outlen = 0;
+
+	for (i = 0; (i < len) && from[i]; i++) {
+		int charlen;
+		/* 2.4.0 kernel or greater */
+		charlen =
+		    codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
+				       NLS_MAX_CHARSET_SIZE);
+		if (charlen > 0) {
+			outlen += charlen;
+		} else {
+			to[outlen++] = '?';
+		}
+	}
+	to[outlen] = 0;
+	cEVENT(0, ("cifs_strfromUCS returning %d - '%s'\n", outlen, to));
+	return outlen;
+}
+
+/*
+ * NAME:	cifs_strtoUCS()
+ *
+ * FUNCTION:	Convert character string to unicode string
+ *
+ */
+int
+cifs_strtoUCS(wchar_t * to, const char *from, int len,
+	      const struct nls_table *codepage)
+{
+	int charlen;
+	int i;
+
+	cEVENT(0, ("cifs_strtoUCS - '%s'\n", from));
+
+	for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
+
+		/* works for 2.4.0 kernel or later */
+		charlen = codepage->char2uni(from, len, &to[i]);
+		if (charlen < 1) {
+			cERROR(1,
+			       ("cifs_strtoUCS: char2uni returned %d.\n",
+				charlen));
+			to[i] = cpu_to_le16(0x003f);	/* a question mark */
+			charlen = 1;
+		}
+		to[i] = cpu_to_le16(to[i]);
+
+	}
+
+	cEVENT(0, (" returning %d\n", i));
+
+	to[i] = 0;
+	return i;
+}
+
+/*
+ * NAME:	get_UCSname2()
+ *
+ * FUNCTION:	Allocate and translate to unicode string
+ *
+ */
+/*int
+get_UCSname2(struct component_name *uniName, struct dentry *dentry,
+	    struct nls_table *nls_tab)
+{
+	int length = dentry->d_name.len;
+
+	if (length > 255)
+		return ENAMETOOLONG;
+
+	uniName->name = kmalloc((length + 1) * sizeof (wchar_t), GFP_KERNEL);
+
+	if (uniName->name == NULL)
+		return ENOSPC;
+
+	uniName->namlen = cifs_strtoUCS(uniName->name, dentry->d_name.name,
+					length, nls_tab);
+
+	return 0;
+} */
diff -Nru a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifs_unicode.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,368 @@
+/*
+ * cifs_unicode:  Unicode kernel case support
+ *
+ * Function:
+ *     Convert a unicode character to upper or lower case using
+ *     compressed tables.
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000,2002
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Notes:
+ *     These APIs are based on the C library functions.  The semantics
+ *     should match the C functions but with expanded size operands.
+ *
+ *     The upper/lower functions are based on a table created by mkupr.
+ *     This is a compressed table of upper and lower case conversion.
+ *
+ */
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+#include <linux/nls.h>
+
+#define  UNIUPR_NOLOWER		/* Example to not expand lower case tables */
+
+/* Just define what we want from uniupr.h.  We don't want to define the tables
+ * in each source file.
+ */
+#ifndef	UNICASERANGE_DEFINED
+struct UniCaseRange {
+	wchar_t start;
+	wchar_t end;
+	signed char *table;
+};
+#endif				/* UNICASERANGE_DEFINED */
+
+#ifndef UNIUPR_NOUPPER
+extern signed char CifsUniUpperTable[512];
+extern const struct UniCaseRange CifsUniUpperRange[];
+#endif				/* UNIUPR_NOUPPER */
+
+#ifndef UNIUPR_NOLOWER
+extern signed char UniLowerTable[512];
+extern struct UniCaseRange UniLowerRange[];
+#endif				/* UNIUPR_NOLOWER */
+
+/*
+ *      directory entry argument
+ */
+struct component_name {
+	int namlen;
+	wchar_t *name;
+};
+
+#ifdef __KERNEL__
+int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *);
+int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *);
+
+int cifs_UCSname(struct component_name *, struct dentry *,
+		 const struct nls_table *);
+
+void toUpper(const struct nls_table *, char *);
+#endif
+
+#define free_UCSname(COMP) kfree((COMP)->name)
+
+/*
+ * UniStrcat:  Concatenate the second string to the first
+ *
+ * Returns:
+ *     Address of the first string
+ */
+static inline wchar_t *
+UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
+{
+	wchar_t *anchor = ucs1;	/* save a pointer to start of ucs1 */
+
+	while (*ucs1++) ;	/* To end of first string */
+	ucs1--;			/* Return to the null */
+	while ((*ucs1++ = *ucs2++)) ;	/* copy string 2 over */
+	return anchor;
+}
+
+/*
+ * UniStrchr:  Find a character in a string
+ *
+ * Returns:
+ *     Address of first occurance of character in string
+ *     or NULL if the character is not in the string
+ */
+static inline wchar_t *
+UniStrchr(const wchar_t * ucs, wchar_t uc)
+{
+	while ((*ucs != uc) && *ucs)
+		ucs++;
+
+	if (*ucs == uc)
+		return (wchar_t *) ucs;
+	return NULL;
+}
+
+/*
+ * UniStrcmp:  Compare two strings
+ *
+ * Returns:
+ *     < 0:  First string is less than second
+ *     = 0:  Strings are equal
+ *     > 0:  First string is greater than second
+ */
+static inline int
+UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
+{
+	while ((*ucs1 == *ucs2) && *ucs1) {
+		ucs1++;
+		ucs2++;
+	}
+	return (int) *ucs1 - (int) *ucs2;
+}
+
+/*
+ * UniStrcpy:  Copy a string
+ */
+static inline wchar_t *
+UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
+{
+	wchar_t *anchor = ucs1;	/* save the start of result string */
+
+	while ((*ucs1++ = *ucs2++)) ;
+	return anchor;
+}
+
+/*
+ * UniStrlen:  Return the length of a string (in 16 bit Unicode chars not bytes)
+ */
+static inline size_t
+UniStrlen(const wchar_t * ucs1)
+{
+	int i = 0;
+
+	while (*ucs1++)
+		i++;
+	return i;
+}
+
+/*
+ * UniStrnlen:  Return the length (in 16 bit Unicode chars not bytes) of a string (length limited)
+ */
+static inline size_t
+UniStrnlen(const wchar_t * ucs1, int maxlen)
+{
+	int i = 0;
+
+	while (*ucs1++) {
+		i++;
+		if (i >= maxlen)
+			break;
+	}
+	return i;
+}
+
+/*
+ * UniStrncat:  Concatenate length limited string
+ */
+static inline wchar_t *
+UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+	wchar_t *anchor = ucs1;	/* save pointer to string 1 */
+
+	while (*ucs1++) ;
+	ucs1--;			/* point to null terminator of s1 */
+	while (n-- && (*ucs1 = *ucs2)) {	/* copy s2 after s1 */
+		ucs1++;
+		ucs2++;
+	}
+	*ucs1 = 0;		/* Null terminate the result */
+	return (anchor);
+}
+
+/*
+ * UniStrncmp:  Compare length limited string
+ */
+static inline int
+UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+	if (!n)
+		return 0;	/* Null strings are equal */
+	while ((*ucs1 == *ucs2) && *ucs1 && --n) {
+		ucs1++;
+		ucs2++;
+	}
+	return (int) *ucs1 - (int) *ucs2;
+}
+
+/*
+ * UniStrncmp_le:  Compare length limited string - native to little-endian
+ */
+static inline int
+UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+	if (!n)
+		return 0;	/* Null strings are equal */
+	while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
+		ucs1++;
+		ucs2++;
+	}
+	return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
+}
+
+/*
+ * UniStrncpy:  Copy length limited string with pad
+ */
+static inline wchar_t *
+UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+	wchar_t *anchor = ucs1;
+
+	while (n-- && *ucs2)	/* Copy the strings */
+		*ucs1++ = *ucs2++;
+
+	n++;
+	while (n--)		/* Pad with nulls */
+		*ucs1++ = 0;
+	return anchor;
+}
+
+/*
+ * UniStrncpy_le:  Copy length limited string with pad to little-endian
+ */
+static inline wchar_t *
+UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+{
+	wchar_t *anchor = ucs1;
+
+	while (n-- && *ucs2)	/* Copy the strings */
+		*ucs1++ = __le16_to_cpu(*ucs2++);
+
+	n++;
+	while (n--)		/* Pad with nulls */
+		*ucs1++ = 0;
+	return anchor;
+}
+
+/*
+ * UniStrstr:  Find a string in a string
+ *
+ * Returns:
+ *     Address of first match found
+ *     NULL if no matching string is found
+ */
+static inline wchar_t *
+UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2)
+{
+	const wchar_t *anchor1 = ucs1;
+	const wchar_t *anchor2 = ucs2;
+
+	while (*ucs1) {
+		if (*ucs1 == *ucs2) {	/* Partial match found */
+			ucs1++;
+			ucs2++;
+		} else {
+			if (!*ucs2)	/* Match found */
+				return (wchar_t *) anchor1;
+			ucs1 = ++anchor1;	/* No match */
+			ucs2 = anchor2;
+		}
+	}
+
+	if (!*ucs2)		/* Both end together */
+		return (wchar_t *) anchor1;	/* Match found */
+	return NULL;		/* No match */
+}
+
+#ifndef UNIUPR_NOUPPER
+/*
+ * UniToupper:  Convert a unicode character to upper case
+ */
+static inline wchar_t
+UniToupper(register wchar_t uc)
+{
+	register const struct UniCaseRange *rp;
+
+	if (uc < sizeof (CifsUniUpperTable)) {	/* Latin characters */
+		return uc + CifsUniUpperTable[uc];	/* Use base tables */
+	} else {
+		rp = CifsUniUpperRange;	/* Use range tables */
+		while (rp->start) {
+			if (uc < rp->start)	/* Before start of range */
+				return uc;	/* Uppercase = input */
+			if (uc <= rp->end)	/* In range */
+				return uc + rp->table[uc - rp->start];
+			rp++;	/* Try next range */
+		}
+	}
+	return uc;		/* Past last range */
+}
+
+/*
+ * UniStrupr:  Upper case a unicode string
+ */
+static inline wchar_t *
+UniStrupr(register wchar_t * upin)
+{
+	register wchar_t *up;
+
+	up = upin;
+	while (*up) {		/* For all characters */
+		*up = UniToupper(*up);
+		up++;
+	}
+	return upin;		/* Return input pointer */
+}
+#endif				/* UNIUPR_NOUPPER */
+
+#ifndef UNIUPR_NOLOWER
+/*
+ * UniTolower:  Convert a unicode character to lower case
+ */
+static inline wchar_t
+UniTolower(wchar_t uc)
+{
+	register struct UniCaseRange *rp;
+
+	if (uc < sizeof (UniLowerTable)) {	/* Latin characters */
+		return uc + UniLowerTable[uc];	/* Use base tables */
+	} else {
+		rp = UniLowerRange;	/* Use range tables */
+		while (rp->start) {
+			if (uc < rp->start)	/* Before start of range */
+				return uc;	/* Uppercase = input */
+			if (uc <= rp->end)	/* In range */
+				return uc + rp->table[uc - rp->start];
+			rp++;	/* Try next range */
+		}
+	}
+	return uc;		/* Past last range */
+}
+
+/*
+ * UniStrlwr:  Lower case a unicode string
+ */
+static inline wchar_t *
+UniStrlwr(register wchar_t * upin)
+{
+	register wchar_t *up;
+
+	up = upin;
+	while (*up) {		/* For all characters */
+		*up = UniTolower(*up);
+		up++;
+	}
+	return upin;		/* Return input pointer */
+}
+
+#endif
diff -Nru a/fs/cifs/cifs_uniupr.h b/fs/cifs/cifs_uniupr.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifs_uniupr.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,253 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000,2002
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * uniupr.h - Unicode compressed case ranges
+ *
+*/
+
+#ifndef UNIUPR_NOUPPER
+/*
+ * Latin upper case
+ */
+signed char CifsUniUpperTable[512] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 000-00f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 010-01f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 020-02f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 030-03f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 040-04f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 050-05f */
+	0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,	/* 060-06f */
+	-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0,	/* 070-07f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 080-08f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 090-09f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0a0-0af */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0b0-0bf */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0c0-0cf */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0d0-0df */
+	-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,	/* 0e0-0ef */
+	-32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121,	/* 0f0-0ff */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 100-10f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 110-11f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 120-12f */
+	0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0,	/* 130-13f */
+	-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1,	/* 140-14f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 150-15f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 160-16f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0,	/* 170-17f */
+	0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0,	/* 180-18f */
+	0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0,	/* 190-19f */
+	0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0,	/* 1a0-1af */
+	-1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0,	/* 1b0-1bf */
+	0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0,	/* 1c0-1cf */
+	-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1,	/* 1d0-1df */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e0-1ef */
+	0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1f0-1ff */
+};
+
+/* Upper case range - Greek */
+static signed char UniCaseRangeU03a0[47] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37,	/* 3a0-3af */
+	0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,	/* 3b0-3bf */
+	-32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64,
+	-63, -63,
+};
+
+/* Upper case range - Cyrillic */
+static signed char UniCaseRangeU0430[48] = {
+	-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,	/* 430-43f */
+	-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,	/* 440-44f */
+	0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80,	/* 450-45f */
+};
+
+/* Upper case range - Extended cyrillic */
+static signed char UniCaseRangeU0490[61] = {
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 490-49f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 4a0-4af */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 4b0-4bf */
+	0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
+};
+
+/* Upper case range - Extended latin and greek */
+static signed char UniCaseRangeU1e00[509] = {
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e00-1e0f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e10-1e1f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e20-1e2f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e30-1e3f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e40-1e4f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e50-1e5f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e60-1e6f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e70-1e7f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1e80-1e8f */
+	0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1,	/* 1e90-1e9f */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1ea0-1eaf */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1eb0-1ebf */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1ec0-1ecf */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1ed0-1edf */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1,	/* 1ee0-1eef */
+	0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0,	/* 1ef0-1eff */
+	8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f00-1f0f */
+	8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f10-1f1f */
+	8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f20-1f2f */
+	8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f30-1f3f */
+	8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f40-1f4f */
+	0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f50-1f5f */
+	8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f60-1f6f */
+	74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0,	/* 1f70-1f7f */
+	8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f80-1f8f */
+	8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f90-1f9f */
+	8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1fa0-1faf */
+	8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1fb0-1fbf */
+	0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1fc0-1fcf */
+	8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1fd0-1fdf */
+	8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1fe0-1fef */
+	0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Upper case range - Wide latin */
+static signed char UniCaseRangeUff40[27] = {
+	0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,	/* ff40-ff4f */
+	-32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
+};
+
+/*
+ * Upper Case Range
+ */
+const struct UniCaseRange CifsUniUpperRange[] = {
+	{0x03a0, 0x03ce, UniCaseRangeU03a0},
+	{0x0430, 0x045f, UniCaseRangeU0430},
+	{0x0490, 0x04cc, UniCaseRangeU0490},
+	{0x1e00, 0x1ffc, UniCaseRangeU1e00},
+	{0xff40, 0xff5a, UniCaseRangeUff40},
+	{0, 0, 0}
+};
+#endif
+
+#ifndef UNIUPR_NOLOWER
+/*
+ * Latin lower case
+ */
+static signed char CifsUniLowerTable[512] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 000-00f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 010-01f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 020-02f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 030-03f */
+	0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,	/* 040-04f */
+	32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0,	/* 050-05f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 060-06f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 070-07f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 080-08f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 090-09f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0a0-0af */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0b0-0bf */
+	32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,	/* 0c0-0cf */
+	32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0,	/* 0d0-0df */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0e0-0ef */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0f0-0ff */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 100-10f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 110-11f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 120-12f */
+	0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1,	/* 130-13f */
+	0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,	/* 140-14f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 150-15f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 160-16f */
+	1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0,	/* 170-17f */
+	0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0,	/* 180-18f */
+	0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,	/* 190-19f */
+	1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1,	/* 1a0-1af */
+	0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	/* 1b0-1bf */
+	0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1,	/* 1c0-1cf */
+	0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0,	/* 1d0-1df */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e0-1ef */
+	0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1f0-1ff */
+};
+
+/* Lower case range - Greek */
+static signed char UniCaseRangeL0380[44] = {
+	0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63,	/* 380-38f */
+	0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,	/* 390-39f */
+	32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+};
+
+/* Lower case range - Cyrillic */
+static signed char UniCaseRangeL0400[48] = {
+	0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80,	/* 400-40f */
+	32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,	/* 410-41f */
+	32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,	/* 420-42f */
+};
+
+/* Lower case range - Extended cyrillic */
+static signed char UniCaseRangeL0490[60] = {
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 490-49f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 4a0-4af */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 4b0-4bf */
+	0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
+};
+
+/* Lower case range - Extended latin and greek */
+static signed char UniCaseRangeL1e00[504] = {
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e00-1e0f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e10-1e1f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e20-1e2f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e30-1e3f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e40-1e4f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e50-1e5f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e60-1e6f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e70-1e7f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1e80-1e8f */
+	1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,	/* 1e90-1e9f */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1ea0-1eaf */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1eb0-1ebf */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1ec0-1ecf */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1ed0-1edf */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,	/* 1ee0-1eef */
+	1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,	/* 1ef0-1eff */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8,	/* 1f00-1f0f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0,	/* 1f10-1f1f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8,	/* 1f20-1f2f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8,	/* 1f30-1f3f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0,	/* 1f40-1f4f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8,	/* 1f50-1f5f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8,	/* 1f60-1f6f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 1f70-1f7f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8,	/* 1f80-1f8f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8,	/* 1f90-1f9f */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8,	/* 1fa0-1faf */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0,	/* 1fb0-1fbf */
+	0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0,	/* 1fc0-1fcf */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0,	/* 1fd0-1fdf */
+	0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0,	/* 1fe0-1fef */
+	0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Lower case range - Wide latin */
+static signed char UniCaseRangeLff20[27] = {
+	0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,	/* ff20-ff2f */
+	32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+};
+
+/*
+ * Lower Case Range
+ */
+const static struct UniCaseRange CifsUniLowerRange[] = {
+	0x0380, 0x03ab, UniCaseRangeL0380,
+	0x0400, 0x042f, UniCaseRangeL0400,
+	0x0490, 0x04cb, UniCaseRangeL0490,
+	0x1e00, 0x1ff7, UniCaseRangeL1e00,
+	0xff20, 0xff3a, UniCaseRangeLff20,
+	0, 0, 0
+};
+#endif
diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifsfs.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,433 @@
+/*
+ *   fs/cifs/cifsfs.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   Common Internet FileSystem (CIFS) client
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Note that BB means BUGBUG (ie something to fix eventually) */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#define DECLARE_GLOBALS_HERE
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include <linux/mm.h>
+#define CIFS_MAGIC_NUMBER 0xFF534D42	/* the first four bytes of all SMB PDUs */
+
+extern struct file_system_type cifs_fs_type;
+
+int cifsFYI = 0;
+int cifsERROR = 1;
+int traceSMB = 0;
+unsigned int oplockEnabled = 0;
+unsigned int multiuser_mount = 0;
+unsigned int extended_security = 0;
+unsigned int ntlmv2_support = 0;
+unsigned int sign_CIFS_PDUs = 0;
+
+extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
+		      char *);
+extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
+void cifs_proc_init(void);
+void cifs_proc_clean(void);
+
+static int
+cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
+{
+	struct inode *inode;
+	struct cifs_sb_info *cifs_sb;
+	int rc = 0;
+
+    sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
+	cifs_sb = CIFS_SB(sb);
+	cifs_sb->local_nls = load_nls_default();	/* needed for ASCII cp to Unicode converts */
+	rc = cifs_mount(sb, cifs_sb, data, devname);
+
+	if (rc) {
+		if (!silent)
+			cERROR(1,
+			       ("cifs_mount failed w/return code = %d\n", rc));
+		goto out_mount_failed;
+	}
+
+	sb->s_magic = CIFS_MAGIC_NUMBER;
+	sb->s_op = &cifs_super_ops;
+	sb->s_blocksize = CIFS_MAX_MSGSIZE;	/* BB check SMBSessSetup negotiated size */
+	sb->s_blocksize_bits = 10;	/* 2**10 = CIFS_MAX_MSGSIZE */
+	inode = iget(sb, ROOT_I);
+
+	if (!inode)
+		goto out_no_root;
+
+	sb->s_root = d_alloc_root(inode);
+
+	if (!sb->s_root)
+		goto out_no_root;
+
+	return 0;
+
+out_no_root:
+	cEVENT(1, ("cifs_read_super: get root inode failed\n"));
+	if (inode)
+		iput(inode);
+
+/*	rc = cifs_umount(sb);  BB is CIFS unmount routine needed? */
+	if (rc) {
+		cERROR(1, ("cifs_umount failed with return code %d\n", rc));
+	}
+out_mount_failed:
+    if(cifs_sb)
+        kfree(cifs_sb);
+	return -EINVAL;
+}
+
+void
+cifs_put_super(struct super_block *sb)
+{
+	int rc = 0;
+	struct cifs_sb_info *cifs_sb;
+
+	cFYI(1, ("In cifs_put_super\n"));
+	cifs_sb = CIFS_SB(sb);
+	rc = cifs_umount(sb, cifs_sb);	
+	if (rc) {
+		cERROR(1, ("cifs_umount failed with return code %d\n", rc));
+	}
+    if(cifs_sb) {    
+        unload_nls(cifs_sb->local_nls);
+        kfree(cifs_sb);
+    }
+	return;
+}
+
+int
+cifs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	int xid, rc;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(sb);
+	pTcon = cifs_sb->tcon;
+
+	buf->f_type = CIFS_MAGIC_NUMBER;
+
+	/* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
+	buf->f_namelen = PATH_MAX;	/* PATH_MAX may be too long - it would presumably
+					   be length of total path, note that some servers may be 
+					   able to support more than this, but best to be safe
+					   since Win2k and others can not handle very long filenames */
+	buf->f_files = 0;	/* undefined */
+	buf->f_ffree = -1;	/* unlimited */
+
+	rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls);
+
+	/*     
+	   int f_type;
+	   __fsid_t f_fsid;
+	   int f_namelen;  */
+	/* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
+
+	return 0;		/* always return success? what if volume is no longer available? */
+}
+
+static kmem_cache_t *cifs_inode_cachep;
+kmem_cache_t *cifs_req_cachep;
+kmem_cache_t *cifs_mid_cachep;
+
+static struct inode *
+cifs_alloc_inode(struct super_block *sb)
+{
+	struct cifsInodeInfo *cifs_inode;
+	cifs_inode =
+	    (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep,
+						      SLAB_KERNEL);
+	if (!cifs_inode)
+		return NULL;
+	cifs_inode->cifsAttrs = 0x20;	/* default */
+	atomic_set(&cifs_inode->inUse, 0);
+	cifs_inode->time = 0;
+	cifs_inode->clientCanCache = 0;
+    INIT_LIST_HEAD(&cifs_inode->openFileList);
+	return &cifs_inode->vfs_inode;
+}
+
+static void
+cifs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
+}
+
+/*
+ * cifs_show_options() is for displaying mount options in /proc/mounts.
+ * It tries to avoid showing settings that were not changed from their
+ * defaults.
+ */
+static int
+cifs_show_options(struct seq_file *s, struct vfsmount *m)
+{
+	struct cifs_sb_info *cifs_sb;
+
+	cifs_sb = CIFS_SB(m->mnt_sb);
+
+	if (cifs_sb)
+		if (cifs_sb->tcon) {
+			seq_printf(s, ", TARGET: %s ", cifs_sb->tcon->treeName);
+			seq_printf(s, "FS TYPE: %s ",
+				   cifs_sb->tcon->nativeFileSystem);
+			if (cifs_sb->tcon->ses->userName)
+				seq_printf(s, " USER: %s ",
+					   cifs_sb->tcon->ses->userName);
+		}
+	return 0;
+}
+
+struct super_operations cifs_super_ops = {
+	.read_inode = cifs_read_inode,
+	.put_super = cifs_put_super,
+	.statfs = cifs_statfs,
+	.alloc_inode = cifs_alloc_inode,
+	.destroy_inode = cifs_destroy_inode,
+/*	.drop_inode	    = generic_delete_inode, 
+	.delete_inode	= cifs_delete_inode,  *//* Do not need the above two functions     
+   unless later we add lazy close of inodes or unless the kernel forgets to call
+   us with the same number of releases (closes) as opens */
+	.show_options = cifs_show_options,
+/*    .umount_begin   = cifs_umount_begin, *//* consider adding in the future */
+};
+
+static struct super_block *
+cifs_get_sb(struct file_system_type *fs_type,
+	    int flags, char *dev_name, void *data)
+{
+	int rc;
+	struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL);
+
+	cFYI(1, ("\nDevname: %s flags: %d ", dev_name, flags));
+
+	if (IS_ERR(sb))
+		return sb;
+
+	sb->s_flags = flags;
+
+	rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0);
+	if (rc) {
+		up_write(&sb->s_umount);
+		deactivate_super(sb);
+		return ERR_PTR(rc);
+	}
+	sb->s_flags |= MS_ACTIVE;
+	return sb;
+}
+
+static struct file_system_type cifs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "cifs",
+	.get_sb = cifs_get_sb,
+	.kill_sb = kill_anon_super,
+	/*  .fs_flags */
+};
+struct inode_operations cifs_dir_inode_ops = {
+	.create = cifs_create,
+	.lookup = cifs_lookup,
+	.unlink = cifs_unlink,
+	.link = cifs_hardlink,
+	.mkdir = cifs_mkdir,
+	.rmdir = cifs_rmdir,
+	.rename = cifs_rename,
+/*	revalidate:cifs_revalidate,   */
+	.setattr = cifs_setattr,
+	.symlink = cifs_symlink,
+};
+
+struct inode_operations cifs_file_inode_ops = {
+/*	revalidate:cifs_revalidate, */
+	.setattr = cifs_setattr,
+	.rename = cifs_rename,
+};
+
+struct inode_operations cifs_symlink_inode_ops = {
+	.readlink = cifs_readlink,
+	.follow_link = cifs_follow_link,
+	/* BB add the following two eventually */
+	/* revalidate:     cifs_revalidate,
+   setattr:        cifs_notify_change, *//* BB do we need notify change */
+};
+
+struct file_operations cifs_file_ops = {
+	.read = cifs_read,
+	.write = cifs_write,
+	.open = cifs_open,
+	.release = cifs_close,
+	.lock = cifs_lock,
+	.fsync = cifs_fsync,
+};
+
+struct file_operations cifs_dir_ops = {
+	.readdir = cifs_readdir,
+	.release = cifs_closedir,
+};
+
+static void
+cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		inode_init_once(&cifsi->vfs_inode);
+		INIT_LIST_HEAD(&cifsi->lockList);
+	}
+}
+
+int
+cifs_init_inodecache(void)
+{
+	cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
+					      sizeof (struct cifsInodeInfo),
+					      0, SLAB_HWCACHE_ALIGN,
+					      cifs_init_once, NULL);
+	if (cifs_inode_cachep == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void
+cifs_destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(cifs_inode_cachep))
+		printk(KERN_INFO "cifs_inode_cache: error freeing\n");
+}
+
+int
+cifs_init_request_bufs(void)
+{
+	cifs_req_cachep = kmem_cache_create("cifs_request",
+					    CIFS_MAX_MSGSIZE +
+					    MAX_CIFS_HDR_SIZE, 0,
+					    SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (cifs_req_cachep == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void
+cifs_destroy_request_bufs(void)
+{
+	if (kmem_cache_destroy(cifs_req_cachep))
+		printk(KERN_INFO
+		       "cifs_destroy_request_cache: error not all structures were freed\n");
+}
+
+int
+cifs_init_mids(void)
+{
+	cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
+					    sizeof (struct mid_q_entry), 0,
+					    SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (cifs_mid_cachep == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void
+cifs_destroy_mids(void)
+{
+	if (kmem_cache_destroy(cifs_mid_cachep))
+		printk(KERN_INFO
+		       "cifs_destroy_mids: error not all structures were freed\n");
+}
+
+static int __init
+init_cifs(void)
+{
+	int rc = 0;
+#if CONFIG_PROC_FS
+	cifs_proc_init();
+#endif
+	INIT_LIST_HEAD(&GlobalServerList);	/* BB not implemented yet */
+	INIT_LIST_HEAD(&GlobalSMBSessionList);
+	INIT_LIST_HEAD(&GlobalTreeConnectionList);
+
+/*
+ *  Initialize Global counters
+ */
+	atomic_set(&sesInfoAllocCount, 0);
+	atomic_set(&tconInfoAllocCount, 0);
+	atomic_set(&bufAllocCount, 0);
+	atomic_set(&midCount, 0);
+	GlobalTotalActiveXid = 0;
+	GlobalMaxActiveXid = 0;
+
+	rc = cifs_init_inodecache();
+	if (!rc) {
+		rc = cifs_init_mids();
+		if (!rc) {
+			rc = cifs_init_request_bufs();
+			if (!rc) {
+				rc = register_filesystem(&cifs_fs_type);
+				if (!rc)
+					return rc;	/* Success */
+				else
+					cifs_destroy_request_bufs();
+			}
+			cifs_destroy_mids();
+		}
+		cifs_destroy_inodecache();
+	}
+#if CONFIG_PROC_FS
+	cifs_proc_clean();
+#endif
+	return rc;
+}
+
+static void __exit
+exit_cifs(void)
+{
+	cFYI(0, ("\nIn unregister ie exit_cifs"));
+#if CONFIG_PROC_FS
+	cifs_proc_clean();
+#endif
+    unregister_filesystem(&cifs_fs_type);
+	cifs_destroy_inodecache();
+	cifs_destroy_mids();
+	cifs_destroy_request_bufs();
+}
+
+MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
+MODULE_LICENSE("GPL");		/* combination of LGPL + GPL source behaves as GPL */
+MODULE_DESCRIPTION
+    ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows");
+module_init(init_cifs)
+module_exit(exit_cifs)
diff -Nru a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifsfs.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,90 @@
+/*
+ *   fs/cifs/cifsfs.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+#ifndef _CIFSFS_H
+#define _CIFSFS_H
+
+#define ROOT_I 2
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+extern int map_cifs_error(int error_class, int error_code,
+			  int status_codes_negotiated);
+
+extern struct address_space_operations cifs_addr_ops;
+
+/* Functions related to super block operations */
+extern struct super_operations cifs_super_ops;
+extern void cifs_put_inode(struct inode *);
+extern void cifs_read_inode(struct inode *);
+extern void cifs_delete_inode(struct inode *);
+/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */
+
+/* Functions related to inodes */
+extern struct inode_operations cifs_dir_inode_ops;
+extern int cifs_create(struct inode *, struct dentry *, int);
+extern struct dentry *cifs_lookup(struct inode *, struct dentry *);
+extern int cifs_unlink(struct inode *, struct dentry *);
+extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
+extern int cifs_mkdir(struct inode *, struct dentry *, int);
+extern int cifs_rmdir(struct inode *, struct dentry *);
+extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
+		       struct dentry *);
+extern int cifs_revalidate(struct dentry *);
+extern int cifs_setattr(struct dentry *, struct iattr *);
+
+extern struct inode_operations cifs_file_inode_ops;
+extern void cifs_truncate_file(struct inode *);
+
+extern struct inode_operations cifs_symlink_inode_ops;
+
+/* Functions related to files and directories */
+extern struct file_operations cifs_file_ops;
+extern int cifs_open(struct inode *inode, struct file *file);
+extern int cifs_close(struct inode *inode, struct file *file);
+extern int cifs_closedir(struct inode *inode, struct file *file);
+extern ssize_t cifs_read(struct file *file, char *read_data,
+			 size_t read_size, loff_t * poffset);
+extern ssize_t cifs_write(struct file *file, const char *write_data,
+			  size_t write_size, loff_t * poffset);
+extern int cifs_lock(struct file *, int, struct file_lock *);
+extern int cifs_fsync(struct file *, struct dentry *, int);
+
+extern struct file_operations cifs_dir_ops;
+extern int cifs_dir_open(struct inode *inode, struct file *file);
+extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
+
+/* Functions related to dir entries */
+extern struct dentry_operations cifs_dentry_ops;
+
+/* Functions related to symlinks */
+extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
+extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen);
+extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
+			const char *symname);
+
+#endif				/* _CIFSSMB_H */
diff -Nru a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifsglob.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,333 @@
+/*
+ *   fs/cifs/cifsglob.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ * 
+ */
+#include <linux/in.h>
+#include "cifs_fs_sb.h"
+/*
+ * The sizes of various internal tables and strings
+ */
+#define MAX_UID_INFO 16
+#define MAX_SES_INFO 2
+#define MAX_TCON_INFO 4
+
+#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1
+#define MAX_SERVER_SIZE 15
+#define MAX_SHARE_SIZE  64	/* used to be 20 - this should still be enough */
+#define MAX_USERNAME_SIZE 32	/* 22 is to allow for 15 char names + null
+				   termination then *2 for unicode versions */
+#define MAX_PASSWORD_SIZE 16
+
+/*
+ * MAX_REQ is the maximum number of requests that WE will send
+ * on one NetBIOS handle concurently.
+ */
+#define MAX_REQ (10)
+
+#define SERVER_NAME_LENGTH 15
+#define SERVER_NAME_LEN_WITH_NULL     (SERVER_NAME_LENGTH + 1)
+
+/* used to define string lengths for reversing unicode strings */
+/*         (256+1)*2 = 514                                     */
+/*           (max path length + 1 for null) * 2 for unicode    */
+#define MAX_NAME 514
+
+#include "cifspdu.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/*
+ * This information is kept on every Server we know about.
+ *
+ * Some things to note:
+ *
+ */
+#define SERVER_NAME_LEN_WITH_NULL	(SERVER_NAME_LENGTH + 1)
+
+/*
+ * CIFS vfs client Status information (based on what we know.)
+ */
+
+ /* associated with each tcp and smb session */
+enum statusEnum {
+	CifsNew = 0,
+	CifsGood,
+	CifsExiting,
+	CifsNeedReconnect
+};
+
+enum securityEnum {
+	NTLM = 0,		/* Legacy NTLM012 auth with NTLM hash */
+	NTLMv2,			/* Legacy NTLM auth with NTLMv2 hash */
+	RawNTLMSSP,		/* NTLMSSP without SPNEGO */
+	NTLMSSP,		/* NTLMSSP via SPNEGO */
+	Kerberos		/* Kerberos via SPNEGO */
+};
+
+/*
+ *****************************************************************
+ * Except the CIFS PDUs themselves all the
+ * globally interesting structs should go here
+ *****************************************************************
+ */
+
+struct TCP_Server_Info {
+	char server_Name[SERVER_NAME_LEN_WITH_NULL];	/* 15 chars + X'20'in 16th */
+	char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];	/* Unicode version of server_Name */
+	struct socket *ssocket;
+	struct sockaddr_in sockAddr;
+	wait_queue_head_t response_q;
+	struct list_head pending_mid_q;
+	void *Server_NlsInfo;	/* BB - placeholder for future NLS info  */
+	unsigned short server_codepage;	/* codepage for the server    */
+	unsigned long ip_address;	/* IP addr for the server if known     */
+	unsigned long svType;	/* computer type                       */
+	char versionMajor;
+	char versionMinor;
+	int svlocal:1;		/* local server or remote */
+	atomic_t socketUseCount;	/* indicates if the server has any open cifs sessions */
+	enum statusEnum tcpStatus;	/* what we think the status is */
+	struct semaphore tcpSem;
+	struct task_struct *tsk;
+	char server_GUID[16];
+};
+
+/*
+ * The following is our shortcut to user information.  We surface the uid,
+ * and name. We always get the password on the fly in case it
+ * has changed. We also hang a list of sessions owned by this user off here. 
+ */
+struct cifsUidInfo {
+	struct cifsUidInfo *next1;	/* BB replace with list and atomicize */
+	struct cifsSesInfo *ses;	/* list of sessions *//* BB replace with list and atomicize */
+	struct srSesInfo *sesSR;	/* Save/Restore session list */
+	uid_t linux_uid;
+	char user[MAX_USERNAME_SIZE + 1];	/* ascii name of user */
+	/* BB eventually need ptr into PAM or WinBind info */
+};
+
+/*
+ * Session structure.  One of these for each uid session with a particular host
+ */
+struct cifsSesInfo {
+	struct list_head cifsSessionList;
+	struct semaphore sesSem;
+	struct cifsUidInfo *uidInfo;	/* pointer to user info */
+	struct TCP_Server_Info *server;	/* pointer to server info */
+	atomic_t inUse;		/* # of CURRENT users of this ses */
+	enum statusEnum status;
+	int dialectIndex;	/* the negotiated dialect index */
+	char secMode;
+	enum securityEnum secType;
+	unsigned int maxReq;	/* Clients should submit no more */
+	/* than maxReq distinct unanswered SMBs to the server when using  */
+	/* multiplexed reads or writes */
+	unsigned int maxBuf;	/* maxBuf specifies the maximum */
+	/* message size the server can send or receive for non-raw SMBs */
+	unsigned int maxRw;	/* maxRw specifies the maximum */
+	/* message size the server can send or receive for */
+	/* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
+	char sessid[4];		/* unique token id for this session */
+	/* (returned on Negotiate */
+	__u16 ipc_tid;		/* special tid for connection to IPC share */
+	int capabilities;
+	__u16 timeZone;
+	char *serverOS;		/* name of operating system underlying the server */
+	char *serverNOS;	/* name of network operating system that the server is running */
+	char *serverDomain;	/* security realm of server */
+	int Suid;		/* needed for user level security */
+	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
+	char userName[MAX_USERNAME_SIZE + 1];	/* BB remove and replace with list of cifsUidInfo structures */
+};
+
+/*
+ * there is one of these for each connection to a resource on a particular
+ * session 
+ */
+struct cifsTconInfo {
+	struct list_head cifsConnectionList;
+    struct list_head openFileList;
+	struct semaphore tconSem;
+	struct cifsSesInfo *ses;	/* pointer to session associated with */
+	char treeName[MAX_TREE_SIZE + 1];	/* The ascii or unicode name of this resource depending on the ses->capabilities *//* BB fill in this field */
+	char *nativeFileSystem;
+	__u16 tid;		/* The 2 byte transaction id */
+	__u16 Flags;		/* optional support bits */
+	atomic_t useCount;	/* how many mounts (explicit or implicit refer to this share */
+	FILE_SYSTEM_DEVICE_INFO fsDevInfo;
+	FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;	/* note file system name may be truncated - but very unlikely */
+	FILE_SYSTEM_UNIX_INFO fsUnixInfo;
+	/* BB add field for back pointer to sb struct? */
+};
+
+/*
+ * This info hangs off the cifsFileInfo structure.  This is used to track
+ * byte stream locks on the file
+ */
+struct cifsLockInfo {
+	struct cifsLockInfo *next;
+	int start;
+	int length;
+	int type;
+};
+
+/*
+ * One of these for each open instance of a file
+ */
+struct cifsFileInfo {
+	struct list_head tlist;	/* pointer to next fid owned by tcon */
+	struct list_head flist;	/* next fid (file instance) for this inode */
+	unsigned int uid;	/* allows you to find which FileInfo structure */
+	__u32 pid;		/* process id who opened file */
+	__u16 netfid;		/* file id from remote */
+	/* BB add lock scope info here if needed */ ;
+	/* lock scope id (0 if none) */
+	int endOfSearch:1;	/* we have reached end of search */
+	int closePend:1;	/* file is marked to close */
+};
+
+/*
+ * One of these for each file inode
+ */
+
+struct cifsInodeInfo {
+	struct list_head lockList;
+	/* BB add in lists for dirty pages - i.e. write caching info for oplock */
+    struct list_head openFileList;
+	__u32 cifsAttrs;	/* e.g. DOS archive bit, sparse, compressed, system etc. */
+	atomic_t inUse;		/* num concurrent users (local openers cifs) of file */
+	unsigned long time;	/* jiffies of last update/check of inode */
+	int clientCanCache:1;	/* oplocked.  We need to extend cases beyond this i.e. what
+				   if file read-only or if file locked? or if file on r/o vol? */
+	struct inode vfs_inode;
+};
+
+static inline struct cifsInodeInfo *
+CIFS_I(struct inode *inode)
+{
+	return container_of(inode, struct cifsInodeInfo, vfs_inode);
+}
+
+static inline struct cifs_sb_info *
+CIFS_SB(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+
+/* one of these for every pending CIFS request to the server */
+struct mid_q_entry {
+	struct list_head qhead;	/* mids waiting on reply from this server */
+	__u16 mid;		/* multiplex id */
+	__u16 pid;		/* process id */
+	__u16 command;		/* smb command code */
+	struct timeval when_sent;	/* time when smb sent */
+	struct cifsSesInfo *ses;	/* smb was sent to this server */
+	struct task_struct *tsk;	/* task waiting for response */
+	struct smb_hdr *resp_buf;	/* response buffer */
+	int midState;		/* wish this could be an enum but can not pass that to wait_event */
+};
+
+#define   MID_FREE 0
+#define   MID_REQUEST_ALLOCATED 1
+#define   MID_REQUEST_SUBMITTED 2
+#define   MID_RESPONSE_RECEIVED 4
+
+struct servers_not_supported {	/* @z4a */
+	struct servers_not_supported *next1;	/* @z4a */
+	char server_Name[SERVER_NAME_LEN_WITH_NULL];	/* @z4a */
+	/* Server Names in SMB protocol are 15 chars + X'20'  */
+	/*   in 16th byte...                      @z4a        */
+};
+
+/*
+ *****************************************************************
+ * All constants go here
+ *****************************************************************
+ */
+
+#define UID_HASH (16)
+
+/*
+ * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the
+ * following to be declared.
+ */
+
+/* BB Every global should have an associated mutex for safe update BB */
+
+#ifdef DECLARE_GLOBALS_HERE
+#define GLOBAL_EXTERN
+#else
+#define GLOBAL_EXTERN extern
+#endif
+
+/*
+ * The list of servers that did not respond with NT LM 0.12.
+ * This list helps improve performance and eliminate the messages indicating
+ * that we had a communications error talking to the server in this list. 
+ */
+GLOBAL_EXTERN struct servers_not_supported *NotSuppList;	/*@z4a */
+
+/*
+ * The following is a hash table of all the users we know about.
+ */
+GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
+
+GLOBAL_EXTERN struct list_head GlobalServerList;	/* BB this one is not implemented yet */
+GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
+GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
+/*
+ * Global list of free SMB structures
+ */
+GLOBAL_EXTERN void *GlobalFreeSMB;
+
+/*
+ * Global transaction id (XID) information
+ */
+GLOBAL_EXTERN unsigned int GlobalCurrentXid;	/* protected by GlobalMid_Sem */
+GLOBAL_EXTERN unsigned int GlobalTotalActiveXid;	/* prot by GlobalMid_Sem */
+GLOBAL_EXTERN unsigned int GlobalMaxActiveXid;	/* prot by GlobalMid_Sem */
+
+GLOBAL_EXTERN char Local_System_Name[15];
+
+/*
+ *  Global counters, updated atomically
+ */
+GLOBAL_EXTERN atomic_t sesInfoAllocCount;
+GLOBAL_EXTERN atomic_t tconInfoAllocCount;
+
+/* Various Debug counters to remove someday (BB) */
+GLOBAL_EXTERN atomic_t bufAllocCount;
+GLOBAL_EXTERN atomic_t midCount;
+
+/* Misc globals */
+GLOBAL_EXTERN unsigned int multiuser_mount;	/* if enabled allows new sessions
+                                     to be established on existing mount if we
+					                 have the uid/password or Kerberos credential 
+                                     or equivalent for current user */
+GLOBAL_EXTERN unsigned int oplockEnabled;
+GLOBAL_EXTERN unsigned int extended_security;	/* if on, session setup sent 
+                                     with more secure ntlmssp2 challenge/resp */
+GLOBAL_EXTERN unsigned int ntlmv2_support;  /* better optional password hash */
+GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
+
+
diff -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifspdu.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,1527 @@
+/*
+ *   fs/cifs/cifspdu.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+#ifndef _CIFSPDU_H
+#define _CIFSPDU_H
+
+#include <net/sock.h>
+
+#define CIFS_PROT   0
+#define BAD_PROT    CIFS_PROT+1
+
+/* SMB command codes */
+#define SMB_COM_CREATE_DIRECTORY      0x00
+#define SMB_COM_DELETE_DIRECTORY      0x01
+#define SMB_COM_CLOSE                 0x04
+#define SMB_COM_DELETE                0x06
+#define SMB_COM_RENAME                0x07
+#define SMB_COM_LOCKING_ANDX          0x24
+#define SMB_COM_READ_ANDX             0x2E
+#define SMB_COM_WRITE_ANDX            0x2F
+#define SMB_COM_TRANSACTION2	      0x32
+#define SMB_COM_TRANSACTION2_SECONDARY 0x33
+#define SMB_COM_TREE_DISCONNECT       0x71
+#define SMB_COM_NEGOTIATE             0x72
+#define SMB_COM_SESSION_SETUP_ANDX    0x73
+#define SMB_COM_LOGOFF_ANDX           0x74
+#define SMB_COM_TREE_CONNECT_ANDX     0x75
+#define SMB_COM_NT_TRANSACT           0xA0
+#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
+#define SMB_COM_NT_CREATE_ANDX        0xA2
+#define SMB_COM_NT_RENAME             0xA5
+
+/* Transact2 subcommand codes */
+#define TRANS2_OPEN                   0x00
+#define TRANS2_FIND_FIRST             0x01
+#define TRANS2_FIND_NEXT              0x02
+#define TRANS2_QUERY_FS_INFORMATION   0x03
+#define TRANS2_QUERY_PATH_INFORMATION 0x05
+#define TRANS2_SET_PATH_INFORMATION   0x06
+#define TRANS2_QUERY_FILE_INFORMATION 0x07
+#define TRANS2_SET_FILE_INFORMATION   0x08
+#define TRANS2_GET_DFS_REFERRAL       0x10
+#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11
+
+/* NT Transact subcommand codes */
+#define NT_TRANSACT_CREATE            0x01
+#define NT_TRANSACT_IOCTL             0x02
+#define NT_TRANSACT_SET_SECURITY_DESC 0x03
+#define NT_TRANSACT_NOTIFY_CHANGE     0x04
+#define NT_TRANSACT_RENAME            0x05
+#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06
+
+#define MAX_CIFS_HDR_SIZE 256	/* chained NTCreateXReadX will probably be biggest */
+
+/* internal cifs vfs structures */
+/*****************************************************************
+ * All constants go here
+ *****************************************************************
+ */
+
+/*
+ * Starting value for maximum SMB size negotiation
+ */
+#define CIFS_MAX_MSGSIZE (4*1024)
+
+/*
+ * Size of encrypted user password in bytes
+ */
+#define CIFS_ENCPWD_SIZE (16)
+
+/*
+ * Size of the crypto key returned on the negotiate SMB in bytes
+ */
+#define CIFS_CRYPTO_KEY_SIZE (8)
+
+/*
+ * Size of the session key (crypto key encrypted with the password
+ */
+#define CIFS_SESSION_KEY_SIZE (24)
+
+/*
+ * Maximum user name length
+ */
+#define CIFS_UNLEN (20)
+
+/*
+ * Flags on SMB open
+ */
+#define SMBOPEN_WRITE_THROUGH 0x4000
+#define SMBOPEN_DENY_ALL      0x0010
+#define SMBOPEN_DENY_WRITE    0x0020
+#define SMBOPEN_DENY_READ     0x0030
+#define SMBOPEN_DENY_NONE     0x0040
+#define SMBOPEN_READ          0x0000
+#define SMBOPEN_WRITE         0x0001
+#define SMBOPEN_READWRITE     0x0002
+#define SMBOPEN_EXECUTE       0x0003
+
+#define SMBOPEN_OCREATE       0x0010
+#define SMBOPEN_OTRUNC        0x0002
+#define SMBOPEN_OAPPEND       0x0001
+
+/*
+ * SMB flag definitions 
+ */
+#define SMBFLG_EXTD_LOCK 0x01	/* server supports lock-read write-unlock primitives */
+#define SMBFLG_RCV_POSTED 0x02	/* obsolete */
+#define SMBFLG_RSVD 0x04
+#define SMBFLG_CASELESS 0x08	/* all pathnames treated as caseless (off implies case sensitive file handling requested) */
+#define SMBFLG_CANONICAL_PATH_FORMAT 0x10	/* obsolete */
+#define SMBFLG_OLD_OPLOCK 0x20	/* obsolete */
+#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40	/* obsolete */
+#define SMBFLG_RESPONSE 0x80	/* this PDU is a response from server */
+
+/*
+ * SMB flag2 definitions 
+ */
+#define SMBFLG2_KNOWS_LONG_NAMES 0x0001	/* can send long (non-8.3) path names in response */
+#define SMBFLG2_KNOWS_EAS 0x0002
+#define SMBFLG2_SECURITY_SIGNATURE 0x0004
+#define SMBFLG2_IS_LONG_NAME 0x0040
+#define SMBFLG2_EXT_SEC 0x0800
+#define SMBFLG2_DFS 0x1000
+#define SMBFLG2_PAGING_IO 0x2000
+#define SMBFLG2_ERR_STATUS 0x4000
+#define SMBFLG2_UNICODE 0x8000
+
+/*
+ * These are the file access permission bits defined in CIFS for the
+ * NTCreateAndX as well as the level 0x107
+ * TRANS2_QUERY_PATH_INFORMATION API.  The level 0x107, SMB_QUERY_FILE_ALL_INFO
+ * responds with the AccessFlags.
+ * The AccessFlags specifies the access permissions a caller has to the
+ * file and can have any suitable combination of the following values:
+ */
+
+#define FILE_READ_DATA        0x00000001	/* Data can be read from the file   */
+#define FILE_WRITE_DATA       0x00000002	/* Data can be written to the file  */
+#define FILE_APPEND_DATA      0x00000004	/* Data can be appended to the file */
+#define FILE_READ_EA          0x00000008	/* Extended attributes associated   */
+					 /* with the file can be read        */
+#define FILE_WRITE_EA         0x00000010	/* Extended attributes associated   */
+					 /* with the file can be written     */
+#define FILE_EXECUTE          0x00000020	/*Data can be read into memory from */
+					 /* the file using system paging I/O */
+#define FILE_DELETE_CHILD     0x00000040
+#define FILE_READ_ATTRIBUTES  0x00000080	/* Attributes associated with the   */
+					 /* file can be read                 */
+#define FILE_WRITE_ATTRIBUTES 0x00000100	/* Attributes associated with the   */
+					 /* file can be written              */
+#define DELETE                0x00010000	/* The file can be deleted          */
+#define READ_CONTROL          0x00020000	/* The access control list and      */
+					 /* ownership associated with the    */
+					 /* file can be read                 */
+#define WRITE_DAC             0x00040000	/* The access control list and      */
+					 /* ownership associated with the    */
+					 /* file can be written.             */
+#define WRITE_OWNER           0x00080000	/* Ownership information associated */
+					 /* with the file can be written     */
+#define SYNCHRONIZE           0x00100000	/* The file handle can waited on to */
+					 /* synchronize with the completion  */
+					 /* of an input/output request       */
+#define GENERIC_ALL           0x10000000
+#define GENERIC_EXECUTE       0x20000000
+#define GENERIC_WRITE         0x40000000
+#define GENERIC_READ          0x80000000
+					 /* In summary - Relevant file       */
+					 /* access flags from CIFS are       */
+					 /* file_read_data, file_write_data  */
+					 /* file_execute, file_read_attributes */
+					 /* write_dac, and delete.           */
+
+/*
+ * Invalid readdir handle
+ */
+#define CIFS_NO_HANDLE        0xFFFF
+
+/* IPC$ in ASCII */
+#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24"
+
+/* IPC$ in Unicode */
+#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00"
+
+/* Unicode Null terminate 2 bytes of 0 */
+#define UNICODE_NULL "\x00\x00"
+#define ASCII_NULL 0x00
+
+/*
+ * Server type values (returned on EnumServer API
+ */
+#define CIFS_SV_TYPE_DC     0x00000008
+#define CIFS_SV_TYPE_BACKDC 0x00000010
+
+/*
+ * Alias type flags (From EnumAlias API call
+ */
+#define CIFS_ALIAS_TYPE_FILE 0x0001
+#define CIFS_SHARE_TYPE_FILE 0x0000
+
+/*
+ * File Attribute flags
+ */
+#define ATTR_READONLY  0x0001
+#define ATTR_HIDDEN    0x0002
+#define ATTR_SYSTEM    0x0004
+#define ATTR_VOLUME    0x0008
+#define ATTR_DIRECTORY 0x0010
+#define ATTR_ARCHIVE   0x0020
+#define ATTR_DEVICE    0x0040
+#define ATTR_NORMAL    0x0080
+#define ATTR_TEMPORARY 0x0100
+#define ATTR_SPARSE    0x0200
+#define ATTR_REPARSE   0x0400
+#define ATTR_COMPRESSED 0x0800
+#define ATTR_OFFLINE    0x1000	/* ie file not immediately available - offline storage */
+#define ATTR_NOT_CONTENT_INDEXED 0x2000
+#define ATTR_ENCRYPTED  0x4000
+#define ATTR_POSIX_SEMANTICS 0x01000000
+#define ATTR_SEQUENTIAL_SCAN 0x08000000
+#define ATTR_RANDOM_ACCESS   0x10000000
+#define ATTR_NO_BUFFERING    0x20000000
+#define ATTR_WRITE_THROUGH   0x80000000
+
+/* ShareAccess flags */
+#define FILE_NO_SHARE     0x00000000
+#define FILE_SHARE_READ   0x00000001
+#define FILE_SHARE_WRITE  0x00000002
+#define FILE_SHARE_DELETE 0x00000004
+#define FILE_SHARE_ALL    0x00000007
+
+/* CreateDisposition flags */
+#define FILE_SUPERSEDE    0x00000000
+#define FILE_OPEN         0x00000001
+#define FILE_CREATE       0x00000002
+#define FILE_OPEN_IF      0x00000003
+#define FILE_OVERWRITE    0x00000004
+#define FILE_OVERWRITE_IF 0x00000005
+
+/* CreateOptions */
+#define CREATE_NOT_FILE   0x00000001	/* if set, indicates must not be file */
+#define CREATE_NOT_DIR    0x00000040	/* if set, indicates must not be directory */
+
+/* ImpersonationLevel flags */
+#define SECURITY_ANONYMOUS      0
+#define SECURITY_IDENTIFICATION 1
+#define SECURITY_IMPERSONATION  2
+#define SECURITY_DELEGATION     3
+
+/* SecurityFlags */
+#define SECURITY_CONTEXT_TRACKING 0x01
+#define SECURITY_EFFECTIVE_ONLY   0x02
+
+/*
+ * Default PID value, used in all SMBs where the PID is not important
+ */
+#define CIFS_DFT_PID  0x1234
+
+/*
+ * We use the same routine for Copy and Move SMBs.  This flag is used to
+ * distinguish
+ */
+#define CIFS_COPY_OP 1
+#define CIFS_RENAME_OP 2
+
+#define GETU16(var)  (*((__u16 *)var))	/* BB check for endian issues */
+#define GETU32(var)  (*((__u32 *)var))	/* BB check for endian issues */
+
+#pragma pack(1)
+
+struct smb_hdr {
+	__u32 smb_buf_length;	/* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */
+	__u8 Protocol[4];
+	__u8 Command;
+	union {
+		struct {
+			__u8 ErrorClass;
+			__u8 Reserved;
+			__u16 Error;	/* note: treated as little endian (le) on wire */
+		} DosError;
+		__u32 CifsError;	/* note: le */
+	} Status;
+	__u8 Flags;
+	__u16 Flags2;		/* note: le */
+	__u16 PidHigh;		/* note: le */
+	__u8 SecuritySignature[8];	/* note le */
+	__u8 pad[2];
+	__u16 Tid;
+	__u16 Pid;		/* note: le */
+	__u16 Uid;
+	__u16 Mid;
+	__u8 WordCount;
+};
+/* given a pointer to an smb_hdr retrieve the value of byte count */
+#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
+
+/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
+#define pByteArea(smb_var) ((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
+
+/*
+ * Computer Name Length
+ */
+#define CNLEN 15
+
+/*
+ * Share Name Length					  @S8A
+ * Note:  This length is limited by the SMB used to get   @S8A
+ *        the Share info.   NetShareEnum only returns 13  @S8A
+ *        chars, including the null termination.          @S8A 
+ */
+#define SNLEN 12		/*@S8A */
+
+/*
+ * Comment Length
+ */
+#define MAXCOMMENTLEN 40
+
+/*
+ * The OS/2 maximum path name
+ */
+#define MAX_PATHCONF 256
+
+/*
+ *  SMB frame definitions  (following must be packed structs)
+ *  See the SNIA CIFS Specification for details.
+ *
+ *  The Naming convention is the lower case version of the
+ *  smb command code name for the struct and this is typedef to the
+ *  uppercase version of the same name with the prefix SMB_ removed 
+ *  for brevity.  Although typedefs are not commonly used for 
+ *  structure definitions in the Linux kernel, their use in the
+ *  CIFS standards document, which this code is based on, may
+ *  make this one of the cases where typedefs for structures make
+ *  sense to improve readability for readers of the standards doc.
+ *  Typedefs can always be removed later if they are too distracting
+ *  and they are only used for the CIFSs PDUs themselves, not
+ *  internal cifs vfs structures
+ *  
+ */
+
+typedef struct negotiate_req {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;
+	unsigned char DialectsArray[1];
+} NEGOTIATE_REQ;
+
+typedef struct negotiate_rsp {
+	struct smb_hdr hdr;	/* wct = 17 */
+	__u16 DialectIndex;
+	__u8 SecurityMode;
+	__u16 MaxMpxCount;
+	__u16 MaxNumberVcs;
+	__u32 MaxBufferSize;
+	__u32 MaxRawSize;
+	__u32 SessionKey;
+	__u32 Capabilities;	/* see below */
+	__u32 SystemTimeLow;
+	__u32 SystemTimeHigh;
+	__u16 ServerTimeZone;
+	__u8 EncryptionKeyLength;
+	__u16 ByteCount;
+	union {
+		unsigned char EncryptionKey[1];	/* if cap extended security is off */
+		/* followed by Domain name - if extended security is off */
+		/* followed by 16 bytes of server GUID */
+		/* followed by security blob if cap_extended_security negotiated */
+		struct {
+			unsigned char GUID[16];
+			unsigned char SecurityBlob[1];
+		} extended_response;
+	} u;
+} NEGOTIATE_RSP;
+
+/* SecurityMode bits */
+#define SECMODE_USER          0x01	/* off indicates share level security */
+#define SECMODE_PW_ENCRYPT    0x02
+#define SECMODE_SIGN_ENABLED  0x04	/* SMB security signatures enabled */
+#define SECMODE_SIGN_REQUIRED 0x08	/* SMB security signatures required */
+
+/* Negotiate response Capabilities */
+#define CAP_RAW_MODE           0x00000001
+#define CAP_MPX_MODE           0x00000002
+#define CAP_UNICODE            0x00000004
+#define CAP_LARGE_FILES        0x00000008
+#define CAP_NT_SMBS            0x00000010	/* implies CAP_NT_FIND */
+#define CAP_RPC_REMOTE_APIS    0x00000020
+#define CAP_STATUS32           0x00000040
+#define CAP_LEVEL_II_OPLOCKS   0x00000080
+#define CAP_LOCK_AND_READ      0x00000100
+#define CAP_NT_FIND            0x00000200
+#define CAP_DFS                0x00001000
+#define CAP_INFOLEVEL_PASSTHRU 0x00002000
+#define CAP_LARGE_READ_X       0x00004000
+#define CAP_LARGE_WRITE_X      0x00008000
+#define CAP_UNIX               0x00800000
+#define CAP_RESERVED           0x02000000
+#define CAP_BULK_TRANSFER      0x20000000
+#define CAP_COMPRESSED_DATA    0x40000000
+#define CAP_EXTENDED_SECURITY  0x80000000
+
+typedef union smb_com_session_setup_andx {
+	struct {		/* request format */
+		struct smb_hdr hdr;	/* wct = 12 */
+		__u8 AndXCommand;
+		__u8 AndXReserved;
+		__u16 AndXOffset;
+		__u16 MaxBufferSize;
+		__u16 MaxMpxCount;
+		__u16 VcNumber;
+		__u32 SessionKey;
+		__u16 SecurityBlobLength;
+		__u32 Reserved;
+		__u32 Capabilities;	/* see below */
+		__u16 ByteCount;
+		unsigned char SecurityBlob[1];	/* followed by */
+		/* STRING NativeOS */
+		/* STRING NativeLanMan */
+	} req;			/* NTLM request format (with extended security */
+
+	struct {		/* request format */
+		struct smb_hdr hdr;	/* wct = 13 */
+		__u8 AndXCommand;
+		__u8 AndXReserved;
+		__u16 AndXOffset;
+		__u16 MaxBufferSize;
+		__u16 MaxMpxCount;
+		__u16 VcNumber;
+		__u32 SessionKey;
+		__u16 CaseInsensitivePasswordLength;	/* ASCII password length */
+		__u16 CaseSensitivePasswordLength;	/* Unicode password length */
+		__u32 Reserved;	/* see below */
+		__u32 Capabilities;
+		__u16 ByteCount;
+		unsigned char CaseInsensitivePassword[1];	/* followed by: */
+		/* unsigned char * CaseSensitivePassword; */
+		/* STRING AccountName */
+		/* STRING PrimaryDomain */
+		/* STRING NativeOS */
+		/* STRING NativeLanMan */
+	} req_no_secext;	/* NTLM request format (without extended security */
+
+	struct {		/* default (NTLM) response format */
+		struct smb_hdr hdr;	/* wct = 4 */
+		__u8 AndXCommand;
+		__u8 AndXReserved;
+		__u16 AndXOffset;
+		__u16 Action;	/* see below */
+		__u16 SecurityBlobLength;
+		__u16 ByteCount;
+		unsigned char SecurityBlob[1];	/* followed by */
+/*      unsigned char  * NativeOS;      */
+/*	unsigned char  * NativeLanMan;  */
+/*      unsigned char  * PrimaryDomain; */
+	} resp;			/* NTLM response format (with or without extended security */
+
+	struct {		/* request format */
+		struct smb_hdr hdr;	/* wct = 10 */
+		__u8 AndXCommand;
+		__u8 AndXReserved;
+		__u16 AndXOffset;
+		__u16 MaxBufferSize;
+		__u16 MaxMpxCount;
+		__u16 VcNumber;
+		__u32 SessionKey;
+		__u16 PassswordLength;
+		__u32 Reserved;
+		__u16 ByteCount;
+		unsigned char AccountPassword[1];	/* followed by */
+		/* STRING AccountName */
+		/* STRING PrimaryDomain */
+		/* STRING NativeOS */
+		/* STRING NativeLanMan */
+	} old_req;		/* pre-NTLM (LANMAN2.1) request format */
+
+	struct {		/* default (NTLM) response format */
+		struct smb_hdr hdr;	/* wct = 3 */
+		__u8 AndXCommand;
+		__u8 AndXReserved;
+		__u16 AndXOffset;
+		__u16 Action;	/* see below */
+		__u16 ByteCount;
+		unsigned char NativeOS[1];	/* followed by */
+/*	unsigned char * NativeLanMan; */
+/*      unsigned char * PrimaryDomain; */
+	} old_resp;		/* pre-NTLM (LANMAN2.1) response format */
+} SESSION_SETUP_ANDX;
+
+#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
+
+/* Capabilities bits (for NTLM SessSetup request) */
+#define CAP_UNICODE            0x00000004
+#define CAP_LARGE_FILES        0x00000008
+#define CAP_NT_SMBS            0x00000010
+#define CAP_STATUS32           0x00000040
+#define CAP_LEVEL_II_OPLOCKS   0x00000080
+#define CAP_NT_FIND            0x00000200	/* reserved should be zero (presumably because NT_SMBs implies the same thing) */
+#define CAP_BULK_TRANSFER      0x20000000
+#define CAP_EXTENDED_SECURITY  0x80000000
+
+/* Action bits */
+#define GUEST_LOGIN 1
+
+typedef struct smb_com_tconx_req {
+	struct smb_hdr hdr;	/* wct = 4 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 Flags;		/* see below */
+	__u16 PasswordLength;
+	__u16 ByteCount;
+	unsigned char Password[1];	/* followed by */
+/* STRING Path    *//* \\server\share name */
+	/* STRING Service */
+} TCONX_REQ;
+
+typedef struct smb_com_tconx_rsp {
+	struct smb_hdr hdr;	/* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 OptionalSupport;	/* see below */
+	__u16 ByteCount;
+	unsigned char Service[1];	/* always ASCII, not Unicode */
+	/* STRING NativeFileSystem */
+} TCONX_RSP;
+
+/* tree connect Flags */
+#define DISCONNECT_TID          0x0001
+#define TCON_EXTENDED_SECINFO   0x0008
+/* OptionalSupport bits */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001	/* must have bits (exclusive searches suppt. */
+#define SMB_SHARE_IS_IN_DFS     0x0002
+
+typedef struct smb_com_logoff_andx_req {
+
+	struct smb_hdr hdr;	/* wct = 2 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 ByteCount;
+} LOGOFF_ANDX_REQ;
+
+typedef struct smb_com_logoff_andx_rsp {
+	struct smb_hdr hdr;	/* wct = 2 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 ByteCount;
+} LOGOFF_ANDX_RSP;
+
+typedef union smb_com_tree_disconnect {	/* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */
+	struct {
+		struct smb_hdr hdr;	/* wct = 0 */
+		__u16 ByteCount;	/* bcc = 0 */
+	} req;
+	struct {
+		struct smb_hdr hdr;	/* wct = 0 */
+		__u16 ByteCount;	/* bcc = 0 */
+	} resp;
+} TREE_DISCONNECT;
+
+typedef struct smb_com_close_req {
+	struct smb_hdr hdr;	/* wct = 3 */
+	__u16 FileID;		/* target file attributes */
+	__u32 LastWriteTime;	/* should be zero */
+	__u16 ByteCount;	/* 0 */
+} CLOSE_REQ;
+
+typedef struct smb_com_close_rsp {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;	/* bct = 0 */
+} CLOSE_RSP;
+
+/* OpenFlags */
+#define REQ_OPLOCK         0x00000002
+#define REQ_BATCHOPLOCK    0x00000004
+#define REQ_OPENDIRONLY    0x00000008
+
+typedef struct smb_com_open_req {	/* also handles create */
+	struct smb_hdr hdr;	/* wct = 24 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u8 Reserved;		/* Must Be Zero */
+	__u16 NameLength;
+	__u32 OpenFlags;
+	__u32 RootDirectoryFid;
+	__u32 DesiredAccess;
+	__u64 AllocationSize;
+	__u32 FileAttributes;
+	__u32 ShareAccess;
+	__u32 CreateDisposition;
+	__u32 CreateOptions;
+	__u32 ImpersonationLevel;
+	__u8 SecurityFlags;
+	__u16 ByteCount;
+	char fileName[1];
+} OPEN_REQ;
+
+typedef struct smb_com_open_rsp {
+	struct smb_hdr hdr;	/* wct = 34 BB */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u8 OplockLevel;
+	__u16 Fid;
+	__u32 CreateAction;
+	__u64 CreationTime;
+	__u64 LastAccessTime;
+	__u64 LastWriteTime;
+	__u64 ChangeTime;
+	__u32 FileAttributes;
+	__u64 AllocationSize;
+	__u64 EndOfFile;
+	__u16 FileType;
+	__u16 DeviceState;
+	__u8 DirectoryFlag;
+	__u16 ByteCount;	/* bct = 0 */
+} OPEN_RSP;
+
+typedef struct smb_com_write_req {
+	struct smb_hdr hdr;	/* wct = 14 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 Fid;
+	__u32 OffsetLow;
+	__u32 Reserved;
+	__u16 WriteMode;
+	__u16 Remaining;
+	__u16 DataLengthHigh;
+	__u16 DataLengthLow;
+	__u16 DataOffset;
+	__u32 OffsetHigh;
+	__u16 ByteCount;
+	__u8 Pad;		/* BB check for whether padded to DWORD boundary and optimum performance here */
+	char Data[1];
+} WRITE_REQ;
+
+typedef struct smb_com_write_rsp {
+	struct smb_hdr hdr;	/* wct = 6 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 Count;
+	__u16 Remaining;
+	__u32 Reserved;
+	__u16 ByteCount;
+} WRITE_RSP;
+
+typedef struct smb_com_read_req {
+	struct smb_hdr hdr;	/* wct = 12 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 Fid;
+	__u32 OffsetLow;
+	__u16 MaxCount;
+	__u16 MinCount;		/* obsolete */
+	__u32 MaxCountHigh;
+	__u16 Remaining;
+	__u32 OffsetHigh;
+	__u16 ByteCount;
+} READ_REQ;
+
+typedef struct smb_com_read_rsp {
+	struct smb_hdr hdr;	/* wct = 12 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 Remaining;
+	__u16 DataCompactionMode;
+	__u16 Reserved;
+	__u16 DataLength;
+	__u16 DataOffset;
+	__u16 DataLengthHigh;
+	__u64 Reserved2;
+	__u16 ByteCount;
+	__u8 Pad;		/* BB check for whether padded to DWORD boundary and optimum performance here */
+	char Data[1];
+} READ_RSP;
+
+typedef struct locking_andx_range {
+	__u16 Pid;
+	__u16 Pad;
+	__u64 Offset;
+	__u64 Length;
+} LOCKING_ANDX_RANGE;
+
+#define LOCKING_ANDX_SHARED_LOCK     0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE  0x02
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK     0x08
+#define LOCKING_ANDX_LARGE_FILES     0x10	/* always on for us */
+
+typedef struct smb_com_lock_req {
+	struct smb_hdr hdr;	/* wct = 8 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 Fid;
+	__u8 LockType;
+	__u8 OplockLevel;
+	__u32 Timeout;
+	__u16 NumberOfUnlocks;
+	__u16 NumberOfLocks;
+	__u16 ByteCount;
+	LOCKING_ANDX_RANGE Locks[1];
+} LOCK_REQ;
+
+typedef struct smb_com_lock_rsp {
+	struct smb_hdr hdr;	/* wct = 2 */
+	__u8 AndXCommand;
+	__u8 AndXReserved;
+	__u16 AndXOffset;
+	__u16 ByteCount;
+} LOCK_RSP;
+
+typedef struct smb_com_rename_req {
+	struct smb_hdr hdr;	/* wct = 1 */
+	__u16 SearchAttributes;	/* target file attributes */
+	__u16 ByteCount;
+	__u8 BufferFormat;	/* 4 = ASCII or Unicode */
+	unsigned char OldFileName[1];
+	/* followed by __u8 BufferFormat2 */
+	/* followed by NewFileName */
+} RENAME_REQ;
+
+#define CREATE_HARD_LINK 0x103
+typedef struct smb_com_nt_rename_req {	/* A5 - also used for create hardlink */
+	struct smb_hdr hdr;	/* wct = 4 */
+	__u16 SearchAttributes;	/* target file attributes */
+	__u16 Flags;		/* spec says Information Level */
+	__u32 ClusterCount;
+	__u16 ByteCount;
+	__u8 BufferFormat;	/* 4 = ASCII or Unicode */
+	unsigned char OldFileName[1];
+	/* followed by __u8 BufferFormat2 */
+	/* followed by NewFileName */
+} NT_RENAME_REQ;
+
+typedef struct smb_com_rename_rsp {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;	/* bct = 0 */
+} RENAME_RSP;
+
+typedef struct smb_com_delete_file_req {
+	struct smb_hdr hdr;	/* wct = 1 */
+	__u16 SearchAttributes;
+	__u16 ByteCount;
+	__u8 BufferFormat;	/* 4 = ASCII */
+	unsigned char fileName[1];
+} DELETE_FILE_REQ;
+
+typedef struct smb_com_delete_file_rsp {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;	/* bct = 0 */
+} DELETE_FILE_RSP;
+
+typedef struct smb_com_delete_directory_req {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;
+	__u8 BufferFormat;	/* 4 = ASCII */
+	unsigned char DirName[1];
+} DELETE_DIRECTORY_REQ;
+
+typedef struct smb_com_delete_directory_rsp {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;	/* bct = 0 */
+} DELETE_DIRECTORY_RSP;
+
+typedef struct smb_com_create_directory_req {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;
+	__u8 BufferFormat;	/* 4 = ASCII */
+	unsigned char DirName[1];
+} CREATE_DIRECTORY_REQ;
+
+typedef struct smb_com_create_directory_rsp {
+	struct smb_hdr hdr;	/* wct = 0 */
+	__u16 ByteCount;	/* bct = 0 */
+} CREATE_DIRECTORY_RSP;
+
+typedef struct smb_com_nt_transaction_ioctl_req {
+	struct smb_hdr hdr;	/* wct = 23 */
+	__u8 MaxSetupCount;
+	__u16 Reserved;
+	__u32 TotalParameterCount;
+	__u32 TotalDataCount;
+	__u32 MaxParameterCount;
+	__u32 MaxDataCount;
+	__u32 ParameterCount;
+	__u32 ParameterOffset;
+	__u32 DataCount;
+	__u32 DataOffset;
+	__u8 SetupCount;	/* four setup words follow subcommand */
+	/* SNIA spec incorrectly included spurious pad here */
+	__u16 SubCommand;	/* 2 = IOCTL/FSCTL */
+	__u32 FunctionCode;
+	__u16 Fid;
+	__u8 IsFSCTLFlag;	/* 1 = File System Control, 0 = device control (IOCTL)    */
+	__u8 IsRootFlag;	/* 1 = apply command to root of share (must be DFS share) */
+	__u16 ByteCount;
+	__u8 Pad[3];
+	__u8 Data[1];
+} TRANSACT_IOCTL_REQ;
+
+typedef struct smb_com_transaction_ioctl_rsp {
+	struct smb_hdr hdr;	/* wct = 19 */
+	__u8 Reserved[3];
+	__u32 TotalParameterCount;
+	__u32 TotalDataCount;
+	__u32 ParameterCount;
+	__u32 ParameterOffset;
+	__u32 ParameterDisplacement;
+	__u32 DataCount;
+	__u32 DataOffset;
+	__u32 DataDisplacement;
+	__u8 SetupCount;	/* 1 */
+	__u16 ReturnedDataLen;
+	__u16 ByteCount;
+	__u8 Pad[3];
+} TRANSACT_IOCTL_RSP;
+
+typedef union smb_com_transaction2 {
+	struct {
+		struct smb_hdr hdr;	/* wct = 14+ */
+		__u16 TotalParameterCount;
+		__u16 TotalDataCount;
+		__u16 MaxParameterCount;
+		__u16 MaxDataCount;
+		__u8 MaxSetupCount;
+		__u8 Reserved;
+		__u16 Flags;
+		__u32 Timeout;
+		__u16 Reserved2;
+		__u16 ParameterCount;
+		__u16 ParameterOffset;
+		__u16 DataCount;
+		__u16 DataOffset;
+		__u8 SetupCount;
+		__u8 Reserved3;
+		__u16 SubCommand;	/* 1st setup word - can be followed by SetupCount words */
+		__u16 ByteCount;	/* careful - setupcount is not always one */
+	} req;
+	struct {
+		struct smb_hdr hdr;	/* wct = 0 */
+		__u16 TotalParameterCount;
+		__u16 TotalDataCount;
+		__u16 Reserved;
+		__u16 ParameterCount;
+		__u16 ParamterOffset;
+		__u16 ParameterDisplacement;
+		__u16 DataCount;
+		__u16 DataOffset;
+		__u16 DataDisplacement;
+		__u8 SetupCount;
+		__u8 Reserved1;	/* should be zero setup words following */
+		__u16 ByteCount;
+		__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
+		/* data area follows */
+	} resp;
+} TRANSACTION2;
+
+/* PathInfo/FileInfo infolevels */
+#define SMB_INFO_STANDARD                1
+#define SMB_INFO_IS_NAME_VALID           6
+#define SMB_QUERY_FILE_BASIC_INFO    0x101
+#define SMB_QUERY_FILE_STANDARD_INFO 0x102
+#define SMB_QUERY_FILE_NAME_INFO     0x104
+#define SMB_QUERY_FILE_ALLOCATION_INFO	0x105
+#define SMB_QUERY_FILE_END_OF_FILEINFO	0x106
+#define SMB_QUERY_FILE_ALL_INFO      0x107
+#define SMB_QUERY_ALT_NAME_INFO      0x108
+#define SMB_QUERY_FILE_STREAM_INFO   0x109
+#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
+#define SMB_QUERY_FILE_UNIX_BASIC    0x200
+#define SMB_QUERY_FILE_UNIX_LINK     0x201
+
+#define SMB_SET_FILE_BASIC_INFO		0x101
+#define SMB_SET_FILE_DISPOSITION_INFO	0x102
+#define SMB_SET_FILE_ALLOCATION_INFO	0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO	0x104
+#define SMB_SET_FILE_UNIX_BASIC         0x200
+#define SMB_SET_FILE_UNIX_LINK          0x201
+#define SMB_SET_FILE_UNIX_HLINK         0x203
+#define SMB_SET_FILE_BASIC_INFO2        0x3ec
+#define SMB_SET_FILE_ALLOCATION_INFO2	0x3fb
+#define SMB_SET_FILE_END_OF_FILE_INFO2	0x3fc
+
+/* Find File infolevels */
+#define SMB_FIND_FILE_DIRECTORY_INFO	  0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
+#define SMB_FIND_FILE_NAMES_INFO	  0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
+#define SMB_FIND_FILE_UNIX                0x202
+
+typedef struct smb_com_transaction2_qpi_req {
+	struct smb_hdr hdr;	/* wct = 14+ */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 MaxParameterCount;
+	__u16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__u32 Timeout;
+	__u16 Reserved2;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u8 SetupCount;
+	__u8 Reserved3;
+	__u16 SubCommand;	/* one setup word */
+	__u16 ByteCount;
+	__u8 Pad;
+	__u16 InformationLevel;
+	__u32 Reserved4;
+	char FileName[1];
+} TRANSACTION2_QPI_REQ;
+
+typedef struct smb_com_transaction2_qpi_rsp {
+	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 Reserved;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 ParameterDisplacement;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u16 DataDisplacement;
+	__u8 SetupCount;
+	__u8 Reserved1;		/* should be zero setup words following */
+	__u16 ByteCount;
+	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
+} TRANSACTION2_QPI_RSP;
+
+typedef struct smb_com_transaction2_spi_req {
+	struct smb_hdr hdr;	/* wct = 15 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 MaxParameterCount;
+	__u16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__u32 Timeout;
+	__u16 Reserved2;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u8 SetupCount;
+	__u8 Reserved3;
+	__u16 SubCommand;	/* one setup word */
+	__u16 ByteCount;
+	__u8 Pad;
+	__u16 Pad1;
+	__u16 InformationLevel;
+	__u32 Reserved4;
+	char FileName[1];
+} TRANSACTION2_SPI_REQ;
+
+typedef struct smb_com_transaction2_spi_rsp {
+	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 Reserved;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 ParameterDisplacement;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u16 DataDisplacement;
+	__u8 SetupCount;
+	__u8 Reserved1;		/* should be zero setup words following */
+	__u16 ByteCount;
+	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
+} TRANSACTION2_SPI_RSP;
+
+struct smb_com_transaction2_sfi_req {
+	struct smb_hdr hdr;	/* wct = 15 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 MaxParameterCount;
+	__u16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__u32 Timeout;
+	__u16 Reserved2;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u8 SetupCount;
+	__u8 Reserved3;
+	__u16 SubCommand;	/* one setup word */
+	__u16 ByteCount;
+	__u8 Pad;
+	__u16 Pad1;
+    __u16 Fid;
+	__u16 InformationLevel;
+	__u16 Reserved4;	
+};
+
+struct smb_com_transaction2_sfi_rsp {
+	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 Reserved;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 ParameterDisplacement;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u16 DataDisplacement;
+	__u8 SetupCount;
+	__u8 Reserved1;		/* should be zero setup words following */
+	__u16 ByteCount;
+	__u16 Reserved2;	/* parameter word reserved - present for infolevels > 100 */
+};
+
+
+/*
+ * Flags on T2 FINDFIRST and FINDNEXT 
+ */
+#define CIFS_SEARCH_CLOSE_ALWAYS  0x0001
+#define CIFS_SEARCH_CLOSE_AT_END  0x0002
+#define CIFS_SEARCH_RETURN_RESUME 0x0004
+#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008
+#define CIFS_SEARCH_BACKUP_SEARCH 0x0010
+
+/*
+ * Size of the resume key on FINDFIRST and FINDNEXT calls
+ */
+#define CIFS_SMB_RESUME_KEY_SIZE 4
+
+typedef struct smb_com_transaction2_ffirst_req {
+	struct smb_hdr hdr;	/* wct = 15 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 MaxParameterCount;
+	__u16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__u32 Timeout;
+	__u16 Reserved2;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u8 SetupCount;	/* one */
+	__u8 Reserved3;
+	__u16 SubCommand;	/* TRANS2_FIND_FIRST */
+	__u16 ByteCount;
+	__u8 Pad;
+	__u16 SearchAttributes;
+	__u16 SearchCount;
+	__u16 SearchFlags;
+	__u16 InformationLevel;
+	__u32 SearchStorageType;
+	char FileName[1];
+} TRANSACTION2_FFIRST_REQ;
+
+typedef struct smb_com_transaction2_ffirst_rsp {
+	struct smb_hdr hdr;	/* wct = 10 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 Reserved;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 ParameterDisplacement;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u16 DataDisplacement;
+	__u8 SetupCount;
+	__u8 Reserved1;		/* should be zero setup words following */
+	__u16 ByteCount;
+} TRANSACTION2_FFIRST_RSP;
+
+typedef struct smb_com_transaction2_ffirst_rsp_parms {
+	__u16 SearchHandle;
+	__u16 SearchCount;
+	__u16 EndofSearch;
+	__u16 EAErrorOffset;
+	__u16 LastNameOffset;
+} T2_FFIRST_RSP_PARMS;
+
+typedef struct smb_com_transaction2_fnext_req {
+	struct smb_hdr hdr;	/* wct = 15 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 MaxParameterCount;
+	__u16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__u32 Timeout;
+	__u16 Reserved2;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u8 SetupCount;	/* one */
+	__u8 Reserved3;
+	__u16 SubCommand;	/* TRANS2_FIND_NEXT */
+	__u16 ByteCount;
+	__u8 Pad;
+	__u16 SearchHandle;
+	__u16 SearchCount;
+	__u16 InformationLevel;
+	__u32 ResumeKey;
+	__u16 SearchFlags;
+	char ResumeFileName[1];	/* will be null string actually since we set bit 3 - resume from previous ending place */
+} TRANSACTION2_FNEXT_REQ;
+
+typedef struct smb_com_transaction2_fnext_rsp {
+	struct smb_hdr hdr;	/* wct = 10 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 Reserved;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 ParameterDisplacement;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u16 DataDisplacement;
+	__u8 SetupCount;
+	__u8 Reserved1;		/* should be zero setup words following */
+	__u16 ByteCount;
+} TRANSACTION2_FNEXT_RSP;
+
+typedef struct smb_com_transaction2_fnext_rsp_parms {
+	__u16 SearchCount;
+	__u16 EndofSearch;
+	__u16 EAErrorOffset;
+	__u16 LastNameOffset;
+} T2_FNEXT_RSP_PARMS;
+
+#define SMB_INFO_ALLOCATION         1
+#define SMB_INFO_VOLUME             2
+#define SMB_QUERY_FS_VOLUME_INFO    0x102
+#define SMB_QUERY_FS_SIZE_INFO      0x103
+#define SMB_QUERY_FS_DEVICE_INFO    0x104
+#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
+#define SMB_QUERY_CIFS_UNIX_INFO    0x200
+
+typedef struct smb_com_transaction2_qfsi_req {
+	struct smb_hdr hdr;	/* wct = 14+ */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 MaxParameterCount;
+	__u16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__u32 Timeout;
+	__u16 Reserved2;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u8 SetupCount;
+	__u8 Reserved3;
+	__u16 SubCommand;	/* one setup word */
+	__u16 ByteCount;
+	__u8 Pad;
+	__u16 InformationLevel;
+} TRANSACTION2_QFSI_REQ;
+
+typedef struct smb_com_transaction_qfsi_rsp {
+	struct smb_hdr hdr;	/* wct = 10 + SetupCount */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 Reserved;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 ParameterDisplacement;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u16 DataDisplacement;
+	__u8 SetupCount;
+	__u8 Reserved1;		/* should be zero setup words following */
+	__u16 ByteCount;
+	__u8 Pad;		/* may be three bytes *//* followed by data area */
+} TRANSACTION2_QFSI_RSP;
+
+typedef struct smb_com_transaction2_get_dfs_refer_req {
+	struct smb_hdr hdr;	/* wct = 15 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 MaxParameterCount;
+	__u16 MaxDataCount;
+	__u8 MaxSetupCount;
+	__u8 Reserved;
+	__u16 Flags;
+	__u32 Timeout;
+	__u16 Reserved2;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u8 SetupCount;
+	__u8 Reserved3;
+	__u16 SubCommand;	/* one setup word */
+	__u16 ByteCount;
+	__u8 Pad[3];		/* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesnt seem to matter though */
+	__u16 MaxReferralLevel;
+	char RequestFileName[1];
+} TRANSACTION2_GET_DFS_REFER_REQ;
+
+typedef struct dfs_referral_level_3 {
+	__u16 VersionNumber;
+	__u16 ReferralSize;
+	__u16 ServerType;	/* 0x0001 = CIFS server */
+	__u16 ReferralFlags;	/* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
+	__u16 TimeToLive;
+	__u16 DfsPathOffset;
+	__u16 DfsAlternatePathOffset;
+	__u16 NetworkAddressOffset;
+} REFERRAL3;
+
+typedef struct smb_com_transaction_get_dfs_refer_rsp {
+	struct smb_hdr hdr;	/* wct = 10 */
+	__u16 TotalParameterCount;
+	__u16 TotalDataCount;
+	__u16 Reserved;
+	__u16 ParameterCount;
+	__u16 ParameterOffset;
+	__u16 ParameterDisplacement;
+	__u16 DataCount;
+	__u16 DataOffset;
+	__u16 DataDisplacement;
+	__u8 SetupCount;
+	__u8 Reserved1;		/* zero setup words following */
+	__u16 ByteCount;
+	__u8 Pad;
+	__u16 PathConsumed;
+	__u16 NumberOfReferrals;
+	__u16 DFSFlags;
+	__u16 Pad2;
+	REFERRAL3 referrals[1];	/* array of level 3 dfs_referral structures */
+	/* followed by the strings pointed to by the referral structures */
+} TRANSACTION2_GET_DFS_REFER_RSP;
+
+/* DFS Flags */
+#define DFSREF_REFERRAL_SERVER  0x0001
+#define DFSREF_STORAGE_SERVER   0x0002
+
+/* IOCTL information */
+/* List of ioctl function codes that look to be of interest to remote clients like this. */
+/* Need to do some experimentation to make sure they all work remotely.                  */
+/* Some of the following such as the encryption/compression ones would be                */
+/* invoked from tools via a specialized hook into the VFS rather than via the            */
+/* standard vfs entry points */
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
+#define FSCTL_REQUEST_BATCH_OPLOCK   0x00090008
+#define FSCTL_LOCK_VOLUME            0x00090018
+#define FSCTL_UNLOCK_VOLUME          0x0009001C
+#define FSCTL_GET_COMPRESSION        0x0009003C
+#define FSCTL_SET_COMPRESSION        0x0009C040
+#define FSCTL_REQUEST_FILTER_OPLOCK  0x0009008C
+#define FSCTL_FILESYS_GET_STATISTICS 0x00090090
+#define FSCTL_SET_REPARSE_POINT      0x000900A4
+#define FSCTL_GET_REPARSE_POINT      0x000900A8
+#define FSCTL_DELETE_REPARSE_POINT   0x000900AC
+#define FSCTL_SET_SPARSE             0x000900C4
+#define FSCTL_SET_ZERO_DATA          0x000900C8
+#define FSCTL_SET_ENCRYPTION         0x000900D7
+#define FSCTL_ENCRYPTION_FSCTL_IO    0x000900DB
+#define FSCTL_WRITE_RAW_ENCRYPTED    0x000900DF
+#define FSCTL_READ_RAW_ENCRYPTED     0x000900E3
+#define FSCTL_SIS_COPYFILE           0x00090100
+#define FSCTL_SIS_LINK_FILES         0x0009C104
+
+#define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
+#define IO_REPARSE_TAG_HSM           0xC0000004
+#define IO_REPARSE_TAG_SIS           0x80000007
+
+/*
+ ************************************************************************
+ * All structs for everything above the SMB PDUs themselves
+ * (such as the T2 level specific data) go here                  
+ ************************************************************************
+ */
+
+/*
+ * Information on a server
+ */
+
+struct serverInfo {
+	char name[16];
+	unsigned char versionMajor;
+	unsigned char versionMinor;
+	unsigned long type;
+	unsigned int commentOffset;
+};
+
+/*
+ * The following structure is the format of the data returned on a NetShareEnum
+ * with level "90" (x5A)
+ */
+
+struct shareInfo {
+	char shareName[13];
+	char pad;
+	unsigned short type;
+	unsigned int commentOffset;
+};
+
+struct aliasInfo {
+	char aliasName[9];
+	char pad;
+	unsigned int commentOffset;
+	unsigned char type[2];
+};
+
+struct aliasInfo92 {
+	int aliasNameOffset;
+	int serverNameOffset;
+	int shareNameOffset;
+};
+
+typedef struct {
+	__u64 TotalAllocationUnits;
+	__u64 FreeAllocationUnits;
+	__u32 SectorsPerAllocationUnit;
+	__u32 BytesPerSector;
+} FILE_SYSTEM_INFO;		/* size info, level 0x103 */
+
+typedef struct {
+	__u16 MajorVersionNumber;
+	__u16 MinorVersionNumber;
+	__u64 Capability;
+} FILE_SYSTEM_UNIX_INFO;	/* Unix extensions info, level 0x200 */
+
+/* DeviceType Flags */
+#define FILE_DEVICE_CD_ROM              0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM  0x00000003
+#define FILE_DEVICE_DFS                 0x00000006
+#define FILE_DEVICE_DISK                0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM    0x00000008
+#define FILE_DEVICE_FILE_SYSTEM         0x00000009
+#define FILE_DEVICE_NAMED_PIPE          0x00000011
+#define FILE_DEVICE_NETWORK             0x00000012
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL                0x00000015
+#define FILE_DEVICE_PARALLEL_PORT       0x00000016
+#define FILE_DEVICE_PRINTER             0x00000018
+#define FILE_DEVICE_SERIAL_PORT         0x0000001b
+#define FILE_DEVICE_STREAMS             0x0000001e
+#define FILE_DEVICE_TAPE                0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM    0x00000020
+#define FILE_DEVICE_VIRTUAL_DISK        0x00000024
+#define FILE_DEVICE_NETWORK_REDIRECTOR  0x00000028
+
+typedef struct {
+	__u32 DeviceType;
+	__u32 DeviceCharacteristics;
+} FILE_SYSTEM_DEVICE_INFO;	/* device info, level 0x104 */
+
+typedef struct {
+	__u32 Attributes;
+	__u32 MaxPathNameComponentLength;
+	__u32 FileSystemNameLen;
+	char FileSystemName[52];	/* do not really need to save this - so potentially get only subset of name */
+} FILE_SYSTEM_ATTRIBUTE_INFO;
+
+typedef struct {		/* data block encoding of response to level 263 QPathInfo */
+	__u64 CreationTime;
+	__u64 LastAccessTime;
+	__u64 LastWriteTime;
+	__u64 ChangeTime;
+	__u32 Attributes;
+	__u32 Pad1;
+	__u64 AllocationSize;
+	__u64 EndOfFile;	/* size ie offset to first free byte in file */
+	__u32 NumberOfLinks;	/* hard links */
+	__u8 DeletePending;
+	__u8 Directory;
+	__u16 Pad2;
+	__u64 IndexNumber;
+	__u32 EASize;
+	__u32 AccessFlags;
+	__u64 IndexNumber1;
+	__u64 CurrentByteOffset;
+	__u32 Mode;
+	__u32 AlignmentRequirement;
+	__u32 FileNameLength;
+	char FileName[1];
+} FILE_ALL_INFO;		/* level 263 QPathInfo */
+
+typedef struct {
+	__u64 EndOfFile;
+	__u64 NumOfBytes;
+	__u64 LastStatusChange;	/*SNIA spec says DCE time for the three time fields */
+	__u64 LastAccessTime;
+	__u64 LastModificationTime;
+	__u64 Uid;
+	__u64 Gid;
+	__u32 Type;
+	__u64 DevMajor;
+	__u64 DevMinor;
+	__u64 UniqueId;
+	__u64 Permissions;
+	__u64 Nlinks;
+} FILE_UNIX_BASIC_INFO;		/* level 512 QPathInfo */
+
+typedef struct {
+	char LinkDest[1];
+} FILE_UNIX_LINK_INFO;		/* level 513 QPathInfo */
+
+/* defines for enumerating possible values of the Unix type field below */
+#define UNIX_FILE      0
+#define UNIX_DIR       1
+#define UNIX_SYMLINK   2
+#define UNIX_CHARDEV   3
+#define UNIX_BLOCKDEV  4
+#define UNIX_FIFO      5
+#define UNIX_SOCKET    6
+
+typedef struct {
+	__u32 NextEntryOffset;
+	__u32 ResumeKey;
+	__u64 EndOfFile;
+	__u64 NumOfBytes;
+	__u64 LastStatusChange;	/*SNIA spec says DCE time for the three time fields */
+	__u64 LastAccessTime;
+	__u64 LastModificationTime;
+	__u64 Uid;
+	__u64 Gid;
+	__u32 Type;
+	__u64 DevMajor;
+	__u64 DevMinor;
+	__u64 UniqueId;
+	__u64 Permissions;
+	__u64 Nlinks;
+	char FileName[1];
+} FILE_UNIX_INFO;
+
+typedef struct {
+	__u64 CreationTime;
+	__u64 LastAccessTime;
+	__u64 LastWriteTime;
+	__u64 ChangeTime;
+	__u32 Attributes;
+	__u32 Pad;
+} FILE_BASIC_INFO;		/* size info, level 0x101 */
+
+struct file_allocation_info {
+	__u64 AllocationSize;
+};		/* size info, level 0x103 */
+
+struct file_end_of_file_info {
+	__u64 FileSize;		/* offset to end of file */
+};	/* size info, level 0x104 */
+
+typedef struct {
+	__u32 NextEntryOffset;
+	__u32 FileIndex;
+	__u64 CreationTime;
+	__u64 LastAccessTime;
+	__u64 LastWriteTime;
+	__u64 ChangeTime;
+	__u64 EndOfFile;
+	__u64 AllocationSize;
+	__u32 ExtFileAttributes;
+	__u32 FileNameLength;
+	char FileName[1];
+} FILE_DIRECTORY_INFO;		/* level 257 FF response data area */
+
+struct gea {
+	unsigned char cbName;
+	char szName[1];
+};
+
+struct gealist {
+	unsigned long cbList;
+	struct gea list[1];
+};
+
+struct fea {
+	unsigned char fEA;
+	unsigned char cbName;
+	unsigned short cbValue;
+	char szName[1];
+};
+/* flags for _FEA.fEA */
+#define FEA_NEEDEA         0x80	/* need EA bit */
+
+struct fealist {
+	unsigned long cbList;
+	struct fea list[1];
+};
+
+/* used to hold an arbitrary blob of data */
+struct data_blob {
+	__u8 *data;
+	size_t length;
+	void (*free) (struct data_blob * data_blob);
+};
+
+#pragma pack()			/* resume default structure packing */
+
+#endif				/* _CIFSPDU_H */
diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifsproto.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,251 @@
+/*
+ *   fs/cifs/cifsproto.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+#ifndef _CIFSPROTO_H
+#define _CIFSPROTO_H
+#include <linux/nls.h>
+
+/*
+ *****************************************************************
+ * All Prototypes
+ *****************************************************************
+ */
+
+extern struct smb_hdr *buf_get(void);
+extern void buf_release(void *);
+extern int smb_send(struct socket *, struct smb_hdr *,
+		    unsigned int /* length */ , struct sockaddr *);
+extern unsigned int _GetXid(void);
+extern void _FreeXid(unsigned int);
+#define GetXid() (int)_GetXid(); cFYI(1,("\nCIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
+#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("\nCIFS VFS: leaving %s (xid = %d) rc = %d\n",__FUNCTION__,curr_xid,rc));}
+extern char *build_path_from_dentry(struct dentry *);
+extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
+extern void renew_parental_timestamps(struct dentry *direntry);
+extern void *kcalloc(size_t mem, int type);
+extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
+		       struct smb_hdr * /* input */ ,
+		       struct smb_hdr * /* out */ ,
+		       int * /* bytes returned */ , const int long_op);
+extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
+extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
+extern int is_valid_oplock_break(struct smb_hdr *smb);
+extern int smbCalcSize(struct smb_hdr *ptr);
+extern int decode_negTokenInit(unsigned char *security_blob, int length,
+			       enum securityEnum *secType);
+extern int map_smb_to_linux_error(struct smb_hdr *smb);
+extern void header_assemble(struct smb_hdr *, char /* command */ ,
+			    const struct cifsTconInfo *, int
+			    /* length of fixed section (word count) in two byte units  */
+    );
+extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
+extern u64 cifs_UnixTimeToNT(time_t);
+extern void RevUcode_to_Ucode(char *revUnicode, char *UnicodeName);
+extern void Ucode_to_RevUcode(char *Unicode, char *revUnicodeName);
+extern void RevUcode_to_Ucode_with_Len(char *revUnicode, char *UnicodeName,
+				       int Len);
+extern void Ucode_to_RevUcode_with_Len(char *Unicode, char *revUnicodeName,
+				       int Len);
+extern int cifs_get_inode_info(struct inode **pinode,
+			       const unsigned char *search_path,
+			       struct super_block *sb);
+extern int cifs_get_inode_info_unix(struct inode **pinode,
+				    const unsigned char *search_path,
+				    struct super_block *sb);
+
+extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses,
+			    char cryptokey[CIFS_CRYPTO_KEY_SIZE]);
+extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
+			 char *user, char *domain,
+			 char *session_key, char *ntlm_session_key,
+			 const struct nls_table *);
+extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
+			       char *user, char *domain,
+			       char *SecurityBlob,
+			       int SecurityBlobLength,
+			       const struct nls_table *);
+extern int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
+					 struct cifsSesInfo *ses,
+					 char *domain,
+					 char *ntlm_session_key,
+                     int  *ntlmv2_flag,
+					 const struct nls_table *);
+extern int CIFSNTLMSSPAuthSessSetup(unsigned int xid,
+				    struct cifsSesInfo *ses, char *user,
+				    char *domain, char *ntlm_session_key,
+				    char *lanman_session_key,
+                    int ntlmv2_flag,
+				    const struct nls_table *);
+
+extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
+		    const char *tree, struct cifsTconInfo *tcon,
+		    const struct nls_table *);
+
+extern int CIFSFindFirst(const int xid, const struct cifsTconInfo *tcon,
+			 const char *searchName,
+			 FILE_DIRECTORY_INFO * findData,
+			 T2_FFIRST_RSP_PARMS * findParms,
+			 const struct nls_table *nls_codepage,
+			 int *pUnicodeFlag,
+			 int *pUnixFlag /* if Unix extensions used */ );
+extern int CIFSFindNext(const int xid, const struct cifsTconInfo *tcon,
+			FILE_DIRECTORY_INFO * findData,
+			T2_FNEXT_RSP_PARMS * findParms,
+			const __u16 searchHandle, const __u32 resumeKey,
+			int *UnicodeFlag, int *pUnixFlag);
+
+extern int CIFSSMBQPathInfo(const int xid, const struct cifsTconInfo *tcon,
+			    const unsigned char *searchName,
+			    FILE_ALL_INFO * findData,
+			    const struct nls_table *nls_codepage);
+
+extern int CIFSSMBUnixQPathInfo(const int xid,
+				const struct cifsTconInfo *tcon,
+				const unsigned char *searchName,
+				FILE_UNIX_BASIC_INFO * pFindData,
+				const struct nls_table *nls_codepage);
+
+extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
+			   const unsigned char *searchName,
+			   unsigned char **targetUNCs,
+			   int *number_of_UNC_in_array,
+			   const struct nls_table *nls_codepage);
+
+extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+			       const char *old_path,
+			       const struct nls_table *nls_codepage);
+
+extern int CIFSSMBQFSInfo(const int xid, const struct cifsTconInfo *tcon,
+			  struct statfs *FSData,
+			  const struct nls_table *nls_codepage);
+extern int CIFSSMBQFSAttributeInfo(const int xid,
+				   struct cifsTconInfo *tcon,
+				   const struct nls_table *nls_codepage);
+extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
+				const struct nls_table *nls_codepage);
+extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+			      const struct nls_table *nls_codepage);
+
+extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
+			   char *fileName, FILE_BASIC_INFO * data,
+			   const struct nls_table *nls_codepage);
+extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
+			 char *fileName, __u64 size,int setAllocationSizeFlag,
+			 const struct nls_table *nls_codepage);
+extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
+			 __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag);
+extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
+			       char *full_path, __u64 mode, __u64 uid,
+			       __u64 gid, const struct nls_table *nls_codepage);
+
+extern int CIFSSMBMkDir(const int xid, const struct cifsTconInfo *tcon,
+			const char *newName,
+			const struct nls_table *nls_codepage);
+extern int CIFSSMBRmDir(const int xid, const struct cifsTconInfo *tcon,
+			const char *name, const struct nls_table *nls_codepage);
+
+extern int CIFSSMBDelFile(const int xid, const struct cifsTconInfo *tcon,
+			  const char *name,
+			  const struct nls_table *nls_codepage);
+extern int CIFSSMBRename(const int xid, const struct cifsTconInfo *tcon,
+			 const char *fromName, const char *toName,
+			 const struct nls_table *nls_codepage);
+extern int CIFSCreateHardLink(const int xid,
+			      const struct cifsTconInfo *tcon,
+			      const char *fromName, const char *toName,
+			      const struct nls_table *nls_codepage);
+extern int CIFSUnixCreateHardLink(const int xid,
+				  const struct cifsTconInfo *tcon,
+				  const char *fromName, const char *toName,
+				  const struct nls_table *nls_codepage);
+extern int CIFSUnixCreateSymLink(const int xid,
+				 const struct cifsTconInfo *tcon,
+				 const char *fromName, const char *toName,
+				 const struct nls_table *nls_codepage);
+extern int CIFSSMBUnixQuerySymLink(const int xid,
+				   const struct cifsTconInfo *tcon,
+				   const unsigned char *searchName,
+				   char *syminfo, const int buflen,
+				   const struct nls_table *nls_codepage);
+
+extern int CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon,
+		       const char *fileName, const int disposition,
+		       const int access_flags, const int omode,
+		       __u16 * netfid, int *pOplock,
+		       const struct nls_table *nls_codepage);
+extern int CIFSSMBClose(const int xid, const struct cifsTconInfo *tcon,
+			const int smb_file_id);
+
+extern int CIFSSMBRead(const int xid, const struct cifsTconInfo *tcon,
+		       const int netfid, unsigned int count,
+		       const __u64 lseek, unsigned int *nbytes, char *buf);
+extern int CIFSSMBWrite(const int xid, const struct cifsTconInfo *tcon,
+			const int netfid, const unsigned int count,
+			const __u64 lseek, unsigned int *nbytes,
+			const char *buf, const int long_op);
+extern int CIFSSMBLock(const int xid, const struct cifsTconInfo *tcon,
+		       const __u16 netfid, const __u64 len,
+		       const __u64 offset, const __u32 numUnlock,
+		       const __u32 numLock, const __u8 lockType,
+		       const int waitFlag);
+
+extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
+
+extern struct cifsSesInfo *sesInfoAlloc(void);
+extern void sesInfoFree(struct cifsSesInfo *);
+extern struct cifsTconInfo *tconInfoAlloc(void);
+extern void tconInfoFree(struct cifsTconInfo *);
+
+extern int cifs_demultiplex_thread(struct TCP_Server_Info *);
+extern int cifs_reconnect(struct TCP_Server_Info *server);
+
+/* BB routines below not implemented yet BB */
+
+extern int CIFSBuildServerList(int xid, char *serverBufferList,
+			       int recordlength, int *entries,
+			       int *totalEntries, int *topoChangedFlag);
+extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon,
+			      struct shareInfo *shareList, int bufferLen,
+			      int *entries, int *totalEntries);
+extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon,
+			     struct aliasInfo *aliasList, int bufferLen,
+			     int *entries, int *totalEntries);
+extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon,
+			    char *aliasName, char *serverName,
+			    char *shareName, char *comment);
+extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon,
+			       char *share, char *comment);
+extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon,
+			       char *userName, char *searchName, int *perms);
+extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid);
+
+extern int CIFSSMBSeek(int xid,
+		       struct cifsTconInfo *tcon,
+		       int netfid,
+		       int pid,
+		       int whence, unsigned long offset, long long *newoffset);
+
+extern int CIFSSMBCopy(int xid,
+		       struct cifsTconInfo *ftcon,
+		       char *fromName,
+		       struct cifsTconInfo *ttcon,
+		       char *toName, int ofun, int flags);
+#endif				/* _CIFSPROTO_H */
diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/cifssmb.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,2155 @@
+/*
+ *   fs/cifs/cifssmb.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   Contains the routines for constructing the SMB PDUs themselves
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ /* All SMB/CIFS PDU handling routines go here - except for a few leftovers in connect.c */
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <asm/uaccess.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+
+static struct {
+	int index;
+	char *name;
+} protocols[] = {
+	{
+	CIFS_PROT, "\2NT LM 0.12"}, {
+	BAD_PROT, "\2"}
+};
+
+int
+smb_init(int smb_command, int wct, const struct cifsTconInfo *tcon,
+	 void **request_buf /* returned */ ,
+	 void **response_buf /* returned */ )
+{
+	int rc = 0;
+
+	*request_buf = buf_get();
+	if (request_buf == 0) {
+		return -ENOMEM;
+	}
+    /* Although the original thought was we needed the response buf for  */
+    /* potential retries of smb operations it turns out we can determine */
+    /* from the mid flags when the request buffer can be resent without  */
+    /* having to use a second distinct buffer for the response */
+	*response_buf = *request_buf; 
+
+	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
+			wct /*wct */ );
+	return rc;
+}
+
+int
+CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses,
+		 char cryptokey[CIFS_CRYPTO_KEY_SIZE])
+{
+	NEGOTIATE_REQ *pSMB;
+	NEGOTIATE_RSP *pSMBr;
+	int rc = 0;
+	int bytes_returned;
+
+	rc = smb_init(SMB_COM_NEGOTIATE, 0, 0 /* no tcon yet */ ,
+		      (void **) &pSMB, (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
+	if (extended_security)
+		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
+    if (sign_CIFS_PDUs) {
+        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+    }
+
+	pSMB->ByteCount = strlen(protocols[0].name) + 1;
+	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	/* null guaranteed to be at end of source and target buffers anyway */
+
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc == 0) {
+		ses->dialectIndex = le16_to_cpu(pSMBr->DialectIndex);
+		ses->secMode = pSMBr->SecurityMode;	/* one byte - no need to convert this or EncryptionKeyLen field from le,  */
+		ses->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
+		/* probably no need to store and check maxvcs */
+		ses->maxBuf =
+		    min(le32_to_cpu(pSMBr->MaxBufferSize),
+			(__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE);
+		ses->maxRw = le32_to_cpu(pSMBr->MaxRawSize);	/* BB le_to_host needed around here and ff */
+		cFYI(1, ("\nMax buf = %d ", ses->maxBuf));
+		GETU32(ses->sessid) = le32_to_cpu(pSMBr->SessionKey);
+		ses->capabilities = le32_to_cpu(pSMBr->Capabilities);
+		ses->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);	/* BB with UTC do we ever need to be using srvr timezone? */
+		if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+			memcpy(cryptokey, pSMBr->u.EncryptionKey,
+			       CIFS_CRYPTO_KEY_SIZE);
+		} else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
+			   && (pSMBr->EncryptionKeyLength == 0)) {
+			/* decode security blob */
+		} else
+			rc = -EIO;
+
+		/* BB might be helpful to save off the domain of server here */
+
+		if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) {
+			if (pSMBr->ByteCount < 16)
+				rc = -EIO;
+			else if (pSMBr->ByteCount == 16) {
+				ses->secType = RawNTLMSSP;
+				if (ses->server->socketUseCount.counter > 1) {
+					if (memcmp
+					    (ses->server->server_GUID,
+					     pSMBr->u.extended_response.
+					     GUID, 16) != 0) {
+						cFYI(1,
+						     ("UID of server does not match that of previous connection to same ip address"));
+						memcpy(ses->server->
+						       server_GUID,
+						       pSMBr->u.
+						       extended_response.
+						       GUID, 16);
+					}
+				} else
+					memcpy(ses->server->server_GUID,
+					       pSMBr->u.extended_response.
+					       GUID, 16);
+			} else {
+				rc = decode_negTokenInit(pSMBr->u.
+							 extended_response.
+							 SecurityBlob,
+							 pSMBr->ByteCount -
+							 16, &ses->secType);
+			}
+
+		} else
+			ses->capabilities &= ~CAP_EXTENDED_SECURITY;
+        if(sign_CIFS_PDUs == FALSE) {        
+            if(ses->secMode & SECMODE_SIGN_REQUIRED)
+                cERROR(1,("\nServer required CIFS packet signing - enable /proc/fs/cifs/PacketSigningEnabled"));
+            ses->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+        }
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
+{
+	struct smb_hdr *smb_buffer;
+	struct smb_hdr *smb_buffer_response;
+	int rc = 0;
+	int length;
+
+	cFYI(1, ("\nIn tree disconnect"));
+	/*
+	 *  If last user of the connection and
+	 *  connection alive - disconnect it
+	 *  If this is the last connection on the server session disconnect it
+	 *  (and inside session disconnect we should check if tcp socket needs to 
+	 *  be freed and kernel thread woken up).
+	 */
+	if (tcon)
+		down(&tcon->tconSem);
+	else
+		return -EIO;
+
+	atomic_dec(&tcon->useCount);
+	if (atomic_read(&tcon->useCount) > 0) {
+		up(&tcon->tconSem);
+		return -EBUSY;
+	}
+
+/* BB remove (from server) list of shares - but with smp safety  BB */
+/* BB is ses active - do we need to check here - but how? BB */
+
+	rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
+		      (void **) &smb_buffer, (void **) &smb_buffer_response);
+	if (rc) {
+		up(&tcon->tconSem);
+		return rc;
+	}
+	rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
+			 &length, 0);
+	if (rc)
+		cFYI(1, (" Tree disconnect failed %d", rc));
+
+	if (smb_buffer)
+		buf_release(smb_buffer);
+	up(&tcon->tconSem);
+	return rc;
+}
+
+int
+CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
+{
+	struct smb_hdr *smb_buffer_response;
+	LOGOFF_ANDX_REQ *pSMB;
+	int rc = 0;
+	int length;
+
+	cFYI(1, ("\nIn SMBLogoff for session disconnect"));
+
+	if (ses)
+		down(&ses->sesSem);	/* need to add more places where this sem is checked */
+	else
+		return -EIO;
+
+	atomic_dec(&ses->inUse);
+	if (atomic_read(&ses->inUse) > 0) {
+		up(&ses->sesSem);
+		return -EBUSY;
+	}
+    if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+	rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */ ,
+		      (void **) &pSMB, (void **) &smb_buffer_response);
+	if (rc) {
+		up(&ses->sesSem);
+		return rc;
+	}
+
+	pSMB->hdr.Uid = ses->Suid;
+
+	pSMB->AndXCommand = 0xFF;
+	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+			 smb_buffer_response, &length, 0);
+	if (ses->server) {
+		atomic_dec(&ses->server->socketUseCount);
+		if (atomic_read(&ses->server->socketUseCount) == 0)
+			ses->server->tcpStatus = CifsExiting;
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	up(&ses->sesSem);
+	return rc;
+}
+
+int
+CIFSSMBDelFile(const int xid, const struct cifsTconInfo *tcon,
+	       const char *fileName, const struct nls_table *nls_codepage)
+{
+	DELETE_FILE_REQ *pSMB = NULL;
+	DELETE_FILE_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(fileName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
+	pSMB->ByteCount = name_len + 1;
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in RMFile = %d\n", rc));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBRmDir(const int xid, const struct cifsTconInfo *tcon,
+	     const char *dirName, const struct nls_table *nls_codepage)
+{
+	DELETE_DIRECTORY_REQ *pSMB = NULL;
+	DELETE_DIRECTORY_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("\nIn CIFSSMBRmDir"));
+
+	rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530
+					 /* find define for this maxpathcomponent */
+					 , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(dirName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->DirName, dirName, name_len);
+	}
+
+	pSMB->ByteCount = name_len + 1;
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in RMDir = %d\n", rc));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBMkDir(const int xid, const struct cifsTconInfo *tcon,
+	     const char *name, const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	CREATE_DIRECTORY_REQ *pSMB = NULL;
+	CREATE_DIRECTORY_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("\nIn CIFSSMBMkDir"));
+
+	rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530
+					 /* find define for this maxpathcomponent */
+					 , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(name, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->DirName, name, name_len);
+	}
+
+	pSMB->ByteCount = name_len + 1 /* for buf format */ ;
+	pSMB->BufferFormat = 0x04;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in RMDir = %d\n", rc));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon,
+	    const char *fileName, const int openDisposition,
+	    const int access_flags, const int omode, __u16 * netfid,
+	    int *pOplock, const struct nls_table *nls_codepage)
+{
+	int rc = -EACCES;
+	OPEN_REQ *pSMB = NULL;
+	OPEN_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len;
+
+	rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->AndXCommand = 0xFF;	/* none */
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		pSMB->ByteCount = 1;	/* account for one byte pad to word boundary */
+		name_len =
+		    cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
+				  fileName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+		pSMB->NameLength = cpu_to_le16(name_len);
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		pSMB->ByteCount = 0;	/* no pad */
+		name_len = strnlen(fileName, 530);
+		name_len++;	/* trailing null */
+		pSMB->NameLength = cpu_to_le16(name_len);
+		strncpy(pSMB->fileName, fileName, name_len);
+	}
+	if (*pOplock)
+		pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
+	pSMB->DesiredAccess = cpu_to_le32(access_flags);
+	pSMB->AllocationSize = 0;
+	pSMB->FileAttributes = ATTR_NORMAL;	/* XP does not handle ATTR_POSIX_SEMANTICS */
+	/*if ((omode & S_IWUGO) == 0)
+		pSMB->FileAttributes |= ATTR_READONLY;*/	
+    /*  Above line causes problems due to problem with vfs splitting create into
+        two pieces - need to set mode after file created not while it is being created */
+	pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes);
+	pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
+	pSMB->CreateDisposition = cpu_to_le32(openDisposition);
+	pSMB->CreateOptions = cpu_to_le32(CREATE_NOT_DIR);	/* BB what are these? BB */
+	pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);	/* BB ?? BB */
+	pSMB->SecurityFlags =
+	    cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY);
+
+	pSMB->ByteCount += name_len;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in Open = %d\n", rc));
+	} else {
+		*pOplock = pSMBr->OplockLevel;	/* one byte no need to le_to_cpu */
+		*netfid = pSMBr->Fid;	/* cifs fid stays in le */
+		/* Do we care about the CreateAction in any cases? */
+
+		/* BB add code to update inode with file sizes from create response */
+	}
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSSMBRead(const int xid, const struct cifsTconInfo *tcon,
+	    const int netfid, const unsigned int count,
+	    const __u64 lseek, unsigned int *nbytes, char *buf)
+{
+	int rc = -EACCES;
+	READ_REQ *pSMB = NULL;
+	READ_RSP *pSMBr = NULL;
+	char *pReadData;
+	int bytes_returned;
+
+	rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->AndXCommand = 0xFF;	/* none */
+	pSMB->Fid = netfid;
+	pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
+	pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+	pSMB->Remaining = 0;
+	pSMB->MaxCount = cpu_to_le16(min(count,
+					 (tcon->ses->maxBuf -
+					  MAX_CIFS_HDR_SIZE) & 0xFFFFFF00));
+	pSMB->MaxCountHigh = 0;
+	pSMB->ByteCount = 0;	/* no need to do le conversion since it is 0 */
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in read = %d\n", rc));
+		*nbytes = 0;
+	} else {
+		pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength);
+		*nbytes = pSMBr->DataLength;
+		/* BB check that DataLength would not go beyond end of SMB BB */
+/* if(pSMBr->DataOffset < pSMBr->ByteCount + sizeof(READ_RSP) - 1 *//* BB fix this length check */
+		if (pSMBr->DataLength > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
+			rc = -EIO;
+			*nbytes = 0;
+		} else {
+			pReadData =
+			    (char *) (&pSMBr->hdr.Protocol) +
+			    le16_to_cpu(pSMBr->DataOffset);
+			copy_to_user(buf, pReadData, pSMBr->DataLength);
+		}
+	}
+
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSSMBWrite(const int xid, const struct cifsTconInfo *tcon,
+	     const int netfid, const unsigned int count,
+	     const __u64 offset, unsigned int *nbytes, const char *buf,
+	     const int long_op)
+{
+	int rc = -EACCES;
+	WRITE_REQ *pSMB = NULL;
+	WRITE_RSP *pSMBr = NULL;
+	int bytes_returned;
+
+	rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->AndXCommand = 0xFF;	/* none */
+	pSMB->Fid = netfid;
+	pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
+	pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+	pSMB->Remaining = 0;
+	if (count > ((tcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00))
+		pSMB->DataLengthLow =
+		    (tcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00;
+	else
+		pSMB->DataLengthLow = count;
+	pSMB->DataLengthHigh = 0;
+	pSMB->DataOffset =
+	    cpu_to_le16((int) &(pSMB->Data) - (int) pSMB->hdr.Protocol);
+	copy_from_user(pSMB->Data, buf, pSMB->DataLengthLow);
+
+	pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
+	pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+	if (rc) {
+		cERROR(1, ("\nSend error in write = %d\n", rc));
+		*nbytes = 0;
+	} else
+		*nbytes = le16_to_cpu(pSMBr->Count);
+
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSSMBLock(const int xid, const struct cifsTconInfo *tcon,
+	    const __u16 smb_file_id, const __u64 len,
+	    const __u64 offset, const __u32 numUnlock,
+	    const __u32 numLock, const __u8 lockType, const int waitFlag)
+{
+	int rc = 0;
+	LOCK_REQ *pSMB = NULL;
+	LOCK_RSP *pSMBr = NULL;
+	int bytes_returned;
+
+	cFYI(1, ("\nIn CIFSSMBLock"));
+
+	rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->NumberOfLocks = cpu_to_le32(numLock);
+	pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock);
+	pSMB->LockType = lockType;
+	pSMB->AndXCommand = 0xFF;	/* none */
+	pSMB->Fid = smb_file_id; /* netfid stays le */
+
+	pSMB->Locks[0].Pid = cpu_to_le16(current->pid);
+	pSMB->Locks[0].Length = cpu_to_le64(len);
+	pSMB->Locks[0].Offset = cpu_to_le64(offset);
+	pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	if (rc) {
+		cERROR(1, ("\nSend error in Lock = %d\n", rc));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSSMBClose(const int xid, const struct cifsTconInfo *tcon, int smb_file_id)
+{
+	int rc = 0;
+	CLOSE_REQ *pSMB = NULL;
+	CLOSE_RSP *pSMBr = NULL;
+	int bytes_returned;
+	cFYI(1, ("\nIn CIFSSMBClose"));
+
+	rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->FileID = (__u16) smb_file_id;
+	pSMB->LastWriteTime = 0;
+	pSMB->ByteCount = 0;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in Close = %d\n", rc));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSSMBRename(const int xid, const struct cifsTconInfo *tcon,
+	      const char *fromName, const char *toName,
+	      const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	RENAME_REQ *pSMB = NULL;
+	RENAME_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len, name_len2;
+
+	cFYI(1, ("\nIn CIFSSMBRename"));
+
+	rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->BufferFormat = 0x04;
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+		pSMB->OldFileName[name_len] = 0;	/* pad */
+		pSMB->OldFileName[name_len + 1] = 0x04;	/* strange that protocol requires an ASCII signature byte on Unicode string */
+		name_len2 =
+		    cifs_strtoUCS((wchar_t *) & pSMB->
+				  OldFileName[name_len + 2], toName, 530,
+				  nls_codepage);
+		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
+		name_len2 *= 2;	/* convert to bytes */
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(fromName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->OldFileName, fromName, name_len);
+		name_len2 = strnlen(toName, 530);
+		name_len2++;	/* trailing null */
+		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
+		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		name_len2++;	/* trailing null */
+		name_len2++;	/* signature byte */
+	}
+
+	pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;	/* we could also set search attributes but not needed */
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSend error in RMDir = %d\n", rc));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSUnixCreateSymLink(const int xid, const struct cifsTconInfo *tcon,
+		      const char *fromName, const char *toName,
+		      const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	char *data_offset;
+	int name_len;
+	int name_len_target;
+	int rc = 0;
+	int bytes_returned = 0;
+
+	cFYI(1, ("\nIn Symlink Unix style"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(fromName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fromName, name_len);
+	}
+	pSMB->ParameterCount = 6 + name_len;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len_target =
+		    cifs_strtoUCS((wchar_t *) data_offset, toName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len_target++;	/* trailing null */
+		name_len_target *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len_target = strnlen(toName, 530);
+		name_len_target++;	/* trailing null */
+		strncpy(data_offset, toName, name_len_target);
+	}
+
+	pSMB->DataCount = name_len_target;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+	pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+	pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1,
+		     ("\nSend error in SetPathInfo (create symlink) = %d\n",
+		      rc));
+	}
+
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSUnixCreateHardLink(const int xid, const struct cifsTconInfo *tcon,
+		       const char *fromName, const char *toName,
+		       const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	char *data_offset;
+	int name_len;
+	int name_len_target;
+	int rc = 0;
+	int bytes_returned = 0;
+
+	cFYI(1, ("\nIn Create Hard link Unix style"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530
+					 /* find define for this maxpathcomponent */
+					 , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len = strnlen(toName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, toName, name_len);
+	}
+	pSMB->ParameterCount = 6 + name_len;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len_target =
+		    cifs_strtoUCS((wchar_t *) data_offset, fromName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len_target++;	/* trailing null */
+		name_len_target *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+		name_len_target = strnlen(fromName, 530);
+		name_len_target++;	/* trailing null */
+		strncpy(data_offset, fromName, name_len_target);
+	}
+
+	pSMB->DataCount = name_len_target;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+	pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSend error in SetPathInfo (hard link) = %d\n", rc));
+	}
+
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSCreateHardLink(const int xid, const struct cifsTconInfo *tcon,
+		   const char *fromName, const char *toName,
+		   const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	NT_RENAME_REQ *pSMB = NULL;
+	RENAME_RSP *pSMBr = NULL;
+	int bytes_returned;
+	int name_len, name_len2;
+
+	cFYI(1, ("\nIn CIFSCreateHardLink"));
+
+	rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+	pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
+	pSMB->ClusterCount = 0;
+
+	pSMB->BufferFormat = 0x04;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+		pSMB->OldFileName[name_len] = 0;	/* pad */
+		pSMB->OldFileName[name_len + 1] = 0x04;	/* strange that protocol requires an ASCII signature byte on Unicode string */
+		name_len2 =
+		    cifs_strtoUCS((wchar_t *) & pSMB->
+				  OldFileName[name_len + 2], toName, 530,
+				  nls_codepage);
+		name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
+		name_len2 *= 2;	/* convert to bytes */
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(fromName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->OldFileName, fromName, name_len);
+		name_len2 = strnlen(toName, 530);
+		name_len2++;	/* trailing null */
+		pSMB->OldFileName[name_len] = 0x04;	/* 2nd buffer format */
+		strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+		name_len2++;	/* trailing null */
+		name_len2++;	/* signature byte */
+	}
+
+	pSMB->ByteCount = 1 /* string type byte */  + name_len + name_len2;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSend error in hard link (NT rename) = %d\n", rc));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+
+	return rc;
+}
+
+int
+CIFSSMBUnixQuerySymLink(const int xid, const struct cifsTconInfo *tcon,
+			const unsigned char *searchName,
+			char *symlinkinfo, const int buflen,
+			const struct nls_table *nls_codepage)
+{
+/* SMB_QUERY_FILE_UNIX_LINK */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("\nIn QPathSymLinkInfo (Unix) the path %s", searchName));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(searchName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	pSMB->TotalParameterCount =
+	    2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &(pSMB->InformationLevel) -
+			(int) pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSend error in QuerySymLinkInfo = %d\n", rc));
+	} else {		/* decode response */
+		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+		pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
+		if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))	/* BB also check enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+				name_len = UniStrnlen((wchar_t *) ((char *)
+								   &pSMBr->hdr.
+								   Protocol +
+								   pSMBr->
+								   DataOffset),
+						      min(buflen,
+							  (int) pSMBr->
+							  DataCount) / 2);
+				cifs_strfromUCS_le(symlinkinfo,
+						   (wchar_t *) ((char *)
+								&pSMBr->
+								hdr.
+								Protocol +
+								pSMBr->
+								DataOffset),
+						   name_len, nls_codepage);
+			} else {
+				strncpy(symlinkinfo,
+					(char *) &pSMBr->hdr.Protocol +
+					pSMBr->DataOffset, min(buflen, (int)
+							       pSMBr->
+							       DataCount));
+			}
+			symlinkinfo[buflen] = 0;	/* just in case so the calling code does not go off the end of the buffer */
+		}
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBQPathInfo(const int xid, const struct cifsTconInfo *tcon,
+		 const unsigned char *searchName,
+		 FILE_ALL_INFO * pFindData,
+		 const struct nls_table *nls_codepage)
+{
+/* level 263 SMB_QUERY_FILE_ALL_INFO */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("\nIn QPathInfo path %s", searchName));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(searchName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
+	    name_len /* includes null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset = cpu_to_le16((int) &(pSMB->InformationLevel)
+					    - (int) pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSend error in QPathInfo = %d\n", rc));
+	} else {		/* decode response */
+		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+		if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512))	/* BB also check enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			memcpy((char *) pFindData,
+			       (char *) &pSMBr->hdr.Protocol +
+			       pSMBr->DataOffset, sizeof (FILE_ALL_INFO));
+		}
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBUnixQPathInfo(const int xid, const struct cifsTconInfo *tcon,
+		     const unsigned char *searchName,
+		     FILE_UNIX_BASIC_INFO * pFindData,
+		     const struct nls_table *nls_codepage)
+{
+/* SMB_QUERY_FILE_UNIX_BASIC */
+	TRANSACTION2_QPI_REQ *pSMB = NULL;
+	TRANSACTION2_QPI_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("\nIn QPathInfo (Unix) the path %s", searchName));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(searchName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
+	    name_len /* includes null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &(pSMB->InformationLevel) -
+			(int) pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSend error in QPathInfo = %d\n", rc));
+	} else {		/* decode response */
+		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+		if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512))	/* BB also check enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			memcpy((char *) pFindData,
+			       (char *) &pSMBr->hdr.Protocol +
+			       pSMBr->DataOffset,
+			       sizeof (FILE_UNIX_BASIC_INFO));
+		}
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSFindSingle(const int xid, const struct cifsTconInfo *tcon,
+	       const char *searchName, FILE_ALL_INFO * findData,
+	       const struct nls_table *nls_codepage)
+{
+/* level 257 SMB_ */
+	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
+	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("\nIn FindUnique"));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(searchName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
+	pSMB->TotalDataCount = 0;	/* no EAs */
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &pSMB->InformationLevel -
+			(int) &pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;	/* one byte, no need to le convert */
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+	pSMB->SearchCount = cpu_to_le16(16);	/* BB increase */
+	pSMB->SearchFlags = cpu_to_le16(1);
+	pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+	pSMB->SearchStorageType = 0;	/* BB what should we set this to? BB */
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	if (rc) {
+		cFYI(1, ("\nSend error in FindFileDirInfo = %d\n", rc));
+	} else {		/* decode response */
+
+		/* BB fill in */
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSFindFirst(const int xid, const struct cifsTconInfo *tcon,
+	      const char *searchName, FILE_DIRECTORY_INFO * findData,
+	      T2_FFIRST_RSP_PARMS * findParms,
+	      const struct nls_table *nls_codepage, int *pUnicodeFlag,
+	      int *pUnixFlag)
+{
+/* level 257 SMB_ */
+	TRANSACTION2_FFIRST_REQ *pSMB = NULL;
+	TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
+	char *response_data;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+
+	cFYI(1, ("\nIn FindFirst"));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(searchName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, searchName, name_len);
+	}
+
+	pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
+	pSMB->TotalDataCount = 0;	/* no EAs */
+	pSMB->MaxParameterCount = cpu_to_le16(10);
+	pSMB->MaxDataCount = cpu_to_le16((tcon->ses->maxBuf -
+					  MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &pSMB->SearchAttributes -
+			(int) &pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;	/* one byte no need to make endian neutral */
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
+	pSMB->SearchAttributes =
+	    cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
+			ATTR_DIRECTORY);
+	pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));	/* should this be shrunk even more ? */
+	pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END);
+
+	/* test for Unix extensions */
+	if (tcon->ses->capabilities & CAP_UNIX) {
+		pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
+		*pUnixFlag = TRUE;
+	} else {
+		pSMB->InformationLevel =
+		    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+		*pUnixFlag = FALSE;
+	}
+	pSMB->SearchStorageType = 0;	/* BB what should we set this to? It is not clear if it matters BB */
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	if (rc) {		/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
+		cFYI(1, ("\nError in FindFirst = %d\n", rc));
+	} else {		/* decode response */
+		/* BB add safety checks for these memcpys */
+		if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+			*pUnicodeFlag = TRUE;
+		else
+			*pUnicodeFlag = FALSE;
+		memcpy(findParms,
+		       (char *) &pSMBr->hdr.Protocol +
+		       le16_to_cpu(pSMBr->ParameterOffset),
+		       sizeof (T2_FFIRST_RSP_PARMS));
+		/* search handle can stay LE and EAoffset not needed so not converted */
+		findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
+		findParms->LastNameOffset =
+		    le16_to_cpu(findParms->LastNameOffset);
+		findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
+		response_data =
+		    (char *) &pSMBr->hdr.Protocol +
+		    le16_to_cpu(pSMBr->DataOffset);
+		memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSFindNext(const int xid, const struct cifsTconInfo *tcon,
+	     FILE_DIRECTORY_INFO * findData,
+	     T2_FNEXT_RSP_PARMS * findParms, const __u16 searchHandle,
+	     __u32 resumeKey, int *pUnicodeFlag, int *pUnixFlag)
+{
+/* level 257 SMB_ */
+	TRANSACTION2_FNEXT_REQ *pSMB = NULL;
+	TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
+	char *response_data;
+	int rc = 0;
+	int bytes_returned;
+
+	cFYI(1, ("\nIn FindNext"));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->TotalParameterCount = 14;	/* includes 2 bytes of null string, converted to LE below */
+	pSMB->TotalDataCount = 0;	/* no EAs */
+	pSMB->MaxParameterCount = cpu_to_le16(8);
+	pSMB->MaxDataCount =
+	    cpu_to_le16((tcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &pSMB->SearchHandle - (int) &pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->SearchHandle = searchHandle;	/* always kept as le */
+	findParms->SearchCount = 0;	/* set to zero in case of error */
+	pSMB->SearchCount =
+	    cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));
+	/* test for Unix extensions */
+	if (tcon->ses->capabilities & CAP_UNIX) {
+		pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
+		*pUnixFlag = TRUE;
+	} else {
+		pSMB->InformationLevel =
+		    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
+		*pUnixFlag = FALSE;
+	}
+	pSMB->ResumeKey = resumeKey;	/* always kept as le */
+	pSMB->SearchFlags =
+	    cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
+			CIFS_SEARCH_CONTINUE_FROM_LAST);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+
+	if (rc) {
+		if (rc == -EBADF)
+			rc = 0;	/* search probably was closed at end of search above */
+		else
+			cFYI(1, ("\nFindNext returned = %d\n", rc));
+	} else {		/* decode response */
+		/* BB add safety checks for these memcpys */
+		if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+			*pUnicodeFlag = TRUE;
+		else
+			*pUnicodeFlag = FALSE;
+		memcpy(findParms,
+		       (char *) &pSMBr->hdr.Protocol +
+		       le16_to_cpu(pSMBr->ParameterOffset),
+		       sizeof (T2_FNEXT_RSP_PARMS));
+		findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
+		findParms->LastNameOffset =
+		    le16_to_cpu(findParms->LastNameOffset);
+		findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
+		response_data =
+		    (char *) &pSMBr->hdr.Protocol +
+		    le16_to_cpu(pSMBr->DataOffset);
+		memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
+		const unsigned char *searchName,
+		unsigned char **targetUNCs,
+		int *number_of_UNC_in_array,
+		const struct nls_table *nls_codepage)
+{
+/* TRANS2_GET_DFS_REFERRAL */
+	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
+	TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
+	int rc = 0;
+	int bytes_returned;
+	int name_len;
+	*number_of_UNC_in_array = 0;
+	*targetUNCs = NULL;
+
+	cFYI(1, ("\nIn GetDFSRefer the path %s", searchName));
+	if (ses == NULL)
+		return -ENODEV;
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, 0, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->hdr.Tid = ses->ipc_tid;
+	pSMB->hdr.Uid = ses->Suid;
+	if (ses->capabilities & CAP_STATUS32) {
+		pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		pSMB->hdr.Flags2 |= SMBFLG2_DFS;
+	}
+    if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
+				  searchName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(searchName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->RequestFileName, searchName, name_len);
+	}
+
+	pSMB->ParameterCount = 2 /* level */  + name_len /*includes null */ ;
+	pSMB->TotalDataCount = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->MaxParameterCount = 0;
+	pSMB->MaxDataCount = cpu_to_le16(4000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &(pSMB->MaxReferralLevel) -
+			(int) pSMB->hdr.Protocol);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
+	pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ;
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->MaxReferralLevel = cpu_to_le16(3);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSend error in GetDFSRefer = %d\n", rc));
+	} else {		/* decode response */
+/* BB Add logic to parse referrals here */
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBQFSInfo(const int xid, const struct cifsTconInfo *tcon,
+	       struct statfs *FSData, const struct nls_table *nls_codepage)
+{
+/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+
+	cFYI(1, ("\nIn QFSInfo"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->TotalParameterCount = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16((int) &(pSMB->InformationLevel)
+					    - (int) pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in QFSInfo = %d\n", rc));
+	} else {		/* decode response */
+		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+		cFYI(1,
+		     ("\nDecoding qfsinfo response.  BCC: %d  Offset %d\n",
+		      pSMBr->ByteCount, pSMBr->DataOffset));
+		if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512))	/* BB also check enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			response_data =
+			    (FILE_SYSTEM_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 pSMBr->DataOffset);
+			FSData->f_bsize =
+			    le32_to_cpu(response_data->BytesPerSector) *
+			    le32_to_cpu(response_data->
+					SectorsPerAllocationUnit);
+			FSData->f_blocks =
+			    le64_to_cpu(response_data->TotalAllocationUnits);
+			FSData->f_bfree = FSData->f_bavail =
+			    le64_to_cpu(response_data->FreeAllocationUnits);
+			cFYI(1,
+			     ("\nBlocks: %ld  Free: %ld Block size %ld\n",
+			      FSData->f_blocks, FSData->f_bfree,
+			      FSData->f_bsize));
+		}
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon,
+			const struct nls_table *nls_codepage)
+{
+/* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+
+	cFYI(1, ("\nIn QFSAttributeInfo"));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->TotalParameterCount = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16((int) &(pSMB->InformationLevel)
+					    - (int) pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in QFSAttributeInfo = %d\n", rc));
+	} else {		/* decode response */
+		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+		if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {	/* BB also check enough bytes returned */
+			rc = -EIO;	/* bad smb */
+		} else {
+			response_data =
+			    (FILE_SYSTEM_ATTRIBUTE_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 pSMBr->DataOffset);
+			memcpy(&tcon->fsAttrInfo, response_data,
+			       sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
+		}
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
+		     const struct nls_table *nls_codepage)
+{
+/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_DEVICE_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+
+	cFYI(1, ("\nIn QFSDeviceInfo"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->TotalParameterCount = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &(pSMB->InformationLevel) -
+			(int) pSMB->hdr.Protocol);
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in QFSDeviceInfo = %d\n", rc));
+	} else {		/* decode response */
+		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+		if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)) || (pSMBr->DataOffset > 512))	/* BB also check enough bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			response_data =
+			    (FILE_SYSTEM_DEVICE_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 pSMBr->DataOffset);
+			memcpy(&tcon->fsDevInfo, response_data,
+			       sizeof (FILE_SYSTEM_DEVICE_INFO));
+		}
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon,
+		   const struct nls_table *nls_codepage)
+{
+/* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
+	TRANSACTION2_QFSI_REQ *pSMB = NULL;
+	TRANSACTION2_QFSI_RSP *pSMBr = NULL;
+	FILE_SYSTEM_UNIX_INFO *response_data;
+	int rc = 0;
+	int bytes_returned = 0;
+
+	cFYI(1, ("\nIn QFSUnixInfo"));
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->ParameterCount = 2;	/* level */
+	pSMB->TotalDataCount = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(100);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ;
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset =
+	    cpu_to_le16((int) &(pSMB->InformationLevel) -
+			(int) pSMB->hdr.Protocol);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
+	pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cERROR(1, ("\nSend error in QFSUnixInfo = %d\n", rc));
+	} else {		/* decode response */
+		pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset);
+		if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {	/* BB also check enough bytes returned */
+			rc = -EIO;	/* bad smb */
+		} else {
+			response_data =
+			    (FILE_SYSTEM_UNIX_INFO
+			     *) (((char *) &pSMBr->hdr.Protocol) +
+				 pSMBr->DataOffset);
+			memcpy(&tcon->fsUnixInfo, response_data,
+			       sizeof (FILE_SYSTEM_UNIX_INFO));
+		}
+	}
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+/* We can not use write of zero bytes trick to 
+   set file size due to need for large file support.  Also note that 
+   this SetPathInfo is preferred to SetFileInfo based method in next 
+   routine which is only needed to work around a sharing violation bug
+   in Samba which this routine can run into */
+
+int
+CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName,
+	      __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
+{
+	struct smb_com_transaction2_spi_req *pSMB = NULL;
+	struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+	struct file_end_of_file_info *parm_data;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+
+	cFYI(1, ("\nIn SetEOF"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(fileName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+	pSMB->ParameterCount = 6 + name_len;
+	pSMB->DataCount = sizeof (struct file_end_of_file_info);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+    if(SetAllocation) {
+        if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+            pSMB->InformationLevel =
+                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+        else
+            pSMB->InformationLevel =
+                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+    } else /* Set File Size */  {    
+	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+	    else
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+    }
+
+	parm_data =
+	    (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
+				       pSMB->DataOffset);
+	pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+	pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+	pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	parm_data->FileSize = cpu_to_le64(size);
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSetPathInfo (file size) returned %d\n", rc));
+	}
+
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
+                   __u16 fid, __u32 pid_of_opener, int SetAllocation)
+{
+	struct smb_com_transaction2_sfi_req *pSMB  = NULL;
+	struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+	char *data_offset;
+    struct file_end_of_file_info *parm_data;
+	int rc = 0;
+	int bytes_returned = 0;
+    __u32 tmp;
+
+	cFYI(1, ("\nSetFileSize (via SetFileInfo)"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	tmp = cpu_to_le32(pid_of_opener);  /* override pid of current process
+                                         so network fid will be valid */
+	pSMB->hdr.Pid = tmp & 0xFFFF;
+	tmp >>= 16;
+	pSMB->hdr.PidHigh = tmp & 0xFFFF;
+    
+	pSMB->ParameterCount = 6;
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    (int) &(pSMB->Fid) - (int) pSMB->hdr.Protocol;
+	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+
+	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;	
+
+	pSMB->DataCount = sizeof(struct file_end_of_file_info);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+	pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+	pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+	pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+	parm_data =
+	    (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
+				       pSMB->DataOffset);
+    parm_data->FileSize = size;
+    pSMB->Fid = fid;
+    if(SetAllocation) {
+        if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+            pSMB->InformationLevel =
+                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+        else
+            pSMB->InformationLevel =
+                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+    } else /* Set File Size */  {    
+	    if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+	    else
+		    pSMB->InformationLevel =
+		        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+    }
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1,
+		     ("\nSend error in SetFileInfo (SetFileSize) = %d\n",
+		      rc));
+	}
+
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName,
+		FILE_BASIC_INFO * data, const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	char *data_offset;
+
+	cFYI(1, ("\nIn SetTimes"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(fileName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+
+	pSMB->ParameterCount = 6 + name_len;
+	pSMB->DataCount = sizeof (FILE_BASIC_INFO);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+	pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+	pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+
+	pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
+	else
+		pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSetPathInfo (times) returned %d\n", rc));
+	}
+
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
+
+int
+CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
+		    char *fileName, __u64 mode, __u64 uid, __u64 gid,
+		    const struct nls_table *nls_codepage)
+{
+	TRANSACTION2_SPI_REQ *pSMB = NULL;
+	TRANSACTION2_SPI_RSP *pSMBr = NULL;
+	int name_len;
+	int rc = 0;
+	int bytes_returned = 0;
+	FILE_UNIX_BASIC_INFO *data_offset;
+
+	cFYI(1, ("\nIn SetUID/GID/Mode"));
+
+	rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+		      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+		name_len =
+		    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+				  /* find define for this maxpathcomponent */
+				  , nls_codepage);
+		name_len++;	/* trailing null */
+		name_len *= 2;
+	} else {		/* BB improve the check for buffer overruns BB */
+
+		name_len = strnlen(fileName, 530);
+		name_len++;	/* trailing null */
+		strncpy(pSMB->FileName, fileName, name_len);
+	}
+
+	pSMB->ParameterCount = 6 + name_len;
+	pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO);
+	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxSetupCount = 0;
+	pSMB->Reserved = 0;
+	pSMB->Flags = 0;
+	pSMB->Timeout = 0;
+	pSMB->Reserved2 = 0;
+	pSMB->ParameterOffset =
+	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+	data_offset =
+	    (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
+				      pSMB->DataOffset);
+	pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+	pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+	pSMB->SetupCount = 1;
+	pSMB->Reserved3 = 0;
+	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+	pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+	pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+	pSMB->TotalParameterCount = pSMB->ParameterCount;
+	pSMB->TotalDataCount = pSMB->DataCount;
+	pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
+	pSMB->Reserved4 = 0;
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	data_offset->Uid = cpu_to_le64(uid);
+	cFYI(1, ("\nUid = %lld from %lld ", data_offset->Uid, uid));
+	data_offset->Gid = cpu_to_le64(gid);
+	cFYI(1, ("\nGid = %lld from %lld ", data_offset->Gid, gid));
+	data_offset->Permissions = cpu_to_le64(mode);
+	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("\nSetPathInfo (perms) returned %d\n", rc));
+	}
+
+	if (pSMB)
+		buf_release(pSMB);
+	return rc;
+}
diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/connect.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,2252 @@
+/*
+ *   fs/cifs/connect.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+#include <linux/fs.h>
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/version.h>
+#include <linux/ipv6.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+
+#define CIFS_PORT 445
+#define RFC1001_PORT 139
+
+extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+		       unsigned char *p24);
+extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
+			 unsigned char *p24);
+extern int inet_addr(char *);
+
+struct smb_vol {
+	char *username;
+	char *password;
+	char *domainname;
+	char *UNC;
+	char *UNCip;
+	uid_t linux_uid;
+	uid_t linux_gid;
+	mode_t file_mode;
+	mode_t dir_mode;
+	int rw;
+};
+
+int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket);
+
+int
+cifs_reconnect(struct TCP_Server_Info *server)
+{
+	int rc = 0;
+
+	cFYI(1, ("\nReconnecting tcp session "));
+
+	/* lock tcp session */
+	/* mark all smb sessions as reconnecting which use this tcp session */
+	/* reconnect tcp session */
+	/* wake up waiters on reconnection */
+	cFYI(1,
+	     ("\nState: 0x%x Flags: 0x%lx", server->ssocket->state,
+	      server->ssocket->flags));
+
+	ipv4_connect(&server->sockAddr, &server->ssocket);
+	return rc;
+}
+
+int
+cifs_demultiplex_thread(struct TCP_Server_Info *server)
+{
+	int length, total_read;
+	unsigned int pdu_length;
+	struct smb_hdr *smb_buffer = NULL;
+	struct msghdr smb_msg;
+	mm_segment_t temp_fs;
+	struct iovec iov;
+	struct socket *csocket = server->ssocket;
+	struct list_head *tmp;
+	struct cifsSesInfo *ses;
+	struct task_struct *task_to_wake = NULL;
+	struct mid_q_entry *mid_entry;
+	char *temp;
+
+	daemonize();
+
+	server->tsk = current;	/* save process info to wake at shutdown */
+	cFYI(1, ("\nDemultiplex PID: %d", current->pid));
+
+	temp_fs = get_fs();	/* we must turn off socket api parm checking */
+	set_fs(get_ds());
+
+	while (server->tcpStatus != CifsExiting) {
+		if (smb_buffer == NULL)
+			smb_buffer = buf_get();
+		else
+			memset(smb_buffer, 0, sizeof (struct smb_hdr));
+
+		if (smb_buffer == NULL) {
+			cERROR(1,
+			       ("\n Error - can not get mem for SMB response buffer "));
+			return -ENOMEM;
+		}
+		iov.iov_base = smb_buffer;
+		iov.iov_len = sizeof (struct smb_hdr) - 1;	
+        /* 1 byte less above since wct is not always returned in error cases */
+		smb_msg.msg_iov = &iov;
+		smb_msg.msg_iovlen = 1;
+		smb_msg.msg_control = NULL;
+		smb_msg.msg_controllen = 0;
+
+		length =
+		    sock_recvmsg(csocket, &smb_msg,
+				 sizeof (struct smb_hdr) -
+				 1 /* RFC1001 header and SMB header */ ,
+				 MSG_PEEK /* flags see socket.h */ );
+		if (length < 0) {
+			if (length == -ECONNRESET) {
+				cERROR(1, ("\nConnection reset by peer "));
+				/* BB fix call below */
+				/* cifs_reconnect(server);       */
+			} else { /* find define for the -512 returned at unmount time */
+				cFYI(1,
+				       ("\nReceived error on sock_recvmsg( peek) with length = %d\n",
+					length)); 
+			}
+			break;
+		}
+		if (length == 0) {
+			cFYI(1,
+			     ("\nZero length peek received - dead session?? "));
+			/* schedule_timeout(HZ/4); 
+			   continue; */
+			break;
+		}
+		pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
+		cFYI(1, ("\nPeek length rcvd: %d with smb length: %d", length, pdu_length));	/* BB */
+
+		temp = (char *) smb_buffer;
+		if (length > 3) {
+			if (temp[0] == (char) 0x85) {
+				iov.iov_base = smb_buffer;
+				iov.iov_len = 4;
+				length = sock_recvmsg(csocket, &smb_msg, 4, 0);
+				cFYI(0,
+				     ("\nReceived 4 byte keep alive packet "));
+			} else if ((temp[0] == (char) 0x83)
+				   && (length == 5)) {
+				/* we get this from Windows 98 instead of error on SMB negprot response */
+				cERROR(1,
+				       ("\nNegative RFC 1002 Session response. Error = 0x%x",
+					temp[4]));
+				break;
+
+			} else if (temp[0] != (char) 0) {
+				cERROR(1,
+				       ("\nUnknown RFC 1001 frame received not 0x00 nor 0x85"));
+				dump_mem(" Received Data is: ", temp, length);
+				break;
+			} else {
+				if ((length != sizeof (struct smb_hdr) - 1)
+				    || (pdu_length >
+					CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
+				    || (pdu_length <
+					sizeof (struct smb_hdr) - 1)
+				    ||
+				    (checkSMBhdr
+				     (smb_buffer, smb_buffer->Mid))) {
+					cERROR(1,
+					       (KERN_ERR
+						"\nInvalid size or format for SMB found with length %d and pdu_lenght %d\n",
+						length, pdu_length));
+					/* BB fix by finding next smb signature - and reading off data until next smb ? BB */
+
+					/* BB add reconnect here */
+
+					break;
+				} else {	/* length ok */
+
+					length = 0;
+					iov.iov_base = smb_buffer;
+					iov.iov_len = pdu_length;
+					for (total_read = 0; total_read < pdu_length; total_read += length) {	
+             /* Should improve check for buffer overflow with bad pdu_length */
+						/*  iov.iov_base = smb_buffer+total_read;
+						   iov.iov_len =  pdu_length-total_read; */
+						length = sock_recvmsg(csocket, &smb_msg, 
+                                 pdu_length - total_read, 0);
+         /* cERROR(1,("\nFor iovlen %d Length received: %d with total read %d",
+						   iov.iov_len, length,total_read));       */
+						if (length == 0) {
+							cERROR(1,
+							       ("\nZero length receive when expecting %d ",
+								pdu_length - total_read));
+							/* BB add reconnect here */
+							break;
+						}						
+					}
+				}
+
+				dump_smb(smb_buffer, length);
+				if (checkSMB
+				    (smb_buffer, smb_buffer->Mid, total_read)) {
+					cERROR(1, ("\n Bad SMB Received "));
+					continue;
+				}
+
+                task_to_wake = NULL;
+				list_for_each(tmp, &server->pending_mid_q) {
+					mid_entry = list_entry(tmp, struct
+							       mid_q_entry,
+							       qhead);
+
+					if (mid_entry->mid == smb_buffer->Mid) {
+						cFYI(1,
+						     (" Mid 0x%x matched - waking up\n ",mid_entry->mid));
+						task_to_wake = mid_entry->tsk;
+						mid_entry->resp_buf =
+						    smb_buffer;
+						mid_entry->midState =
+						    MID_RESPONSE_RECEIVED;
+					}
+				}
+
+				if (task_to_wake) {
+					smb_buffer = NULL;	/* will be freed by users thread after he is done */
+					wake_up_process(task_to_wake);
+				} else if (is_valid_oplock_break(smb_buffer) == FALSE) {                          
+                	cERROR(1, ("\n No task to wake, unknown frame rcvd!\n"));
+                }
+			}
+		} else {
+			cFYI(0,
+			     ("\nFrame less than four bytes received  %d bytes long.",
+			      length));
+			if (length > 0) {
+				length = sock_recvmsg(csocket, &smb_msg, length, 0);	/* throw away junk frame */
+				cFYI(1,
+				     (" with junk  0x%x in it\n",
+				      *(__u32 *) smb_buffer));
+			}
+		}
+	}
+	/* BB add code to lock SMB sessions while releasing */
+	if(server->ssocket) {
+        sock_release(csocket);
+	    server->ssocket = NULL;
+    }
+	set_fs(temp_fs);
+	if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
+		buf_release(smb_buffer);
+	if (list_empty(&server->pending_mid_q)) {
+		/* loop through server session structures attached to this and mark them dead */
+		list_for_each(tmp, &GlobalSMBSessionList) {
+			ses =
+			    list_entry(tmp, struct cifsSesInfo,
+				       cifsSessionList);
+			if (ses->server == server) {
+				ses->status = CifsExiting;
+				ses->server = NULL;
+			}
+		}
+		kfree(server);
+	} else	/* BB need to more gracefully handle the rare negative session 
+               response case because response will be still outstanding */
+		cERROR(1, ("\nThere are still active MIDs in queue and we are exiting but we can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!\n "));	/* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */
+/* BB Need to fix bug in error path above - perhaps wait until smb requests
+   time out and then free the tcp per server struct BB */
+
+	cFYI(1, ("\nAbout to exit from demultiplex thread\n"));
+	return 0;
+}
+
+int
+parse_mount_options(char *options, char *devname, struct smb_vol *vol)
+{
+	char *value;
+	char *data;
+
+	vol->username = NULL;
+	vol->password = NULL;
+	vol->domainname = NULL;
+	vol->UNC = NULL;
+	vol->UNCip = NULL;
+	vol->linux_uid = current->uid;	/* current->euid instead? */
+	vol->linux_gid = current->gid;
+	vol->rw = TRUE;
+
+	if (!options)
+		return 1;
+
+	while ((data = strsep(&options, ",")) != NULL) {
+		if (!*data)
+			continue;
+		if ((value = strchr(data, '=')) != NULL)
+			*value++ = '\0';
+		if (strnicmp(data, "user", 4) == 0) {
+			if (!value || !*value) {
+				printk(KERN_ERR
+				       "CIFS: invalid or missing username");
+				return 1;	/* needs_arg; */
+			}
+			if (strnlen(value, 200) < 200) {
+				vol->username = value;
+			} else {
+				printk(KERN_ERR "CIFS: username too long");
+				return 1;
+			}
+		} else if (strnicmp(data, "pass", 4) == 0) {
+			if (!value || !*value) {
+				vol->password = NULL;
+			} else if (strnlen(value, 17) < 17) {
+				vol->password = value;
+			} else {
+				printk(KERN_ERR "CIFS: password too long");
+				return 1;
+			}
+		} else if ((strnicmp(data, "unc", 3) == 0)
+			   || (strnicmp(data, "target", 6) == 0)
+			   || (strnicmp(data, "path", 4) == 0)) {
+			if (!value || !*value) {
+				printk(KERN_ERR
+				       "CIFS: invalid path to network resource");
+				return 1;	/* needs_arg; */
+			}
+			if (strnlen(value, 300) < 300) {
+				vol->UNC = value;
+				if (strncmp(vol->UNC, "//", 2) == 0) {
+					vol->UNC[0] = '\\';
+					vol->UNC[1] = '\\';
+				} else if (strncmp(vol->UNC, "\\\\", 2) != 0) {	                   
+					printk(KERN_ERR
+					       "CIFS: UNC Path does not begin with // or \\\\");
+					return 1;
+				}
+				vol->UNCip = &vol->UNC[2];
+			} else {
+				printk(KERN_ERR "CIFS: UNC name too long");
+				return 1;
+			}
+		} else if ((strnicmp(data, "domain", 3) == 0)
+			   || (strnicmp(data, "workgroup", 5) == 0)) {
+			if (!value || !*value) {
+				printk(KERN_ERR "CIFS: invalid domain name");
+				return 1;	/* needs_arg; */
+			}
+			if (strnlen(value, 65) < 65) {
+				vol->domainname = value;
+				cFYI(1, ("\nDomain name set"));
+			} else {
+				printk(KERN_ERR "CIFS: domain name too long");
+				return 1;
+			}
+		} else if (strnicmp(data, "uid", 3) == 0) {
+			if (value && *value) {
+				vol->linux_uid =
+				    simple_strtoul(value, &value, 0);
+			}
+		} else if (strnicmp(data, "gid", 3) == 0) {
+			if (value && *value) {
+				vol->linux_gid =
+				    simple_strtoul(value, &value, 0);
+			}
+		} else if (strnicmp(data, "file_mode", 4) == 0) {
+			if (value && *value) {
+				vol->file_mode =
+				    simple_strtoul(value, &value, 0);
+			}
+		} else if (strnicmp(data, "dir_mode", 3) == 0) {
+			if (value && *value) {
+				vol->dir_mode =
+				    simple_strtoul(value, &value, 0);
+			}
+		} else if (strnicmp(data, "version", 3) == 0) {
+			/* ignore */
+		} else if (strnicmp(data, "rw", 2) == 0) {
+			vol->rw = TRUE;
+		} else
+			printk(KERN_ERR
+			       "CIFS: Unrecognized mount option %s = %s",
+			       data, value);
+	}
+	if (vol->UNC == NULL) {
+		if (strnlen(devname, 300) < 300) {
+			vol->UNC = devname;
+			if (strncmp(vol->UNC, "//", 2) == 0) {
+				vol->UNC[0] = '\\';
+				vol->UNC[1] = '\\';
+			} else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
+				printk(KERN_ERR
+				       "CIFS: UNC Path does not begin with // or \\\\");
+				return 1;
+			}
+			vol->UNCip = &vol->UNC[2];
+		} else {
+			printk(KERN_ERR "CIFS: UNC name too long");
+			return 1;
+		}
+	}
+	return 0;
+}
+
+struct cifsSesInfo *
+find_tcp_session(__u32 new_target_ip_addr,
+		 char *userName, struct TCP_Server_Info **psrvTcp)
+{
+	struct list_head *tmp;
+	struct cifsSesInfo *ses;
+
+	*psrvTcp = NULL;
+
+	list_for_each(tmp, &GlobalSMBSessionList) {
+		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
+		if (ses->server) {
+			if (ses->server->sockAddr.sin_addr.s_addr ==
+			    new_target_ip_addr) {
+				/* BB lock server and tcp session and increment use count here?? */
+				*psrvTcp = ses->server;	/* found a match on the TCP session */
+				/* BB check if reconnection needed */
+				if (strncmp
+				    (ses->userName, userName,
+				     MAX_USERNAME_SIZE) == 0)
+					return ses;	/* found exact match on both tcp and SMB sessions */
+			}
+		}
+		/* else tcp and smb sessions need reconnection */
+	}
+	return NULL;
+}
+
+struct cifsTconInfo *
+find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
+{
+	struct list_head *tmp;
+	struct cifsTconInfo *tcon;
+
+	list_for_each(tmp, &GlobalTreeConnectionList) {
+		cFYI(1, ("\nNext tcon - "));
+		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+		if (tcon->ses) {
+			if (tcon->ses->server) {
+				cFYI(1,
+				     (" old ip addr: %x == new ip %x ?",
+				      tcon->ses->server->sockAddr.sin_addr.
+				      s_addr, new_target_ip_addr));
+				if (tcon->ses->server->sockAddr.sin_addr.
+				    s_addr == new_target_ip_addr) {
+	/* BB lock tcon and server and tcp session and increment use count here? */
+					/* found a match on the TCP session */
+					/* BB check if reconnection needed */
+					cFYI(1,
+					     ("\nMatched ip, old UNC: %s == new: %s ?",
+					      tcon->treeName, uncName));
+					if (strncmp
+					    (tcon->treeName, uncName,
+					     MAX_TREE_SIZE) == 0) {
+						cFYI(1,
+						     ("\nMatched UNC, old user: %s == new: %s ?",
+						      tcon->treeName, uncName));
+						if (strncmp
+						    (tcon->ses->userName,
+						     userName,
+						     MAX_USERNAME_SIZE) == 0)
+							return tcon;/* also matched user (smb session)*/
+					}
+				}
+			}
+		}
+	}
+	return NULL;
+}
+
+int
+connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+		    const char *old_path, const struct nls_table *nls_codepage)
+{
+	char *temp_unc;
+	int rc = 0;
+	int num_referrals = 0;
+	unsigned char *referrals = NULL;
+
+	if (pSesInfo->ipc_tid == 0) {
+		temp_unc =
+		    kmalloc(2 +
+			    strnlen(pSesInfo->serverName,
+				    SERVER_NAME_LEN_WITH_NULL * 2) + 1 +
+			    4 /* IPC$ */  + 1, GFP_KERNEL);
+		if (temp_unc == NULL)
+			return -ENOMEM;
+		temp_unc[0] = '\\';
+		temp_unc[1] = '\\';
+		strncpy(temp_unc + 2, pSesInfo->serverName,
+			SERVER_NAME_LEN_WITH_NULL * 2);
+		strncpy(temp_unc + 2 +
+			strnlen(pSesInfo->serverName,
+				SERVER_NAME_LEN_WITH_NULL * 2), "\\IPC$", 6);
+		rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
+		cFYI(1,
+		     ("\nCIFS Tcon rc = %d ipc_tid = %d\n", rc,
+		      pSesInfo->ipc_tid));
+		kfree(temp_unc);
+	}
+	if (rc == 0)
+		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &referrals,
+				     &num_referrals, nls_codepage);
+
+	return -ENODEV;		/* BB remove and add return rc; */
+
+}
+
+int
+ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket)
+{
+	int rc = 0;
+
+	rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
+	if (rc < 0) {
+		cERROR(1, ("Error creating socket. Aborting operation\n"));
+		return rc;
+	}
+
+	psin_server->sin_family = AF_INET;
+	psin_server->sin_port = htons(CIFS_PORT);
+
+	rc = (*csocket)->ops->connect(*csocket,
+				      (struct sockaddr *) psin_server,
+				      sizeof (struct sockaddr_in), 0
+		/* Is there a way to fix a polling timeout -
+         and find out what more of the flags really mean? */
+	    );
+	if (rc < 0) {
+		psin_server->sin_port = htons(RFC1001_PORT);
+		rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
+					      psin_server,
+					      sizeof (struct sockaddr_in), 0);
+		if (rc < 0) {
+			cFYI(1, ("Error connecting to socket. %d\n", rc));
+			sock_release(*csocket);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+int
+ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
+{
+	int rc = 0;
+
+	rc = sock_create(PF_INET6, SOCK_STREAM,
+			 IPPROTO_TCP /* IPPROTO_IPV6 ? */ , csocket);
+	if (rc < 0) {
+		cERROR(1, ("Error creating socket. Aborting operation\n"));
+		return rc;
+	}
+
+	psin_server->sin6_family = AF_INET6;
+	psin_server->sin6_port = htons(CIFS_PORT);
+
+	rc = (*csocket)->ops->connect(*csocket,
+				      (struct sockaddr *) psin_server,
+				      sizeof (struct sockaddr_in6), 0
+/* BB fix the timeout to be shorter - and check flags */
+	    );
+	if (rc < 0) {
+		psin_server->sin6_port = htons(RFC1001_PORT);
+		rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
+					      psin_server,
+					      sizeof (struct sockaddr_in6), 0);
+		if (rc < 0) {
+			cFYI(1,
+			     ("Error connecting to socket (via ipv6). %d\n",
+			      rc));
+			sock_release(*csocket);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+int
+cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
+	   char *mount_data, char *devname)
+{
+	int rc = 0;
+	int xid;
+    int ntlmv2_flag = FALSE;
+	struct socket *csocket;
+	struct sockaddr_in sin_server;
+/*	struct sockaddr_in6 sin_server6; */
+	struct smb_vol volume_info;
+	struct cifsSesInfo *pSesInfo = NULL;
+	struct cifsSesInfo *existingCifsSes = NULL;
+	struct cifsTconInfo *tcon = NULL;
+	struct TCP_Server_Info *srvTcp = NULL;
+	char cryptKey[CIFS_CRYPTO_KEY_SIZE];
+	char session_key[CIFS_SESSION_KEY_SIZE];
+	char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+	char password_with_pad[CIFS_ENCPWD_SIZE];
+
+	xid = GetXid();
+	cFYI(0, ("\nEntering cifs_mount. Xid: %d with: %s\n", xid, mount_data));
+
+	parse_mount_options(mount_data, devname, &volume_info);
+
+	if (volume_info.username) {
+		cFYI(1, ("\nUsername: %s ", volume_info.username));
+
+	} else {
+		cERROR(1, ("\nNo username specified "));	
+        /* Could add ways to allow getting user name from alternate locations */
+	}
+
+	if (volume_info.UNC) {
+		sin_server.sin_addr.s_addr = inet_addr(volume_info.UNCip);
+		cFYI(1, ("\nUNC: %s  ", volume_info.UNC));
+	} else {
+		/* BB we could connect to the DFS root? but which server do we ask? */
+		cERROR(1,
+		       ("\nCIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified  "));
+		FreeXid(xid);
+		return -ENODEV;
+	}
+	/* BB add support to use the multiuser_mount flag BB */
+	existingCifsSes =
+	    find_tcp_session(sin_server.sin_addr.s_addr,
+			     volume_info.username, &srvTcp);
+	if (srvTcp) {
+		cFYI(1, ("\nExisting tcp session with server found "));                
+	} else {		/* create socket */
+		rc = ipv4_connect(&sin_server, &csocket);
+		if (rc < 0) {
+			cERROR(1,
+			       ("Error connecting to IPv4 socket. Aborting operation\n"));
+			FreeXid(xid);
+			return rc;
+		}
+
+		srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
+		if (srvTcp == NULL) {
+			rc = -ENOMEM;
+			sock_release(csocket);
+			FreeXid(xid);
+			return rc;
+		} else {
+			memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
+			memcpy(&srvTcp->sockAddr, &sin_server, sizeof (struct sockaddr_in));	
+            /* BB Add code for ipv6 case too */
+			srvTcp->ssocket = csocket;
+			init_waitqueue_head(&srvTcp->response_q);
+			INIT_LIST_HEAD(&srvTcp->pending_mid_q);
+			kernel_thread((void *) (void *)
+				      cifs_demultiplex_thread, srvTcp,
+				      CLONE_FS | CLONE_FILES | CLONE_VM);
+		}
+	}
+
+	if (existingCifsSes) {
+		pSesInfo = existingCifsSes;
+		cFYI(1, ("\nExisting smb sess found "));
+	} else if (!rc) {
+		cFYI(1, ("\nExisting smb sess not found "));
+		pSesInfo = sesInfoAlloc();
+		if (pSesInfo == NULL)
+			rc = -ENOMEM;
+		else {
+			pSesInfo->server = srvTcp;
+			pSesInfo->status = CifsGood;
+			sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
+				NIPQUAD(sin_server.sin_addr.s_addr));
+		}
+
+		/* send negotiate protocol smb */
+		if (!rc)
+			rc = CIFSSMBNegotiate(xid, pSesInfo, cryptKey);
+		cFYI(0, ("\nNegotiate rc = %d ", rc));
+		if (!rc) {
+			cFYI(1, ("\nSecurity Mode: %x", pSesInfo->secMode));
+			cFYI(1,
+			     (" Server Capabilities: %x",
+			      pSesInfo->capabilities));
+			cFYI(1,
+			     (" Time Zone: 0x%x %d\n", pSesInfo->timeZone,
+			      pSesInfo->timeZone));
+
+			memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+			if (volume_info.password)
+				strcpy(password_with_pad, volume_info.password);
+
+			if (extended_security
+			    && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+			    && (pSesInfo->secType == NTLMSSP)) {
+				cFYI(1, ("\nNew style sesssetup "));
+				rc = CIFSSpnegoSessSetup(xid, pSesInfo,
+							 volume_info.
+							 username,
+							 volume_info.
+							 domainname, NULL
+							 /* security blob */
+							 , 0	/* blob length */
+							 , cifs_sb->local_nls);
+			} else if (extended_security
+				   && (pSesInfo->
+				       capabilities & CAP_EXTENDED_SECURITY)
+				   && (pSesInfo->secType == RawNTLMSSP)) {
+				cFYI(1, ("\nNTLMSSP sesssetup "));
+				rc = CIFSNTLMSSPNegotiateSessSetup(xid,
+								   pSesInfo,
+								   cryptKey,
+								   volume_info.domainname,
+                                   &ntlmv2_flag,
+								   cifs_sb->local_nls);
+				if (!rc) {
+                    if(ntlmv2_flag) {
+                        cFYI(1,("\nAble to use the more secure NTLM version 2 password hash"));
+                        /* SMBNTv2encrypt( ...);  */ /* BB fix this up - 
+                        and note that Samba client equivalent looks wrong */
+                    } else
+					    SMBNTencrypt(password_with_pad,cryptKey,ntlm_session_key);
+
+					/* for better security the weaker lanman hash not sent 
+                       in AuthSessSetup so why bother calculating it */
+
+					/* toUpper(cifs_sb->local_nls,
+						password_with_pad);
+					SMBencrypt(password_with_pad,
+						   cryptKey, session_key); */
+
+					rc = CIFSNTLMSSPAuthSessSetup(xid,
+								      pSesInfo,
+								      volume_info.
+								      username,
+								      volume_info.domainname,
+								      ntlm_session_key,
+								      session_key,
+                                      ntlmv2_flag,
+								      cifs_sb->local_nls);
+				}
+			} else {	/* old style NTLM 0.12 session setup */
+				SMBNTencrypt(password_with_pad, cryptKey,
+					     ntlm_session_key);
+               /* Removed following few lines to not send old style password 
+                  hash ever - for better security */
+			   /* toUpper(cifs_sb->local_nls, password_with_pad);
+				   SMBencrypt(password_with_pad, cryptKey,session_key); 
+				   dump_mem("\nCIFS (Samba encrypt): ", session_key,CIFS_SESSION_KEY_SIZE); */
+
+				rc = CIFSSessSetup(xid, pSesInfo,
+						   volume_info.username,
+						   volume_info.
+						   domainname,
+						   session_key,
+						   ntlm_session_key,
+						   cifs_sb->local_nls);
+			}
+			if (rc) {
+				cERROR(1,
+				       ("\nSend error in SessSetup = %d\n",
+					rc));
+			} else {
+				cFYI(1,
+				     ("CIFS Session Established successfully "));
+				strncpy(pSesInfo->userName,
+					volume_info.username,
+					MAX_USERNAME_SIZE);
+				atomic_inc(&srvTcp->socketUseCount);
+			}
+		}
+	}
+
+	/* search for existing tcon to this server share */
+	if (!rc) {
+		tcon =
+		    find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
+			     volume_info.username);
+		if (tcon) {
+			cFYI(1, ("\nFound match on UNC path "));
+		} else {
+			tcon = tconInfoAlloc();
+			if (tcon == NULL)
+				rc = -ENOMEM;
+			else {
+				/* check for null share name ie connect to dfs root */
+
+				/* BB check if this works for exactly length three strings */
+				if ((strchr(volume_info.UNC + 3, '\\') == NULL)
+				    && (strchr(volume_info.UNC + 3, '/') ==
+					NULL)) {
+					rc = connect_to_dfs_path(xid,
+								 pSesInfo,
+								 "",
+								 cifs_sb->
+								 local_nls);
+					return -ENODEV;
+				} else {
+					rc = CIFSTCon(xid, pSesInfo,
+						      volume_info.UNC,
+						      tcon, cifs_sb->local_nls);
+					cFYI(1, ("\nCIFS Tcon rc = %d\n", rc));
+				}
+				if (!rc)
+					atomic_inc(&pSesInfo->inUse);
+			}
+		}
+	}
+	if (pSesInfo->capabilities & CAP_LARGE_FILES) {
+		cFYI(0, ("\nLarge files supported "));
+		sb->s_maxbytes = (u64) 1 << 63;
+	} else
+		sb->s_maxbytes = (u64) 1 << 31;	/* 2 GB */
+
+/* on error free sesinfo and tcon struct if needed */
+	if (rc) {
+		           /* If find_unc succeeded then rc == 0 so we can not end */
+        if (tcon)  /* up here accidently freeing someone elses tcon struct */
+			tconInfoFree(tcon);
+		if (existingCifsSes == 0) {
+			if (pSesInfo) {
+				if (pSesInfo->server) {
+					cFYI(0,
+					     ("\nAbout to check if we need to do SMBLogoff "));
+					if (pSesInfo->Suid)
+						CIFSSMBLogoff(xid, pSesInfo);
+					wake_up_process(pSesInfo->server->tsk);
+					schedule_timeout(HZ / 4);	/* give captive thread time to exit */
+				} else
+					cFYI(1, ("\nNo session or bad tcon"));
+				sesInfoFree(pSesInfo);
+				/* pSesInfo = NULL; */
+			}
+		}
+	} else {
+		atomic_inc(&tcon->useCount);
+		cifs_sb->tcon = tcon;
+		tcon->ses = pSesInfo;
+
+		/* do not care if following two calls succeed - informational only */
+		CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
+		CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
+		if (tcon->ses->capabilities & CAP_UNIX)
+			CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
+	}
+
+	FreeXid(xid);
+
+	return rc;
+}
+
+int
+CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *user,
+	      char *domain, char session_key[CIFS_SESSION_KEY_SIZE],
+	      char session_key2[CIFS_SESSION_KEY_SIZE],
+	      const struct nls_table *nls_codepage)
+{
+	struct smb_hdr *smb_buffer;
+	struct smb_hdr *smb_buffer_response;
+	SESSION_SETUP_ANDX *pSMB;
+	SESSION_SETUP_ANDX *pSMBr;
+	char *bcc_ptr;
+	int rc = 0;
+	int remaining_words = 0;
+	int bytes_returned = 0;
+	int len;
+
+	cFYI(1, ("\nIn sesssetup "));
+
+	smb_buffer = buf_get();
+	if (smb_buffer == 0) {
+		return -ENOMEM;
+	}
+    smb_buffer_response = smb_buffer;
+	pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+
+	/* send SMBsessionSetup here */
+	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+			0 /* no tCon exists yet */ , 13 /* wct */ );
+
+	pSMB->req_no_secext.AndXCommand = 0xFF;
+	pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->maxBuf);
+	pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->maxReq);
+
+    if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+        smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	pSMB->req_no_secext.Capabilities =
+	    CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
+	if (ses->capabilities & CAP_UNICODE) {
+		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+		pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+		pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		smb_buffer->Flags2 |= SMBFLG2_DFS;
+		pSMB->req_no_secext.Capabilities |= CAP_DFS;
+	}
+	pSMB->req_no_secext.Capabilities =
+	    cpu_to_le32(pSMB->req_no_secext.Capabilities);
+	/* pSMB->req_no_secext.CaseInsensitivePasswordLength =
+	   CIFS_SESSION_KEY_SIZE; */
+	pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+	pSMB->req_no_secext.CaseSensitivePasswordLength =
+	    cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+	bcc_ptr = pByteArea(smb_buffer);
+	/* memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
+	   bcc_ptr += CIFS_SESSION_KEY_SIZE; */
+	memcpy(bcc_ptr, (char *) session_key2, CIFS_SESSION_KEY_SIZE);
+	bcc_ptr += CIFS_SESSION_KEY_SIZE;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		if ((int) bcc_ptr % 2) {	/* must be word aligned for Unicode */
+			*bcc_ptr = 0;
+			bcc_ptr++;
+		}
+        if(user == NULL)
+            bytes_returned = 0; /* skill null user */
+        else
+		    bytes_returned =
+		        cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;	/* convert num 16 bit words to bytes */
+		bcc_ptr += 2;	/* trailing null */
+		if (domain == NULL)
+			bytes_returned =
+			    cifs_strtoUCS((wchar_t *) bcc_ptr,
+					  "CIFS_LINUX_DOM", 32, nls_codepage);
+		else
+			bytes_returned =
+			    cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+					  nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+				  32, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+				  nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+				  64, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;
+	} else {
+        if(user != NULL) {                
+		    strncpy(bcc_ptr, user, 200);
+		    bcc_ptr += strnlen(user, 200);
+        }
+		*bcc_ptr = 0;
+		bcc_ptr++;
+		if (domain == NULL) {
+			strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+			bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
+		} else {
+			strncpy(bcc_ptr, domain, 64);
+			bcc_ptr += strnlen(domain, 64);
+			*bcc_ptr = 0;
+			bcc_ptr++;
+		}
+		strcpy(bcc_ptr, "Linux version ");
+		bcc_ptr += strlen("Linux version ");
+		strcpy(bcc_ptr, UTS_RELEASE);
+		bcc_ptr += strlen(UTS_RELEASE) + 1;
+		strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+		bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+	}
+	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	smb_buffer->smb_buf_length += BCC(smb_buffer);
+	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+			 &bytes_returned, 1);
+	/* dump_mem("\nSessSetup response is: ", smb_buffer_response, 92);*/
+	if (rc) {
+/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
+	} else if ((smb_buffer_response->WordCount == 3)
+		   || (smb_buffer_response->WordCount == 4)) {
+		pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+		if (pSMBr->resp.Action & GUEST_LOGIN)
+			cFYI(1, (" Guest login"));	/* do we want to mark SesInfo struct ? */
+		if (ses) {
+			ses->Suid = smb_buffer_response->Uid;	/* UID left in wire format (le) */
+			cFYI(1, ("UID = %d ", ses->Suid));
+         /* response can have either 3 or 4 word count - Samba sends 3 */
+			bcc_ptr = pByteArea(smb_buffer_response);	
+			if ((pSMBr->resp.hdr.WordCount == 3)
+			    || ((pSMBr->resp.hdr.WordCount == 4)
+				&& (pSMBr->resp.SecurityBlobLength <
+				    pSMBr->resp.ByteCount))) {
+				if (pSMBr->resp.hdr.WordCount == 4)
+					bcc_ptr +=
+					    pSMBr->resp.SecurityBlobLength;
+
+				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+					if ((int) (bcc_ptr) % 2) {
+						remaining_words =
+						    (BCC(smb_buffer_response)
+						     - 1) / 2;
+						bcc_ptr++;	/* Unicode strings must be word aligned */
+					} else {
+						remaining_words =
+						    BCC
+						    (smb_buffer_response) / 2;
+					}
+					len =
+					    UniStrnlen((wchar_t *) bcc_ptr,
+						       remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+   the end since (at least) WIN2K and Windows XP have a major bug in not null
+   terminating last Unicode string in response  */
+					ses->serverOS = kcalloc(2 * (len + 1), GFP_KERNEL);
+					cifs_strfromUCS_le(ses->serverOS,
+							   (wchar_t *)bcc_ptr, len,nls_codepage);
+					bcc_ptr += 2 * (len + 1);
+					remaining_words -= len + 1;
+					ses->serverOS[2 * len] = 0;
+					ses->serverOS[1 + (2 * len)] = 0;
+					if (remaining_words > 0) {
+						len = UniStrnlen((wchar_t *)bcc_ptr,
+								 remaining_words
+								 - 1);
+						ses->serverNOS =kcalloc(2 * (len + 1),GFP_KERNEL);
+						cifs_strfromUCS_le(ses->serverNOS,
+								   (wchar_t *)bcc_ptr,len,nls_codepage);
+						bcc_ptr += 2 * (len + 1);
+						ses->serverNOS[2 * len] = 0;
+						ses->serverNOS[1 + (2 * len)] = 0;
+						remaining_words -= len + 1;
+						if (remaining_words > 0) {
+							len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
+          /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+							ses->serverDomain =
+							    kcalloc(2*(len+1),GFP_KERNEL);
+							cifs_strfromUCS_le(ses->serverDomain,
+							     (wchar_t *)bcc_ptr,len,nls_codepage);
+							bcc_ptr += 2 * (len + 1);
+							ses->serverDomain[2*len] = 0;
+							ses->serverDomain[1+(2*len)] = 0;
+						} /* else no more room so create dummy domain string */
+						else
+							ses->serverDomain =
+							    kcalloc(2,
+								    GFP_KERNEL);
+					} else {	/* no room so create dummy domain and NOS string */
+						ses->serverDomain =
+						    kcalloc(2, GFP_KERNEL);
+						ses->serverNOS =
+						    kcalloc(2, GFP_KERNEL);
+					}
+				} else {	/* ASCII */
+
+					len = strnlen(bcc_ptr, 1024);
+					if (((int) bcc_ptr + len) - (int)
+					    pByteArea(smb_buffer_response)
+					    <= BCC(smb_buffer_response)) {
+						ses->serverOS = kcalloc(len + 1,GFP_KERNEL);
+						strncpy(ses->serverOS,bcc_ptr, len);
+
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;	/* null terminate the string */
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverNOS = kcalloc(len + 1,GFP_KERNEL);
+						strncpy(ses->serverNOS, bcc_ptr, len);
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverDomain = kcalloc(len + 1,GFP_KERNEL);
+						strncpy(ses->serverDomain, bcc_ptr, len);
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+					} else
+						cFYI(1,
+						     ("Variable field of length %d extends beyond end of smb ",
+						      len));
+				}
+			} else {
+				cERROR(1,
+				       (" Security Blob Length extends beyond end of SMB"));
+			}
+		} else {
+			cERROR(1, ("No session structure passed in."));
+		}
+	} else {
+		cERROR(1,
+		       (" Invalid Word count %d: ",
+			smb_buffer_response->WordCount));
+		rc = -EIO;
+	}
+	
+	if (smb_buffer)
+		buf_release(smb_buffer);
+
+	return rc;
+}
+
+int
+CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
+		    char *user, char *domain, char *SecurityBlob,
+		    int SecurityBlobLength,
+		    const struct nls_table *nls_codepage)
+{
+	struct smb_hdr *smb_buffer;
+	struct smb_hdr *smb_buffer_response;
+	SESSION_SETUP_ANDX *pSMB;
+	SESSION_SETUP_ANDX *pSMBr;
+	char *bcc_ptr;
+	int rc = 0;
+	int remaining_words = 0;
+	int bytes_returned = 0;
+	int len;
+
+	cFYI(1, ("\nIn v2 sesssetup "));
+
+	smb_buffer = buf_get();
+	if (smb_buffer == 0) {
+		return -ENOMEM;
+	}
+	smb_buffer_response = smb_buffer;
+	pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+
+	/* send SMBsessionSetup here */
+	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+			0 /* no tCon exists yet */ , 12 /* wct */ );
+	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+	pSMB->req.AndXCommand = 0xFF;
+	pSMB->req.MaxBufferSize = cpu_to_le16(ses->maxBuf);
+	pSMB->req.MaxMpxCount = cpu_to_le16(ses->maxReq);
+
+    if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+        smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	pSMB->req.Capabilities =
+	    CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+	    CAP_EXTENDED_SECURITY;
+	if (ses->capabilities & CAP_UNICODE) {
+		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+		pSMB->req.Capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+		pSMB->req.Capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		smb_buffer->Flags2 |= SMBFLG2_DFS;
+		pSMB->req.Capabilities |= CAP_DFS;
+	}
+	pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+
+	pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
+	bcc_ptr = pByteArea(smb_buffer);
+	memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
+	bcc_ptr += SecurityBlobLength;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		if ((int) bcc_ptr % 2) {	/* must be word aligned for Unicode strings */
+			*bcc_ptr = 0;
+			bcc_ptr++;
+		}
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;	/* convert num of 16 bit words to bytes */
+		bcc_ptr += 2;	/* trailing null */
+		if (domain == NULL)
+			bytes_returned =
+			    cifs_strtoUCS((wchar_t *) bcc_ptr,
+					  "CIFS_LINUX_DOM", 32, nls_codepage);
+		else
+			bytes_returned =
+			    cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+					  nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+				  32, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+				  nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+				  64, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;
+	} else {
+		strncpy(bcc_ptr, user, 200);
+		bcc_ptr += strnlen(user, 200);
+		*bcc_ptr = 0;
+		bcc_ptr++;
+		if (domain == NULL) {
+			strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+			bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
+		} else {
+			strncpy(bcc_ptr, domain, 64);
+			bcc_ptr += strnlen(domain, 64);
+			*bcc_ptr = 0;
+			bcc_ptr++;
+		}
+		strcpy(bcc_ptr, "Linux version ");
+		bcc_ptr += strlen("Linux version ");
+		strcpy(bcc_ptr, UTS_RELEASE);
+		bcc_ptr += strlen(UTS_RELEASE) + 1;
+		strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+		bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+	}
+	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	smb_buffer->smb_buf_length += BCC(smb_buffer);
+	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+			 &bytes_returned, 1);
+	/* dump_mem("\nSessSetup response is: ", smb_buffer_response, 92);  */
+	if (rc) {
+/*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
+	} else if ((smb_buffer_response->WordCount == 3)
+		   || (smb_buffer_response->WordCount == 4)) {
+		pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+		pSMBr->resp.SecurityBlobLength =
+		    le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+		if (pSMBr->resp.Action & GUEST_LOGIN)
+			cFYI(1, (" Guest login"));	/* BB do we want to set anything in SesInfo struct ? */
+		if (ses) {
+			ses->Suid = smb_buffer_response->Uid;	/* UID left in wire format (le) */
+			cFYI(1, ("UID = %d ", ses->Suid));
+			bcc_ptr = pByteArea(smb_buffer_response);	/* response can have either 3 or 4 word count - Samba sends 3 */
+
+			/* BB Fix below to make endian neutral !! */
+
+			if ((pSMBr->resp.hdr.WordCount == 3)
+			    || ((pSMBr->resp.hdr.WordCount == 4)
+				&& (pSMBr->resp.SecurityBlobLength <
+				    pSMBr->resp.ByteCount))) {
+				if (pSMBr->resp.hdr.WordCount == 4) {
+					bcc_ptr +=
+					    pSMBr->resp.SecurityBlobLength;
+					cFYI(1,
+					     ("\nSecurity Blob Length %d ",
+					      pSMBr->resp.SecurityBlobLength));
+				}
+
+				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+					if ((int) (bcc_ptr) % 2) {
+						remaining_words =
+						    (BCC(smb_buffer_response)
+						     - 1) / 2;
+						bcc_ptr++;	/* Unicode strings must be word aligned */
+					} else {
+						remaining_words =
+						    BCC
+						    (smb_buffer_response) / 2;
+					}
+					len =
+					    UniStrnlen((wchar_t *) bcc_ptr,
+						       remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+   the end since (at least) WIN2K and Windows XP have a major bug in not null
+   terminating last Unicode string in response  */
+					ses->serverOS =
+					    kcalloc(2 * (len + 1), GFP_KERNEL);
+					cifs_strfromUCS_le(ses->serverOS,
+							   (wchar_t *)
+							   bcc_ptr, len,
+							   nls_codepage);
+					bcc_ptr += 2 * (len + 1);
+					remaining_words -= len + 1;
+					ses->serverOS[2 * len] = 0;
+					ses->serverOS[1 + (2 * len)] = 0;
+					if (remaining_words > 0) {
+						len = UniStrnlen((wchar_t *)bcc_ptr,
+								 remaining_words
+								 - 1);
+						ses->serverNOS =
+						    kcalloc(2 * (len + 1),
+							    GFP_KERNEL);
+						cifs_strfromUCS_le(ses->serverNOS,
+								   (wchar_t *)bcc_ptr,
+								   len,
+								   nls_codepage);
+						bcc_ptr += 2 * (len + 1);
+						ses->serverNOS[2 * len] = 0;
+						ses->serverNOS[1 + (2 * len)] = 0;
+						remaining_words -= len + 1;
+						if (remaining_words > 0) {
+							len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
+                            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+							ses->serverDomain = kcalloc(2*(len+1),GFP_KERNEL);
+							cifs_strfromUCS_le(ses->serverDomain,
+							     (wchar_t *)bcc_ptr, 
+                                 len,
+							     nls_codepage);
+							bcc_ptr += 2*(len+1);
+							ses->serverDomain[2*len] = 0;
+							ses->serverDomain[1+(2*len)] = 0;
+						} /* else no more room so create dummy domain string */
+						else
+							ses->serverDomain =
+							    kcalloc(2,GFP_KERNEL);
+					} else {	/* no room so create dummy domain and NOS string */
+						ses->serverDomain = kcalloc(2, GFP_KERNEL);
+						ses->serverNOS = kcalloc(2, GFP_KERNEL);
+					}
+				} else {	/* ASCII */
+
+					len = strnlen(bcc_ptr, 1024);
+					if (((int) bcc_ptr + len) - (int)
+					    pByteArea(smb_buffer_response)
+					    <= BCC(smb_buffer_response)) {
+						ses->serverOS = kcalloc(len + 1, GFP_KERNEL);
+						strncpy(ses->serverOS, bcc_ptr, len);
+
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;	/* null terminate the string */
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverNOS = kcalloc(len + 1,GFP_KERNEL);
+						strncpy(ses->serverNOS, bcc_ptr, len);
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverDomain = kcalloc(len + 1, GFP_KERNEL);
+						strncpy(ses->serverDomain, bcc_ptr, len);
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+					} else
+						cFYI(1,
+						     ("Variable field of length %d extends beyond end of smb ",
+						      len));
+				}
+			} else {
+				cERROR(1,
+				       (" Security Blob Length extends beyond end of SMB"));
+			}
+		} else {
+			cERROR(1, ("No session structure passed in."));
+		}
+	} else {
+		cERROR(1,
+		       (" Invalid Word count %d: ",
+			smb_buffer_response->WordCount));
+		rc = -EIO;
+	}
+
+	if (smb_buffer)
+		buf_release(smb_buffer);
+
+	return rc;
+}
+
+int
+CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
+			      struct cifsSesInfo *ses,
+			      char *challenge_from_server,
+			      char *domain, int * pNTLMv2_flag,
+			      const struct nls_table *nls_codepage)
+{
+	struct smb_hdr *smb_buffer;
+	struct smb_hdr *smb_buffer_response;
+	SESSION_SETUP_ANDX *pSMB;
+	SESSION_SETUP_ANDX *pSMBr;
+	char *bcc_ptr;
+	int rc = 0;
+	int remaining_words = 0;
+	int bytes_returned = 0;
+	int len;
+	int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
+	PNEGOTIATE_MESSAGE SecurityBlob;
+	PCHALLENGE_MESSAGE SecurityBlob2;
+
+	cFYI(1, ("\nIn NTLMSSP sesssetup (negotiate) "));
+    *pNTLMv2_flag = FALSE;
+	smb_buffer = buf_get();
+	if (smb_buffer == 0) {
+		return -ENOMEM;
+	}
+	smb_buffer_response = smb_buffer;
+	pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+	pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
+
+	/* send SMBsessionSetup here */
+	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+			0 /* no tCon exists yet */ , 12 /* wct */ );
+	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+	pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
+
+	pSMB->req.AndXCommand = 0xFF;
+	pSMB->req.MaxBufferSize = cpu_to_le16(ses->maxBuf);
+	pSMB->req.MaxMpxCount = cpu_to_le16(ses->maxReq);
+
+    if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+        smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	pSMB->req.Capabilities =
+	    CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+	    CAP_EXTENDED_SECURITY;
+	if (ses->capabilities & CAP_UNICODE) {
+		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+		pSMB->req.Capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+		pSMB->req.Capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		smb_buffer->Flags2 |= SMBFLG2_DFS;
+		pSMB->req.Capabilities |= CAP_DFS;
+	}
+	pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+
+	bcc_ptr = (char *) &pSMB->req.SecurityBlob;
+	SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
+	strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
+	SecurityBlob->MessageType = NtLmNegotiate;
+	SecurityBlob->NegotiateFlags =
+	    NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
+	    NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
+	    NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_128;
+    if(ntlmv2_support)
+        SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+	/* setup pointers to domain name and workstation name */
+	bcc_ptr += SecurityBlobLength;
+
+	SecurityBlob->WorkstationName.Buffer = 0;
+	SecurityBlob->WorkstationName.Length = 0;
+	SecurityBlob->WorkstationName.MaximumLength = 0;
+
+	if (domain == NULL) {
+		SecurityBlob->DomainName.Buffer = 0;
+		SecurityBlob->DomainName.Length = 0;
+		SecurityBlob->DomainName.MaximumLength = 0;
+	} else {
+		SecurityBlob->NegotiateFlags |=
+		    NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
+		strncpy(bcc_ptr, domain, 63);
+		SecurityBlob->DomainName.Length = strnlen(domain, 64);
+		SecurityBlob->DomainName.MaximumLength =
+		    cpu_to_le16(SecurityBlob->DomainName.Length);
+		SecurityBlob->DomainName.Buffer =
+		    cpu_to_le32((unsigned int) &SecurityBlob->
+				DomainString -
+				(unsigned int) &SecurityBlob->Signature);
+		bcc_ptr += SecurityBlob->DomainName.Length;
+		SecurityBlobLength += SecurityBlob->DomainName.Length;
+		SecurityBlob->DomainName.Length =
+		    cpu_to_le16(SecurityBlob->DomainName.Length);
+	}
+	if (ses->capabilities & CAP_UNICODE) {
+		if ((int) bcc_ptr % 2) {
+			*bcc_ptr = 0;
+			bcc_ptr++;
+		}
+
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+				  32, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+				  nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;	/* null terminate Linux version */
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+				  64, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		*(bcc_ptr + 1) = 0;
+		*(bcc_ptr + 2) = 0;
+		bcc_ptr += 2;	/* null terminate network opsys string */
+		*(bcc_ptr + 1) = 0;
+		*(bcc_ptr + 2) = 0;
+		bcc_ptr += 2;	/* null domain */
+	} else {		/* ASCII */
+		strcpy(bcc_ptr, "Linux version ");
+		bcc_ptr += strlen("Linux version ");
+		strcpy(bcc_ptr, UTS_RELEASE);
+		bcc_ptr += strlen(UTS_RELEASE) + 1;
+		strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+		bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+		bcc_ptr++;	/* empty domain field */
+		*bcc_ptr = 0;
+	}
+	SecurityBlob->NegotiateFlags =
+	    cpu_to_le32(SecurityBlob->NegotiateFlags);
+	pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
+	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	smb_buffer->smb_buf_length += BCC(smb_buffer);
+	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+			 &bytes_returned, 1);
+
+	if (smb_buffer_response->Status.CifsError ==
+	    (NT_STATUS_MORE_PROCESSING_REQUIRED))
+		rc = 0;
+
+	if (rc) {
+/*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
+	} else if ((smb_buffer_response->WordCount == 3)
+		   || (smb_buffer_response->WordCount == 4)) {
+		pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+		pSMBr->resp.SecurityBlobLength =
+		    le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+		if (pSMBr->resp.Action & GUEST_LOGIN)
+			cFYI(1, (" Guest login"));	
+        /* Do we want to set anything in SesInfo struct when guest login? */
+
+		bcc_ptr = pByteArea(smb_buffer_response);	
+        /* response can have either 3 or 4 word count - Samba sends 3 */
+
+		SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
+		if (SecurityBlob2->MessageType != NtLmChallenge) {
+			cFYI(1,
+			     ("\nUnexpected NTLMSSP message type received %d",
+			      SecurityBlob2->MessageType));
+		} else if (ses) {
+			ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
+			cFYI(1, ("UID = %d ", ses->Suid));
+			if ((pSMBr->resp.hdr.WordCount == 3)
+			    || ((pSMBr->resp.hdr.WordCount == 4)
+				&& (pSMBr->resp.SecurityBlobLength <
+				    pSMBr->resp.ByteCount))) {
+				if (pSMBr->resp.hdr.WordCount == 4) {
+					bcc_ptr +=
+					    pSMBr->resp.SecurityBlobLength;
+					cFYI(1,
+					     ("\nSecurity Blob Length %d ",
+					      pSMBr->resp.SecurityBlobLength));
+				}
+
+				cFYI(1, ("\nNTLMSSP Challenge rcvd "));
+
+				memcpy(challenge_from_server,
+				       SecurityBlob2->Challenge,
+				       CIFS_CRYPTO_KEY_SIZE);
+                if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
+                    *pNTLMv2_flag = TRUE;
+				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+					if ((int) (bcc_ptr) % 2) {
+						remaining_words =
+						    (BCC(smb_buffer_response)
+						     - 1) / 2;
+						bcc_ptr++;	/* Unicode strings must be word aligned */
+					} else {
+						remaining_words =
+						    BCC
+						    (smb_buffer_response) / 2;
+					}
+					len =
+					    UniStrnlen((wchar_t *) bcc_ptr,
+						       remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+   the end since (at least) WIN2K and Windows XP have a major bug in not null
+   terminating last Unicode string in response  */
+					ses->serverOS =
+					    kcalloc(2 * (len + 1), GFP_KERNEL);
+					cifs_strfromUCS_le(ses->serverOS,
+							   (wchar_t *)
+							   bcc_ptr, len,
+							   nls_codepage);
+					bcc_ptr += 2 * (len + 1);
+					remaining_words -= len + 1;
+					ses->serverOS[2 * len] = 0;
+					ses->serverOS[1 + (2 * len)] = 0;
+					if (remaining_words > 0) {
+						len = UniStrnlen((wchar_t *)
+								 bcc_ptr,
+								 remaining_words
+								 - 1);
+						ses->serverNOS =
+						    kcalloc(2 * (len + 1),
+							    GFP_KERNEL);
+						cifs_strfromUCS_le(ses->
+								   serverNOS,
+								   (wchar_t *)
+								   bcc_ptr,
+								   len,
+								   nls_codepage);
+						bcc_ptr += 2 * (len + 1);
+						ses->serverNOS[2 * len] = 0;
+						ses->serverNOS[1 +
+							       (2 * len)] = 0;
+						remaining_words -= len + 1;
+						if (remaining_words > 0) {
+							len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
+           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+							ses->serverDomain =
+							    kcalloc(2 *
+								    (len +
+								     1),
+								    GFP_KERNEL);
+							cifs_strfromUCS_le
+							    (ses->
+							     serverDomain,
+							     (wchar_t *)
+							     bcc_ptr, len,
+							     nls_codepage);
+							bcc_ptr +=
+							    2 * (len + 1);
+							ses->
+							    serverDomain[2
+									 * len]
+							    = 0;
+							ses->
+							    serverDomain[1
+									 +
+									 (2
+									  *
+									  len)]
+							    = 0;
+						} /* else no more room so create dummy domain string */
+						else
+							ses->serverDomain =
+							    kcalloc(2,
+								    GFP_KERNEL);
+					} else {	/* no room so create dummy domain and NOS string */
+						ses->serverDomain =
+						    kcalloc(2, GFP_KERNEL);
+						ses->serverNOS =
+						    kcalloc(2, GFP_KERNEL);
+					}
+				} else {	/* ASCII */
+
+					len = strnlen(bcc_ptr, 1024);
+					if (((int) bcc_ptr + len) - (int)
+					    pByteArea(smb_buffer_response)
+					    <= BCC(smb_buffer_response)) {
+						ses->serverOS =
+						    kcalloc(len + 1,
+							    GFP_KERNEL);
+						strncpy(ses->serverOS,
+							bcc_ptr, len);
+
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;	/* null terminate string */
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverNOS =
+						    kcalloc(len + 1,
+							    GFP_KERNEL);
+						strncpy(ses->serverNOS, bcc_ptr, len);
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverDomain =
+						    kcalloc(len + 1,
+							    GFP_KERNEL);
+						strncpy(ses->serverDomain, bcc_ptr, len);	
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+					} else
+						cFYI(1,
+						     ("Variable field of length %d extends beyond end of smb ",
+						      len));
+				}
+			} else {
+				cERROR(1,
+				       (" Security Blob Length extends beyond end of SMB"));
+			}
+		} else {
+			cERROR(1, ("No session structure passed in."));
+		}
+	} else {
+		cERROR(1,
+		       (" Invalid Word count %d: ",
+			smb_buffer_response->WordCount));
+		rc = -EIO;
+	}
+
+	if (smb_buffer)
+		buf_release(smb_buffer);
+
+	return rc;
+}
+
+int
+CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
+			 char *user, char *domain,
+			 char *ntlm_session_key,
+			 char *lanman_session_key, int ntlmv2_flag,
+			 const struct nls_table *nls_codepage)
+{
+	struct smb_hdr *smb_buffer;
+	struct smb_hdr *smb_buffer_response;
+	SESSION_SETUP_ANDX *pSMB;
+	SESSION_SETUP_ANDX *pSMBr;
+	char *bcc_ptr;
+	int rc = 0;
+	int remaining_words = 0;
+	int bytes_returned = 0;
+	int len;
+	int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
+	PAUTHENTICATE_MESSAGE SecurityBlob;
+
+	cFYI(1, ("\nIn NTLMSSPSessSetup (Authenticate)"));
+
+	smb_buffer = buf_get();
+	if (smb_buffer == 0) {
+		return -ENOMEM;
+	}
+	smb_buffer_response = smb_buffer;
+	pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
+	pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
+
+	/* send SMBsessionSetup here */
+	header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
+			0 /* no tCon exists yet */ , 12 /* wct */ );
+	pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
+	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+	pSMB->req.AndXCommand = 0xFF;
+	pSMB->req.MaxBufferSize = cpu_to_le16(ses->maxBuf);
+	pSMB->req.MaxMpxCount = cpu_to_le16(ses->maxReq);
+
+	pSMB->req.hdr.Uid = ses->Suid;
+
+    if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+        smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	pSMB->req.Capabilities =
+	    CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+	    CAP_EXTENDED_SECURITY;
+	if (ses->capabilities & CAP_UNICODE) {
+		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+		pSMB->req.Capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+		pSMB->req.Capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		smb_buffer->Flags2 |= SMBFLG2_DFS;
+		pSMB->req.Capabilities |= CAP_DFS;
+	}
+	pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
+
+	bcc_ptr = (char *) &pSMB->req.SecurityBlob;
+	SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
+	strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
+	SecurityBlob->MessageType = NtLmAuthenticate;
+	bcc_ptr += SecurityBlobLength;
+	SecurityBlob->NegotiateFlags =
+	    NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
+	    NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
+	    0x80000000 | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_128;
+    if(ntlmv2_flag)
+        SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
+
+/* setup pointers to domain name and workstation name */
+
+	SecurityBlob->WorkstationName.Buffer = 0;
+	SecurityBlob->WorkstationName.Length = 0;
+	SecurityBlob->WorkstationName.MaximumLength = 0;
+	SecurityBlob->SessionKey.Length = 0;
+	SecurityBlob->SessionKey.MaximumLength = 0;
+	SecurityBlob->SessionKey.Buffer = 0;
+
+	SecurityBlob->LmChallengeResponse.Length = 0;
+	SecurityBlob->LmChallengeResponse.MaximumLength = 0;
+	SecurityBlob->LmChallengeResponse.Buffer = 0;
+
+	SecurityBlob->NtChallengeResponse.Length =
+	    cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+	SecurityBlob->NtChallengeResponse.MaximumLength =
+	    cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+	memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+	SecurityBlob->NtChallengeResponse.Buffer =
+	    cpu_to_le32(SecurityBlobLength);
+	SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
+	bcc_ptr += CIFS_SESSION_KEY_SIZE;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		if (domain == NULL) {
+			SecurityBlob->DomainName.Buffer = 0;
+			SecurityBlob->DomainName.Length = 0;
+			SecurityBlob->DomainName.MaximumLength = 0;
+		} else {
+			SecurityBlob->DomainName.Length =
+			    cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
+					  nls_codepage);
+			SecurityBlob->DomainName.Length *= 2;
+			SecurityBlob->DomainName.MaximumLength =
+			    cpu_to_le16(SecurityBlob->DomainName.Length);
+			SecurityBlob->DomainName.Buffer =
+			    cpu_to_le32(SecurityBlobLength);
+			bcc_ptr += SecurityBlob->DomainName.Length;
+			SecurityBlobLength += SecurityBlob->DomainName.Length;
+			SecurityBlob->DomainName.Length =
+			    cpu_to_le16(SecurityBlob->DomainName.Length);
+		}
+		if (user == NULL) {
+			SecurityBlob->UserName.Buffer = 0;
+			SecurityBlob->UserName.Length = 0;
+			SecurityBlob->UserName.MaximumLength = 0;
+		} else {
+			SecurityBlob->UserName.Length =
+			    cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
+					  nls_codepage);
+			SecurityBlob->UserName.Length *= 2;
+			SecurityBlob->UserName.MaximumLength =
+			    cpu_to_le16(SecurityBlob->UserName.Length);
+			SecurityBlob->UserName.Buffer =
+			    cpu_to_le32(SecurityBlobLength);
+			bcc_ptr += SecurityBlob->UserName.Length;
+			SecurityBlobLength += SecurityBlob->UserName.Length;
+			SecurityBlob->UserName.Length =
+			    cpu_to_le16(SecurityBlob->UserName.Length);
+		}
+
+		/* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
+		   SecurityBlob->WorkstationName.Length *= 2;
+		   SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
+		   SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
+		   bcc_ptr += SecurityBlob->WorkstationName.Length;
+		   SecurityBlobLength += SecurityBlob->WorkstationName.Length;
+		   SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
+
+		if ((int) bcc_ptr % 2) {
+			*bcc_ptr = 0;
+			bcc_ptr++;
+		}
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
+				  32, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+				  nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		bcc_ptr += 2;	/* null term version string */
+		bytes_returned =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
+				  64, nls_codepage);
+		bcc_ptr += 2 * bytes_returned;
+		*(bcc_ptr + 1) = 0;
+		*(bcc_ptr + 2) = 0;
+		bcc_ptr += 2;	/* null terminate network opsys string */
+		*(bcc_ptr + 1) = 0;
+		*(bcc_ptr + 2) = 0;
+		bcc_ptr += 2;	/* null domain */
+	} else {		/* ASCII */
+		if (domain == NULL) {
+			SecurityBlob->DomainName.Buffer = 0;
+			SecurityBlob->DomainName.Length = 0;
+			SecurityBlob->DomainName.MaximumLength = 0;
+		} else {
+			SecurityBlob->NegotiateFlags |=
+			    NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
+			strncpy(bcc_ptr, domain, 63);
+			SecurityBlob->DomainName.Length = strnlen(domain, 64);
+			SecurityBlob->DomainName.MaximumLength =
+			    cpu_to_le16(SecurityBlob->DomainName.Length);
+			SecurityBlob->DomainName.Buffer =
+			    cpu_to_le32(SecurityBlobLength);
+			bcc_ptr += SecurityBlob->DomainName.Length;
+			SecurityBlobLength += SecurityBlob->DomainName.Length;
+			SecurityBlob->DomainName.Length =
+			    cpu_to_le16(SecurityBlob->DomainName.Length);
+		}
+		if (user == NULL) {
+			SecurityBlob->UserName.Buffer = 0;
+			SecurityBlob->UserName.Length = 0;
+			SecurityBlob->UserName.MaximumLength = 0;
+		} else {
+			strncpy(bcc_ptr, user, 63);
+			SecurityBlob->UserName.Length = strnlen(user, 64);
+			SecurityBlob->UserName.MaximumLength =
+			    cpu_to_le16(SecurityBlob->UserName.Length);
+			SecurityBlob->UserName.Buffer =
+			    cpu_to_le32(SecurityBlobLength);
+			bcc_ptr += SecurityBlob->UserName.Length;
+			SecurityBlobLength += SecurityBlob->UserName.Length;
+			SecurityBlob->UserName.Length =
+			    cpu_to_le16(SecurityBlob->UserName.Length);
+		}
+		/* BB fill in our workstation name if known BB */
+
+		strcpy(bcc_ptr, "Linux version ");
+		bcc_ptr += strlen("Linux version ");
+		strcpy(bcc_ptr, UTS_RELEASE);
+		bcc_ptr += strlen(UTS_RELEASE) + 1;
+		strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
+		bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
+		bcc_ptr++;	/* null domain */
+		*bcc_ptr = 0;
+	}
+	SecurityBlob->NegotiateFlags =
+	    cpu_to_le32(SecurityBlob->NegotiateFlags);
+	pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
+	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	smb_buffer->smb_buf_length += BCC(smb_buffer);
+	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
+			 &bytes_returned, 1);
+	if (rc) {
+/*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
+	} else if ((smb_buffer_response->WordCount == 3)
+		   || (smb_buffer_response->WordCount == 4)) {
+		pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
+		pSMBr->resp.SecurityBlobLength =
+		    le16_to_cpu(pSMBr->resp.SecurityBlobLength);
+		if (pSMBr->resp.Action & GUEST_LOGIN)
+			cFYI(1, (" Guest login"));	/* BB do we want to set anything in SesInfo struct ? */
+/*        if(SecurityBlob2->MessageType != NtLm??){                               
+                 cFYI("\nUnexpected message type on auth response is %d ")); 
+        } */
+		if (ses) {
+			cFYI(1,
+			     ("Does UID on challenge %d match auth response UID %d ",
+			      ses->Suid, smb_buffer_response->Uid));
+			ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
+			bcc_ptr = pByteArea(smb_buffer_response);	
+            /* response can have either 3 or 4 word count - Samba sends 3 */
+			if ((pSMBr->resp.hdr.WordCount == 3)
+			    || ((pSMBr->resp.hdr.WordCount == 4)
+				&& (pSMBr->resp.SecurityBlobLength <
+				    pSMBr->resp.ByteCount))) {
+				if (pSMBr->resp.hdr.WordCount == 4) {
+					bcc_ptr +=
+					    pSMBr->resp.SecurityBlobLength;
+					cFYI(1,
+					     ("\nSecurity Blob Length %d ",
+					      pSMBr->resp.SecurityBlobLength));
+				}
+
+				cFYI(1,
+				     ("\nNTLMSSP response to Authenticate "));
+
+				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+					if ((int) (bcc_ptr) % 2) {
+						remaining_words =
+						    (BCC(smb_buffer_response)
+						     - 1) / 2;
+						bcc_ptr++;	/* Unicode strings must be word aligned */
+					} else {
+						remaining_words = BCC(smb_buffer_response) / 2;
+					}
+					len =
+					    UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
+/* We look for obvious messed up bcc or strings in response so we do not go off
+  the end since (at least) WIN2K and Windows XP have a major bug in not null
+  terminating last Unicode string in response  */
+					ses->serverOS =
+					    kcalloc(2 * (len + 1), GFP_KERNEL);
+					cifs_strfromUCS_le(ses->serverOS,
+							   (wchar_t *)
+							   bcc_ptr, len,
+							   nls_codepage);
+					bcc_ptr += 2 * (len + 1);
+					remaining_words -= len + 1;
+					ses->serverOS[2 * len] = 0;
+					ses->serverOS[1 + (2 * len)] = 0;
+					if (remaining_words > 0) {
+						len = UniStrnlen((wchar_t *)
+								 bcc_ptr,
+								 remaining_words
+								 - 1);
+						ses->serverNOS =
+						    kcalloc(2 * (len + 1),
+							    GFP_KERNEL);
+						cifs_strfromUCS_le(ses->
+								   serverNOS,
+								   (wchar_t *)
+								   bcc_ptr,
+								   len,
+								   nls_codepage);
+						bcc_ptr += 2 * (len + 1);
+						ses->serverNOS[2 * len] = 0;
+						ses->serverNOS[1+(2*len)] = 0;
+						remaining_words -= len + 1;
+						if (remaining_words > 0) {
+							len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);	
+     /* last string not always null terminated (e.g. for Windows XP & 2000) */
+							ses->serverDomain =
+							    kcalloc(2 *
+								    (len +
+								     1),
+								    GFP_KERNEL);
+							cifs_strfromUCS_le
+							    (ses->
+							     serverDomain,
+							     (wchar_t *)
+							     bcc_ptr, len,
+							     nls_codepage);
+							bcc_ptr +=
+							    2 * (len + 1);
+							ses->
+							    serverDomain[2
+									 * len]
+							    = 0;
+							ses->
+							    serverDomain[1
+									 +
+									 (2
+									  *
+									  len)]
+							    = 0;
+						} /* else no more room so create dummy domain string */
+						else
+							ses->serverDomain = kcalloc(2,GFP_KERNEL);
+					} else {  /* no room so create dummy domain and NOS string */
+						ses->serverDomain = kcalloc(2, GFP_KERNEL);
+						ses->serverNOS = kcalloc(2, GFP_KERNEL);
+					}
+				} else {	/* ASCII */
+
+					len = strnlen(bcc_ptr, 1024);
+					if (((int) bcc_ptr + len) - 
+                        (int) pByteArea(smb_buffer_response) 
+                            <= BCC(smb_buffer_response)) {
+						ses->serverOS = kcalloc(len + 1,GFP_KERNEL);
+						strncpy(ses->serverOS,bcc_ptr, len);
+
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;	/* null terminate the string */
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverNOS = kcalloc(len+1,GFP_KERNEL);
+						strncpy(ses->serverNOS, bcc_ptr, len);	
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+
+						len = strnlen(bcc_ptr, 1024);
+						ses->serverDomain = kcalloc(len+1,GFP_KERNEL);
+						strncpy(ses->serverDomain, bcc_ptr, len);
+						bcc_ptr += len;
+						bcc_ptr[0] = 0;
+						bcc_ptr++;
+					} else
+						cFYI(1,
+						     ("Variable field of length %d extends beyond end of smb ",
+						      len));
+				}
+			} else {
+				cERROR(1,
+				       (" Security Blob Length extends beyond end of SMB"));
+			}
+		} else {
+			cERROR(1, ("No session structure passed in."));
+		}
+	} else {
+		cERROR(1,
+		       (" Invalid Word count %d: ",
+			smb_buffer_response->WordCount));
+		rc = -EIO;
+	}
+
+	if (smb_buffer)
+		buf_release(smb_buffer);
+
+	return rc;
+}
+
+int
+CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
+	 const char *tree, struct cifsTconInfo *tcon,
+	 const struct nls_table *nls_codepage)
+{
+	struct smb_hdr *smb_buffer;
+	struct smb_hdr *smb_buffer_response;
+	TCONX_REQ *pSMB;
+	TCONX_RSP *pSMBr;
+	char *bcc_ptr;
+	int rc = 0;
+	int length;
+
+	if (ses == NULL)
+		return -EIO;
+
+	smb_buffer = buf_get();
+	if (smb_buffer == 0) {
+		return -ENOMEM;
+	}
+	smb_buffer_response = smb_buffer;
+
+	header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
+			0 /*no tid */ , 4 /*wct */ );
+	smb_buffer->Uid = ses->Suid;
+	pSMB = (TCONX_REQ *) smb_buffer;
+	pSMBr = (TCONX_RSP *) smb_buffer_response;
+
+	pSMB->AndXCommand = 0xFF;
+	pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
+	pSMB->PasswordLength = cpu_to_le16(1);	/* minimum */
+	bcc_ptr = &(pSMB->Password[0]);
+	bcc_ptr++;		/* skip password */
+
+    if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+        smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	if (ses->capabilities & CAP_STATUS32) {
+		smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		smb_buffer->Flags2 |= SMBFLG2_DFS;
+	}
+	if (ses->capabilities & CAP_UNICODE) {
+		smb_buffer->Flags2 |= SMBFLG2_UNICODE;
+		length =
+		    cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
+		bcc_ptr += 2 * length;	/* convert num of 16 bit words to bytes */
+		bcc_ptr += 2;	/* skip trailing null */
+	} else {		/* ASCII */
+
+		strcpy(bcc_ptr, tree);
+		bcc_ptr += strlen(tree) + 1;
+	}
+	strcpy(bcc_ptr, "?????");
+	bcc_ptr += strlen("?????");
+	bcc_ptr += 1;
+	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	smb_buffer->smb_buf_length += BCC(smb_buffer);
+	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
+
+	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
+
+	/* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
+    /* above now done in SendReceive */
+	if ((rc == 0) && (tcon != NULL)) {
+		tcon->tid = smb_buffer_response->Tid;
+		bcc_ptr = pByteArea(smb_buffer_response);
+		length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
+        /* skip service field (NB: this field is always ASCII) */
+		bcc_ptr += length + 1;	
+        strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
+		if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
+			length = UniStrnlen((wchar_t *) bcc_ptr, 512);
+			if (((int) bcc_ptr + (2 * length)) -
+			    (int) pByteArea(smb_buffer_response) <=
+			    BCC(smb_buffer_response)) {
+				tcon->nativeFileSystem =
+				    kcalloc(length + 2, GFP_KERNEL);
+				cifs_strfromUCS_le(tcon->nativeFileSystem,
+						   (wchar_t *) bcc_ptr,
+						   length, nls_codepage);
+				bcc_ptr += 2 * length;
+				bcc_ptr[0] = 0;	/* null terminate the string */
+				bcc_ptr[1] = 0;
+				bcc_ptr += 2;
+			}
+			/* else do not bother copying these informational fields */
+		} else {
+			length = strnlen(bcc_ptr, 1024);
+			if (((int) bcc_ptr + length) -
+			    (int) pByteArea(smb_buffer_response) <=
+			    BCC(smb_buffer_response)) {
+				tcon->nativeFileSystem =
+				    kcalloc(length + 1, GFP_KERNEL);
+				strncpy(tcon->nativeFileSystem, bcc_ptr,
+					length);
+			}
+			/* else do not bother copying these informational fields */
+		}
+		tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+		cFYI(1, ("\nTcon flags: 0x%x ", tcon->Flags));
+	} else if ((rc == 0) && tcon == NULL) {
+        /* all we need to save for IPC$ connection */
+		ses->ipc_tid = smb_buffer_response->Tid;
+	}
+
+	if (smb_buffer)
+		buf_release(smb_buffer);
+	return rc;
+}
+
+int
+cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
+{
+	int rc = 0;
+	int xid;
+	struct cifsSesInfo *ses = NULL;
+
+	xid = GetXid();
+	if (cifs_sb->tcon) {
+		ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
+		rc = CIFSSMBTDis(xid, cifs_sb->tcon);
+		if (rc == -EBUSY) {
+			FreeXid(xid);
+			return 0;
+		}
+		tconInfoFree(cifs_sb->tcon);
+		if ((ses) && (ses->server)) {
+			cFYI(1, ("\nAbout to do SMBLogoff "));
+			rc = CIFSSMBLogoff(xid, ses);
+			if (rc == -EBUSY) {
+				/* BB this looks wrong - why is this here? */
+				FreeXid(xid);
+				return 0;
+			}
+    	 /* wake_up_process(ses->server->tsk);*/ /* was worth a try */
+			schedule_timeout(HZ / 4);	/* give captive thread time to exit */
+            if((ses->server) && (ses->server->ssocket)) {            
+                cFYI(1,("\nWaking up socket by sending it signal "));
+                send_sig(SIGINT,ses->server->tsk,1);
+                /* No luck figuring out a better way to_close socket */
+         /*ses->server->ssocket->sk->prot->close(ses->server->ssocket->sk,0);*/
+              /*  ses->server->ssocket = NULL; */  /* serialize better */
+                /* sock_wake_async(ses->server->ssocket,3,POLL_HUP); */
+            }
+		} else
+			cFYI(1, ("\nNo session or bad tcon"));
+	}
+	/* BB future check active count of tcon and then free if needed BB */
+	cifs_sb->tcon = NULL;
+	if (ses) {
+		schedule_timeout(HZ / 2);
+		/* if ((ses->server) && (ses->server->ssocket)) {
+               cFYI(1,("\nReleasing socket "));        
+               sock_release(ses->server->ssocket); 
+               kfree(ses->server); 
+          } */ 
+	}
+	if (ses)
+		sesInfoFree(ses);
+
+	FreeXid(xid);
+	return rc;		/* BB check if we should always return zero here */
+} 
diff -Nru a/fs/cifs/dir.c b/fs/cifs/dir.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/dir.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,303 @@
+/*
+ *   fs/cifs/dir.c
+ *
+ *   vfs operations that deal with dentries
+ * 
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+void
+renew_parental_timestamps(struct dentry *direntry)
+{
+	/* BB check if there is a way to get the kernel to do this or if we really need this */
+	do {
+		direntry->d_time = jiffies;
+		direntry = direntry->d_parent;
+	} while (!IS_ROOT(direntry));	/* BB for DFS case should stop at the root of share which could be lower than root of this mount due to implicit dfs connections */
+}
+
+/* Note: caller must free return buffer */
+char *
+build_path_from_dentry(struct dentry *direntry)
+{
+	struct dentry *temp;
+	int namelen = 0;
+	char *full_path;
+
+	for (temp = direntry; !IS_ROOT(temp);) {
+		namelen += (1 + temp->d_name.len);
+		cFYI(1, (" len %d ", namelen));
+		temp = temp->d_parent;
+	}
+	namelen += 1;		/* allow for trailing null */
+	cFYI(1, ("Final namelength (in build_path): %d ", namelen));	/* BB remove */
+	full_path = kmalloc(namelen, GFP_KERNEL);
+	namelen--;
+	full_path[namelen] = 0;	/* trailing null */
+	for (temp = direntry; !IS_ROOT(temp);) {
+		namelen -= 1 + temp->d_name.len;
+		if (namelen < 0) {
+			break;
+		} else {
+			full_path[namelen] = '\\';
+			strncpy(full_path + namelen + 1, temp->d_name.name,
+				temp->d_name.len);
+			cFYI(1, (" name: %s ", full_path + namelen));	/* BB remove */
+		}
+		temp = temp->d_parent;
+	}
+	if (namelen != 0)
+		cERROR(1,
+		       ("\nWe did not end path lookup where we expected namelen is %d",
+			namelen));
+
+	return full_path;
+}
+
+char *
+build_wildcard_path_from_dentry(struct dentry *direntry)
+{
+	struct dentry *temp;
+	int namelen = 0;
+	char *full_path;
+
+	for (temp = direntry; !IS_ROOT(temp);) {
+		namelen += (1 + temp->d_name.len);
+		temp = temp->d_parent;
+	}
+	namelen += 3;		/* allow for trailing null and wildcard (slash and *) */
+	full_path = kmalloc(namelen, GFP_KERNEL);
+	namelen--;
+	full_path[namelen] = 0;	/* trailing null */
+	namelen--;
+	full_path[namelen] = '*';
+	namelen--;
+	full_path[namelen] = '\\';
+
+	for (temp = direntry; !IS_ROOT(temp);) {
+		namelen -= 1 + temp->d_name.len;
+		if (namelen < 0) {
+			break;
+		} else {
+			full_path[namelen] = '\\';
+			strncpy(full_path + namelen + 1, temp->d_name.name,
+				temp->d_name.len);
+		}
+		temp = temp->d_parent;
+	}
+	if (namelen != 0)
+		cERROR(1,
+		       ("\nWe did not end path lookup where we expected namelen is %d",
+			namelen));
+
+	return full_path;
+}
+
+/* Inode operations in similar order to how they appear in the Linux file fs.h */
+
+int
+cifs_create(struct inode *inode, struct dentry *direntry, int mode)
+{
+	int rc = -ENOENT;
+	int xid;
+	int oplock = FALSE;	/* no need to oplock when we are not going to read from the file */
+	__u16 fileHandle;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+	struct inode *newinode = NULL;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_path_from_dentry(direntry);
+
+	/* BB add processing for setting the equivalent of mode - e.g. via CreateX with ACLs */
+
+	rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, GENERIC_ALL
+			 /* 0x20197 was used previously */ , mode,
+			 &fileHandle, &oplock, cifs_sb->local_nls);
+	if (rc) {
+		cFYI(1, ("\ncifs_create returned 0x%x ", rc));
+	} else {
+		if (pTcon->ses->capabilities & CAP_UNIX)
+			rc = cifs_get_inode_info_unix(&newinode, full_path,
+						      inode->i_sb);
+		else
+			rc = cifs_get_inode_info(&newinode, full_path,
+						 inode->i_sb);
+
+		if (rc != 0) {
+			cFYI(1,
+			     ("\nCreate worked but get_inode_info failed with rc = %d ",
+			      rc));
+			/* close handle */
+		} else {
+			direntry->d_op = &cifs_dentry_ops;
+			d_instantiate(direntry, newinode);
+		}
+		CIFSSMBClose(xid, pTcon, fileHandle);	
+        /* BB In the future chain close with the NTCreateX to narrow window */
+        
+        if(newinode)
+            newinode->i_mode = mode;
+	}
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+
+	return rc;
+}
+
+struct dentry *
+cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
+{
+	int rc, xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	struct inode *newInode = NULL;
+	char *full_path = NULL;
+
+	xid = GetXid();
+
+	cFYI(1,
+	     (" parent inode = 0x%p name is: %s and dentry = 0x%p",
+	      parent_dir_inode, direntry->d_name.name, direntry));
+
+	/* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */
+
+	/* check whether path exists */
+
+	cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_path_from_dentry(direntry);
+	if (direntry->d_inode != NULL) {
+		cFYI(1, (" non-NULL inode in lookup"));
+	} else {
+		cFYI(1, (" NULL inode in lookup"));
+	}
+	cFYI(1,
+	     (" Full path: %s inode = 0x%p\n", full_path, direntry->d_inode));
+	if (pTcon->ses->capabilities & CAP_UNIX)
+		rc = cifs_get_inode_info_unix(&newInode, full_path,
+					      parent_dir_inode->i_sb);
+	else
+		rc = cifs_get_inode_info(&newInode, full_path,
+					 parent_dir_inode->i_sb);
+
+	if ((rc == 0) && (newInode != NULL)) {
+		direntry->d_op = &cifs_dentry_ops;
+		d_add(direntry, newInode);
+
+		/* since paths are not looked up by component - the parent directories are presumed to be good here */
+		renew_parental_timestamps(direntry);
+
+	} else if (rc == -ENOENT) {
+		rc = 0;
+		d_add(direntry, NULL);
+	} else {
+		cERROR(1,
+		       ("Error 0x%x or (%d decimal) on cifs_get_inode_info in lookup\n",
+			rc, rc));
+		/* BB special case check for Access Denied - watch security exposure of returning dir info implicitly via different rc if file exists or not but no access BB */
+	}
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return ERR_PTR(rc);
+}
+
+int
+cifs_dir_open(struct inode *inode, struct file *file)
+{				/* NB: currently unused since searches are opened in readdir */
+	int rc = 0;
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_wildcard_path_from_dentry(file->f_dentry);
+
+	cFYI(1, (" inode = 0x%p and full path is %s\n", inode, full_path));
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
+
+static int
+cifs_d_revalidate(struct dentry *direntry, int flags)
+{
+	int isValid = 1;
+
+/*	lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */
+
+	if (direntry->d_inode) {
+		cFYI(1,
+		     ("In cifs_d_revalidate, name = %s and inode = 0x%p with count %d with time %ld and dentry 0x%p with time %ld\n",
+		      direntry->d_name.name, direntry->d_inode,
+		      direntry->d_inode->i_count.counter,
+		      direntry->d_inode->i_atime, direntry, direntry->d_time));
+		if (cifs_revalidate(direntry)) {
+			/* unlock_kernel(); */
+			return 0;
+		}
+	} else {
+		cFYI(1,
+		     ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p\n",
+		      direntry->d_name.name, direntry));
+	}
+
+/*    unlock_kernel(); */
+
+	return isValid;
+}
+
+/* static int cifs_d_delete(struct dentry *direntry)
+{
+	int rc = 0;
+
+	cFYI(1, ("In cifs d_delete, name = %s\n", direntry->d_name.name));
+
+	return rc;
+}     */
+
+struct dentry_operations cifs_dentry_ops = {
+	.d_revalidate = cifs_d_revalidate,
+/* d_delete:       cifs_d_delete,       *//* not needed except for debugging */
+	/* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
+};
diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/file.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1027 @@
+/*
+ *   fs/cifs/file.c
+ *
+ *   vfs operations that deal with files
+ * 
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/version.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <asm/div64.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+int
+cifs_open(struct inode *inode, struct file *file)
+{
+	int rc = -EACCES;
+	int xid, oplock;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+    struct cifsFileInfo *pCifsFile;
+    struct cifsInodeInfo *pCifsInode;
+	char *full_path = NULL;
+	int desiredAccess = 0x20197;
+	int disposition = FILE_OPEN;
+	__u16 netfid;
+
+	xid = GetXid();
+
+	cFYI(1, (" inode = 0x%p file flags are %x", inode, file->f_flags));
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_path_from_dentry(file->f_dentry);
+
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		desiredAccess = GENERIC_READ;
+	else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
+		desiredAccess = GENERIC_WRITE;
+	else if ((file->f_flags & O_ACCMODE) == O_RDWR)
+		desiredAccess = GENERIC_ALL;
+
+/* BB check other flags carefully to find equivalent NTCreateX flags */
+
+/*
+#define O_CREAT		   0100	
+#define O_EXCL		   0200	
+#define O_NOCTTY	   0400	
+#define O_TRUNC		  01000	
+#define O_APPEND	  02000
+#define O_NONBLOCK	  04000
+#define O_NDELAY	O_NONBLOCK
+#define O_SYNC		 010000
+#define FASYNC		 020000	
+#define O_DIRECT	 040000	
+#define O_LARGEFILE	0100000
+#define O_DIRECTORY	0200000	
+#define O_NOFOLLOW	0400000
+#define O_ATOMICLOOKUP	01000000 */
+
+	if (file->f_flags & O_CREAT)
+		disposition = FILE_OVERWRITE;
+
+	/* BB finish adding in oplock support BB */
+	if (oplockEnabled)
+		oplock = TRUE;
+	else
+		oplock = FALSE;
+
+	/* BB pass O_SYNC flag through on file attributes .. BB */
+	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,			 
+			 -1 /* i.e. dummy value, ignored for time being */,
+			 &netfid, &oplock, cifs_sb->local_nls);
+	if (rc) {
+		cFYI(1, ("\ncifs_open returned 0x%x ", rc));
+		cFYI(1, (" oplock: %d ", oplock));
+	} else {
+		file->private_data =
+		    kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
+		if (file->private_data) {
+			memset(file->private_data, 0,
+			       sizeof (struct cifsFileInfo));
+            pCifsFile = (struct cifsFileInfo *) file->private_data;
+			pCifsFile->netfid = netfid;
+			pCifsFile->pid = current->pid;
+            list_add(&pCifsFile->tlist,&pTcon->openFileList);
+            pCifsInode = CIFS_I(file->f_dentry->d_inode);
+            list_add(&pCifsFile->flist,&pCifsInode->openFileList);
+            if(file->f_flags & O_CREAT) {           
+                 /* time to set mode which we can not
+                 set earlier due to problems creating new read-only files */
+                if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)                
+                    CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
+                                        0xFFFFFFFFFFFFFFFF,  
+                                        0xFFFFFFFFFFFFFFFF,
+                                        cifs_sb->local_nls);
+                else {/* BB to be implemented via Windows secrty descriptors*/
+         /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
+                    /* in the meantime we could set the r/o dos attribute 
+                       when perms are e.g.:   
+                            mode & 0222 == 0 */
+                }
+            }
+
+		}
+	}
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_close(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	struct cifsFileInfo *pSMBFile =
+	    (struct cifsFileInfo *) file->private_data;
+
+	cFYI(1, ("\n  inode = 0x%p with ", inode));
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+ 	if (pSMBFile) {
+        list_del(&pSMBFile->flist);
+        list_del(&pSMBFile->tlist);
+        rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid);
+		kfree(file->private_data);
+		file->private_data = NULL;
+	} else
+		rc = -EBADF;
+
+	FreeXid(xid);
+	return rc;
+
+}
+
+int
+cifs_closedir(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int xid;
+	struct cifsFileInfo *pSMBFileStruct =
+	    (struct cifsFileInfo *) file->private_data;
+
+	cFYI(1, ("\nClosedir inode = 0x%p with ", inode));
+
+	xid = GetXid();
+
+	if (pSMBFileStruct) {
+		cFYI(1, ("\nFreeing private data in close dir"));
+		kfree(file->private_data);
+		file->private_data = NULL;
+	}
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
+{
+	int rc, xid;
+	__u32 lockType = LOCKING_ANDX_LARGE_FILES;
+	__u32 numLock = 0;
+	__u32 numUnlock = 0;
+	__u64 length;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	length = 1 + pfLock->fl_end - pfLock->fl_start;
+
+	rc = -EACCES;
+
+	xid = GetXid();
+
+	cFYI(1,
+	     ("\nLock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld",
+	      cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
+	      pfLock->fl_end));
+
+	if (pfLock->fl_flags & FL_POSIX)
+		cFYI(1, ("\nPosix "));
+	if (pfLock->fl_flags & FL_FLOCK)
+		cFYI(1, ("\nFlock "));
+	if (pfLock->fl_flags & FL_SLEEP)
+		cFYI(1, ("\nBlocking lock "));
+	if (pfLock->fl_flags & FL_ACCESS)
+		cFYI(1, ("\nProcess suspended by mandatory locking "));
+	if (pfLock->fl_flags & FL_LEASE)
+		cFYI(1, ("\nLease on file "));
+	if (pfLock->fl_flags & 0xFFD0)
+		cFYI(1, ("\n Unknown lock flags "));
+
+	if (pfLock->fl_type == F_WRLCK) {
+		cFYI(1, ("\nF_WRLCK "));
+		numLock = 1;
+	} else if (pfLock->fl_type == F_UNLCK) {
+		cFYI(1, ("\nF_UNLCK "));
+		numUnlock = 1;
+	} else if (pfLock->fl_type == F_RDLCK) {
+		cFYI(1, ("\nF_RDLCK "));
+		lockType |= LOCKING_ANDX_SHARED_LOCK;
+		numLock = 1;
+	} else if (pfLock->fl_type == F_EXLCK) {
+		cFYI(1, ("\nF_EXLCK "));
+		numLock = 1;
+	} else if (pfLock->fl_type == F_SHLCK) {
+		cFYI(1, ("\nF_SHLCK "));
+		lockType |= LOCKING_ANDX_SHARED_LOCK;
+		numLock = 1;
+	} else
+		cFYI(1, ("\nUnknown type of lock "));
+
+	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+	pTcon = cifs_sb->tcon;
+
+	if (file->private_data == NULL) {
+		FreeXid(xid);
+		return -EBADF;
+	}
+
+	if (IS_GETLK(cmd)) {
+		rc = CIFSSMBLock(xid, pTcon,
+				 ((struct cifsFileInfo *) file->
+				  private_data)->netfid,
+				 length,
+				 pfLock->fl_start, 0, 1, lockType,
+				 0 /* wait flag */ );
+		if (rc == 0) {
+			rc = CIFSSMBLock(xid, pTcon,
+					 ((struct cifsFileInfo *) file->
+					  private_data)->netfid,
+					 length,
+					 pfLock->fl_start, 1 /* numUnlock */ ,
+					 0 /* numLock */ , lockType,
+					 0 /* wait flag */ );
+			pfLock->fl_type = F_UNLCK;
+			if (rc != 0)
+				cERROR(1,
+				       ("\nError unlocking previously locked range %d during test of lock ",
+					rc));
+			rc = 0;
+
+		} else {
+			/* if rc == ERR_SHARING_VIOLATION ? */
+			rc = 0;	/* do not change lock type to unlock since range in use */
+		}
+
+		FreeXid(xid);
+		return rc;
+	}
+
+	rc = CIFSSMBLock(xid, pTcon,
+			 ((struct cifsFileInfo *) file->private_data)->
+			 netfid, length,
+			 pfLock->fl_start, numUnlock, numLock, lockType,
+			 0 /* wait flag */ );
+	FreeXid(xid);
+	return rc;
+}
+
+ssize_t
+cifs_write(struct file * file, const char *write_data,
+	   size_t write_size, loff_t * poffset)
+{
+	int rc = 0;
+	int bytes_written = 0;
+	int total_written;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	int xid, long_op;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+	pTcon = cifs_sb->tcon;
+
+	/*cFYI(1,
+	   (" write %d bytes to offset %lld of %s \n", write_size,
+	   *poffset, file->f_dentry->d_name.name)); */
+
+	if (file->private_data == NULL) {
+		FreeXid(xid);
+		return -EBADF;
+	}
+
+	if (*poffset > file->f_dentry->d_inode->i_size)
+		long_op = 2;	/* writes past end of file can take a long time */
+	else
+		long_op = 1;
+
+	for (total_written = 0; write_size > total_written;
+	     total_written += bytes_written) {
+		rc = CIFSSMBWrite(xid, pTcon,
+				  ((struct cifsFileInfo *) file->
+				   private_data)->netfid,
+				  write_size - total_written, *poffset,
+				  &bytes_written,
+				  write_data + total_written, long_op);
+		if (rc || (bytes_written == 0)) {
+			FreeXid(xid);
+			if (total_written)
+				break;
+			else {
+				FreeXid(xid);
+				return rc;
+			}
+		} else
+			*poffset += bytes_written;
+		long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
+	}
+	file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+	if (bytes_written > 0) {
+		if (*poffset > file->f_dentry->d_inode->i_size)
+			file->f_dentry->d_inode->i_size = *poffset;
+	}
+	mark_inode_dirty_sync(file->f_dentry->d_inode);
+	return total_written;
+}
+
+static int
+cifs_writepage(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+	int rc = -EFAULT;
+	int bytes_written = 0;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	int xid;
+	struct inode *inode = page->mapping->host;
+	loff_t *poffset = NULL;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	/* figure out which file struct to use 
+	   if (file->private_data == NULL) {
+	   FreeXid(xid);
+	   return -EBADF;
+	   }     
+	 */
+	if (!mapping) {
+		FreeXid(xid);
+		return -EFAULT;
+	}
+
+	/* BB fix and add missing call to cifs_writepage_sync here */
+
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;	/* BB is this right? */
+	if ((bytes_written > 0) && (poffset)) {
+		if (*poffset > inode->i_size)
+			inode->i_size = *poffset;
+	}
+	mark_inode_dirty_sync(inode);
+
+	FreeXid(xid);
+	return rc;
+}
+
+static int
+cifs_prepare_write(struct file *file, struct page *page, unsigned offset,
+		   unsigned to)
+{
+	return 0;	/* eventually add code to flush any incompatible requests */
+}
+
+static int
+cifs_commit_write(struct file *file, struct page *page, unsigned offset,
+		  unsigned to)
+{
+	long rc = -EFAULT;
+
+	lock_kernel();
+/*	status = cifs_updatepage(file, page, offset, to-offset); */
+
+/* BB add - do we really need to lock the kernel here for so long ? */
+
+	unlock_kernel();
+	return rc;
+}
+
+int
+cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	int xid;
+	int rc = 0;
+	xid = GetXid();
+	/* BB fill in code to flush write behind buffers - when we start supporting oplock */
+	cFYI(1, (" name: %s datasync: 0x%x ", dentry->d_name.name, datasync));
+	FreeXid(xid);
+	return rc;
+}
+
+static int
+cifs_sync_page(struct page *page)
+{
+	struct address_space *mapping;
+	struct inode *inode;
+	unsigned long index = page->index;
+	unsigned int rpages = 0;
+	int rc = 0;
+
+	mapping = page->mapping;
+	if (!mapping)
+		return 0;
+	inode = mapping->host;
+	if (!inode)
+		return 0;
+
+/*	fill in rpages then 
+    result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */
+
+	cFYI(1, ("\nrpages is %d for sync page of Index %ld ", rpages, index));
+
+	if (rc < 0)
+		return rc;
+	return 0;
+}
+
+ssize_t
+cifs_read(struct file * file, char *read_data, size_t read_size,
+	  loff_t * poffset)
+{
+	int rc = -EACCES;
+	int bytes_read = 0;
+	int total_read;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	int xid;
+
+	xid = GetXid();
+	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+	pTcon = cifs_sb->tcon;
+
+	if (file->private_data == NULL) {
+		FreeXid(xid);
+		return -EBADF;
+	}
+
+	for (total_read = 0; read_size > total_read; total_read += bytes_read) {
+		rc = CIFSSMBRead(xid, pTcon,
+				 ((struct cifsFileInfo *) file->
+				  private_data)->netfid,
+				 read_size - total_read, *poffset,
+				 &bytes_read, read_data + total_read);
+		if (rc || (bytes_read == 0)) {
+			if (total_read) {
+				break;
+			} else {
+				FreeXid(xid);
+				return rc;
+			}
+		} else
+			*poffset += bytes_read;
+	}
+
+	FreeXid(xid);
+	return total_read;
+}
+
+static int
+cifs_readpage_sync(struct file *file, struct page *page)
+{
+	unsigned int count = PAGE_CACHE_SIZE;
+	int rc = -EACCES;
+	int bytes_read = 0;
+	int total_read = 0;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	int xid;
+
+	xid = GetXid();
+	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+	pTcon = cifs_sb->tcon;
+
+	if (file->private_data == NULL) {
+		FreeXid(xid);
+		return -EBADF;
+	}
+
+	/* BB finish adding missing here */
+
+	cFYI(1,
+	     ("\nCount is %d total read %d bytes read %d ", count, total_read,
+	      bytes_read));
+
+	FreeXid(xid);
+	return rc;
+}
+
+static int
+cifs_readpage(struct file *file, struct page *page)
+{
+	int rc;
+
+	page_cache_get(page);
+	rc = cifs_readpage_sync(file, page);
+	/* for reads over a certain size we could initiate async read ahead */
+	page_cache_release(page);
+	return rc;
+}
+
+void
+fill_in_inode(struct inode *tmp_inode,
+	      FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
+{
+	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+	pfindData->ExtFileAttributes =
+	    le32_to_cpu(pfindData->ExtFileAttributes);
+	pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
+	pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
+	cifsInfo->cifsAttrs = pfindData->ExtFileAttributes;
+	cifsInfo->time = jiffies;
+	atomic_inc(&cifsInfo->inUse);	/* inc on every refresh of inode info */
+
+	/* Linux can not store file creation time unfortunately so we ignore it */
+	tmp_inode->i_atime =
+	    le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastAccessTime));
+	tmp_inode->i_mtime =
+	    le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastWriteTime));
+	tmp_inode->i_ctime =
+	    le64_to_cpu(cifs_NTtimeToUnix(pfindData->ChangeTime));
+	/* should we treat the dos attribute of read-only as read-only mode bit e.g. 555 */
+	tmp_inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);	/* 2767 perms - indicate mandatory locking */
+	cFYI(0,
+	     ("\nCIFS FFIRST: Attributes came in as 0x%x",
+	      pfindData->ExtFileAttributes));
+	if (pfindData->ExtFileAttributes & ATTR_REPARSE) {
+		*pobject_type = DT_LNK;
+		tmp_inode->i_mode |= S_IFLNK;	/* BB can this and S_IFREG or S_IFDIR be set at same time as in Windows? */
+	} else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) {
+		*pobject_type = DT_DIR;
+		tmp_inode->i_mode = S_IRWXUGO;	/* override default perms since we do not lock dirs */
+		tmp_inode->i_mode |= S_IFDIR;
+	} else {
+		*pobject_type = DT_REG;
+		tmp_inode->i_mode |= S_IFREG;
+	}/* could add code here - to validate if device or weird share type? */
+
+	/* can not fill in nlink here as in qpathinfo version and in Unx search */
+	tmp_inode->i_size = pfindData->EndOfFile;
+	tmp_inode->i_blocks =
+	    do_div(pfindData->AllocationSize, tmp_inode->i_blksize);
+	cFYI(1,
+	     ("\nFinddata alloc size (from smb) %lld",
+	      pfindData->AllocationSize));
+	if (pfindData->AllocationSize < pfindData->EndOfFile)
+		cFYI(1, ("\nServer inconsistency Error: it says allocation size less than end of file "));
+	cFYI(1,
+	     ("\nCIFS FFIRST: Size %ld and blocks %ld and blocksize %ld",
+	      (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
+	      tmp_inode->i_blksize));
+	if (S_ISREG(tmp_inode->i_mode)) {
+		cFYI(1, (" File inode "));
+		tmp_inode->i_op = &cifs_file_inode_ops;
+		tmp_inode->i_fop = &cifs_file_ops;
+	} else if (S_ISDIR(tmp_inode->i_mode)) {
+		cFYI(1, (" Directory inode"));
+		tmp_inode->i_op = &cifs_dir_inode_ops;
+		tmp_inode->i_fop = &cifs_dir_ops;
+	} else if (S_ISLNK(tmp_inode->i_mode)) {
+		cFYI(1, (" Symbolic Link inode "));
+		tmp_inode->i_op = &cifs_symlink_inode_ops;
+	} else {
+		cFYI(1, ("\nInit special inode "));
+		init_special_inode(tmp_inode, tmp_inode->i_mode,
+				   kdev_t_to_nr(tmp_inode->i_rdev));
+	}
+}
+
+void
+unix_fill_in_inode(struct inode *tmp_inode,
+		   FILE_UNIX_INFO * pfindData, int *pobject_type)
+{
+	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+	cifsInfo->time = jiffies;
+	atomic_inc(&cifsInfo->inUse);
+
+	tmp_inode->i_atime =
+	    le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastAccessTime));
+	tmp_inode->i_mtime =
+	    le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastModificationTime));
+	tmp_inode->i_ctime =
+	    le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastStatusChange));
+
+	/* tmp_inode->i_mtime =
+	   cifs_NTtimeToUnix(pfindData->LastModificationTime);
+	   tmp_inode->i_ctime =
+	   cifs_NTtimeToUnix(pfindData->LastStatusChange); */
+	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
+	pfindData->Type = le32_to_cpu(pfindData->Type);
+	if (pfindData->Type == UNIX_FILE) {
+		*pobject_type = DT_REG;
+		tmp_inode->i_mode |= S_IFREG;
+	} else if (pfindData->Type == UNIX_SYMLINK) {
+		*pobject_type = DT_LNK;
+		tmp_inode->i_mode |= S_IFLNK;
+	} else if (pfindData->Type == UNIX_DIR) {
+		*pobject_type = DT_DIR;
+		tmp_inode->i_mode |= S_IFDIR;
+	} else if (pfindData->Type == UNIX_CHARDEV) {
+		*pobject_type = DT_CHR;
+		tmp_inode->i_mode |= S_IFCHR;
+	} else if (pfindData->Type == UNIX_BLOCKDEV) {
+		*pobject_type = DT_BLK;
+		tmp_inode->i_mode |= S_IFBLK;
+	} else if (pfindData->Type == UNIX_FIFO) {
+		*pobject_type = DT_FIFO;
+		tmp_inode->i_mode |= S_IFIFO;
+	} else if (pfindData->Type == UNIX_SOCKET) {
+		*pobject_type = DT_SOCK;
+		tmp_inode->i_mode |= S_IFSOCK;
+	}
+
+	tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
+	tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
+	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
+
+	pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes);
+	pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
+	tmp_inode->i_size = pfindData->EndOfFile;
+	tmp_inode->i_blocks =
+	    do_div(pfindData->NumOfBytes, tmp_inode->i_blksize);
+	cFYI(0, ("\nFinddata alloc size (from smb) %lld", pfindData->NumOfBytes));	/* BB remove */
+	if (pfindData->NumOfBytes < pfindData->EndOfFile)
+		cFYI(0, ("\nServer inconsistency Error: it says allocation size less than end of file "));	/* BB remove */
+	cFYI(1, ("\nCIFS FFIRST: Size %ld and blocks %ld ", (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks));	/* BB remove */
+	if (S_ISREG(tmp_inode->i_mode)) {
+		cFYI(1, (" File inode "));
+		tmp_inode->i_op = &cifs_file_inode_ops;
+		tmp_inode->i_fop = &cifs_file_ops;
+	} else if (S_ISDIR(tmp_inode->i_mode)) {
+		cFYI(1, (" Directory inode"));
+		tmp_inode->i_op = &cifs_dir_inode_ops;
+		tmp_inode->i_fop = &cifs_dir_ops;
+	} else if (S_ISLNK(tmp_inode->i_mode)) {
+		cFYI(1, (" Symbolic Link inode "));
+		tmp_inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+	} else {
+		cFYI(1, ("\nInit special inode "));
+		init_special_inode(tmp_inode, tmp_inode->i_mode,
+				   kdev_t_to_nr(tmp_inode->i_rdev));
+	}
+}
+
+void
+construct_dentry(struct qstr *qstring, struct file *file,
+		 struct inode **ptmp_inode, struct dentry **pnew_dentry)
+{
+	struct dentry *tmp_dentry;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+
+	cFYI(1, ("\nFor %s ", qstring->name));
+	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+	pTcon = cifs_sb->tcon;
+
+	qstring->hash = full_name_hash(qstring->name, qstring->len);
+	tmp_dentry = d_lookup(file->f_dentry, qstring);
+	if (tmp_dentry) {
+		cFYI(1, (" existing dentry with inode 0x%p ", tmp_dentry->d_inode));	/* BB remove */
+		*ptmp_inode = tmp_dentry->d_inode;
+		/* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
+	} else {
+		tmp_dentry = d_alloc(file->f_dentry, qstring);
+		*ptmp_inode = new_inode(file->f_dentry->d_sb);
+		cFYI(1, ("\nAlloc new inode %p ", *ptmp_inode));
+		tmp_dentry->d_op = &cifs_dentry_ops;
+		cFYI(1, (" instantiate dentry 0x%p with inode 0x%p ",
+			 tmp_dentry, *ptmp_inode));
+		d_instantiate(tmp_dentry, *ptmp_inode);
+		d_rehash(tmp_dentry);
+	}
+
+	tmp_dentry->d_time = jiffies;
+	(*ptmp_inode)->i_blksize =
+	    (pTcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;
+	cFYI(1, ("\ni_blksize = %ld", (*ptmp_inode)->i_blksize));
+	*pnew_dentry = tmp_dentry;
+}
+
+void
+cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
+	     struct file *file, filldir_t filldir, void *direntry)
+{
+	struct inode *tmp_inode;
+	struct dentry *tmp_dentry;
+	int object_type;
+
+	pqstring->name = pfindData->FileName;
+	pqstring->len = pfindData->FileNameLength;
+
+	construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
+
+	fill_in_inode(tmp_inode, pfindData, &object_type);
+	filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
+		tmp_inode->i_ino, object_type);
+	dput(tmp_dentry);
+}
+
+void
+cifs_filldir_unix(struct qstr *pqstring,
+		  FILE_UNIX_INFO * pUnixFindData, struct file *file,
+		  filldir_t filldir, void *direntry)
+{
+	struct inode *tmp_inode;
+	struct dentry *tmp_dentry;
+	int object_type;
+
+	pqstring->name = pUnixFindData->FileName;
+	pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
+
+	construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
+
+	unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
+	filldir(direntry, pUnixFindData->FileName, pqstring->len,
+		file->f_pos, tmp_inode->i_ino, object_type);
+	dput(tmp_dentry);
+}
+
+int
+cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
+{
+	int rc = 0;
+	int xid, i;
+	int Unicode = FALSE;
+	int UnixSearch = FALSE;
+	__u16 searchHandle;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	struct cifsFileInfo *cifsFile = NULL;
+	char *full_path = NULL;
+	char *data;
+	struct qstr qstring;
+	T2_FFIRST_RSP_PARMS findParms;
+	T2_FNEXT_RSP_PARMS findNextParms;
+	FILE_DIRECTORY_INFO *pfindData;
+	FILE_UNIX_INFO *pfindDataUnix;
+
+	xid = GetXid();
+
+	data = kmalloc(4096, GFP_KERNEL);
+	pfindData = (FILE_DIRECTORY_INFO *) data;
+
+	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_wildcard_path_from_dentry(file->f_dentry);
+
+	cFYI(1, ("\nFull path: %s start at: %lld ", full_path, file->f_pos));
+
+	switch ((int) file->f_pos) {
+	case 0:
+		if (filldir
+		    (direntry, ".", 1, file->f_pos,
+		     file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
+			cERROR(1, ("\nFilldir for current dir failed "));
+			break;
+		}
+		file->f_pos++;
+		/* fallthrough */
+	case 1:
+		if (filldir
+		    (direntry, "..", 2, file->f_pos,
+		     file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
+			cERROR(1, ("\nFilldir for parent dir failed "));
+			break;
+		}
+		file->f_pos++;
+		/* fallthrough */
+	case 2:
+		/* Should we first check if file->private_data is null? */
+		rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
+				   &findParms, cifs_sb->local_nls,
+				   &Unicode, &UnixSearch);
+		cFYI(1,
+		     ("Count: %d  End: %d ", findParms.SearchCount,
+		      findParms.EndofSearch));
+
+		if (rc == 0) {
+			searchHandle = findParms.SearchHandle;
+			file->private_data =
+			    kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
+			if (file->private_data) {
+				memset(file->private_data, 0,
+				       sizeof (struct cifsFileInfo));
+				cifsFile =
+				    (struct cifsFileInfo *) file->private_data;
+				cifsFile->netfid = searchHandle;
+			}
+
+			renew_parental_timestamps(file->f_dentry);
+
+			for (i = 2; i < findParms.SearchCount + 2; i++) {
+				if (UnixSearch == FALSE) {
+					pfindData->FileNameLength =
+					    le32_to_cpu(pfindData->
+							FileNameLength);
+					if (Unicode == TRUE)
+						pfindData->FileNameLength =
+						    cifs_strfromUCS_le
+						    (pfindData->FileName,
+						     (wchar_t *)
+						     pfindData->FileName,
+						     (pfindData->
+						      FileNameLength) / 2,
+						     cifs_sb->local_nls);
+					qstring.len = pfindData->FileNameLength;
+					if (((qstring.len != 1)
+					     || (pfindData->FileName[0] != '.'))
+					    && ((qstring.len != 2)
+						|| (pfindData->
+						    FileName[0] != '.')
+						|| (pfindData->
+						    FileName[1] != '.'))) {
+						cifs_filldir(&qstring,
+							     pfindData,
+							     file, filldir,
+							     direntry);
+						file->f_pos++;
+					}
+				} else {	/* UnixSearch */
+					pfindDataUnix =
+					    (FILE_UNIX_INFO *) pfindData;
+					if (Unicode == TRUE)
+						qstring.len =
+						    cifs_strfromUCS_le
+						    (pfindDataUnix->
+						     FileName, (wchar_t *)
+						     pfindDataUnix->
+						     FileName,
+						     MAX_PATHCONF,
+						     cifs_sb->local_nls);
+					else
+						qstring.len =
+						    strnlen(pfindDataUnix->
+							    FileName,
+							    MAX_PATHCONF);
+					if (((qstring.len != 1)
+					     || (pfindDataUnix->
+						 FileName[0] != '.'))
+					    && ((qstring.len != 2)
+						|| (pfindDataUnix->
+						    FileName[0] != '.')
+						|| (pfindDataUnix->
+						    FileName[1] != '.'))) {
+						cifs_filldir_unix(&qstring,
+								  pfindDataUnix,
+								  file,
+								  filldir,
+								  direntry);
+						file->f_pos++;
+					}
+				}
+				pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset));	/* works also for Unix find struct since this is the first field of both */
+				/* BB also should check to make sure that pointer is not beyond the end of the SMB */
+			}	/* end for loop */
+			if ((findParms.EndofSearch != 0) && cifsFile) {
+				cifsFile->endOfSearch = TRUE;
+			}
+		} else {
+			if (cifsFile)
+				cifsFile->endOfSearch = TRUE;
+			rc = 0;	/* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */
+		}
+		break;
+	default:
+		if (file->private_data == NULL) {
+			rc = -EBADF;
+			cFYI(1,
+			     ("\nReaddir on closed srch, pos = %lld",
+			      file->f_pos));
+		} else {
+			cifsFile = (struct cifsFileInfo *) file->private_data;
+			if (cifsFile->endOfSearch) {
+				rc = 0;
+				cFYI(1, ("\nEnd of search "));
+				break;
+			}
+			searchHandle = cifsFile->netfid;
+			rc = CIFSFindNext(xid, pTcon, pfindData,
+					  &findNextParms, searchHandle, 0,
+					  &Unicode, &UnixSearch);
+			cFYI(1,
+			     ("Count: %d  End: %d ",
+			      findNextParms.SearchCount,
+			      findNextParms.EndofSearch));
+			if ((rc == 0) && (findNextParms.SearchCount != 0)) {
+				for (i = 0; i < findNextParms.SearchCount; i++) {
+					pfindData->FileNameLength =
+					    le32_to_cpu(pfindData->
+							FileNameLength);
+					if (UnixSearch == FALSE) {
+						if (Unicode == TRUE)
+							pfindData->
+							    FileNameLength
+							    =
+							    cifs_strfromUCS_le
+							    (pfindData->
+							     FileName,
+							     (wchar_t *)
+							     pfindData->
+							     FileName,
+							     (pfindData->
+							      FileNameLength)
+							     / 2,
+							     cifs_sb->
+							     local_nls);
+						qstring.len =
+						    pfindData->FileNameLength;
+						if (((qstring.len != 1)
+						     || (pfindData->
+							 FileName[0] != '.'))
+						    && ((qstring.len != 2)
+							|| (pfindData->
+							    FileName[0] != '.')
+							|| (pfindData->
+							    FileName[1] !=
+							    '.'))) {
+							cifs_filldir
+							    (&qstring,
+							     pfindData,
+							     file, filldir,
+							     direntry);
+							file->f_pos++;
+						}
+					} else {	/* UnixSearch */
+						pfindDataUnix =
+						    (FILE_UNIX_INFO *)
+						    pfindData;
+						if (Unicode == TRUE)
+							qstring.len =
+							    cifs_strfromUCS_le
+							    (pfindDataUnix->
+							     FileName,
+							     (wchar_t *)
+							     pfindDataUnix->
+							     FileName,
+							     MAX_PATHCONF,
+							     cifs_sb->
+							     local_nls);
+						else
+							qstring.len =
+							    strnlen
+							    (pfindDataUnix->
+							     FileName,
+							     MAX_PATHCONF);
+
+						if (((qstring.len != 1)
+						     || (pfindDataUnix->
+							 FileName[0] != '.'))
+						    && ((qstring.len != 2)
+							|| (pfindDataUnix->
+							    FileName[0] != '.')
+							|| (pfindDataUnix->
+							    FileName[1] !=
+							    '.'))) {
+							cifs_filldir_unix
+							    (&qstring,
+							     pfindDataUnix,
+							     file, filldir,
+							     direntry);
+							file->f_pos++;
+						}
+					}
+					pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset));	/* works also for Unix find struct since this is the first field of both */
+					/* BB also should check to make sure that pointer is not beyond the end of the SMB */
+
+				}	/* end for loop */
+				if (findNextParms.EndofSearch != 0) {
+					cifsFile->endOfSearch = TRUE;
+				}
+			} else {
+				cifsFile->endOfSearch = TRUE;
+				rc = 0;	/* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */
+			}
+		}
+	}			/* end switch */
+
+	if (data)
+		kfree(data);
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+
+	return rc;
+}
+
+struct address_space_operations cifs_addr_ops = {
+	.readpage = cifs_readpage,
+	.sync_page = cifs_sync_page,
+	.writepage = cifs_writepage,
+	.prepare_write = cifs_prepare_write,
+	.commit_write = cifs_commit_write
+};
diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/inode.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,691 @@
+/*
+ *   fs/cifs/inode.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <asm/div64.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+int
+cifs_get_inode_info_unix(struct inode **pinode,
+			 const unsigned char *search_path,
+			 struct super_block *sb)
+{
+	int xid;
+	int rc = 0;
+	FILE_UNIX_BASIC_INFO findData;
+	struct cifsTconInfo *pTcon;
+	struct inode *inode;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	char *tmp_path;
+
+	xid = GetXid();
+
+	pTcon = cifs_sb->tcon;
+	cFYI(1, ("\nGetting info on %s ", search_path));
+	/* we could have done a find first instead but this returns more info */
+	rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
+				  cifs_sb->local_nls);
+	/* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
+	if (rc) {
+		if (rc == -EREMOTE) {
+/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
+   &referrals,
+   &num_referrals,
+   cifs_sb->local_nls); */
+			tmp_path =
+			    kmalloc(strnlen
+				    (pTcon->treeName,
+				     MAX_TREE_SIZE + 1) +
+				    strnlen(search_path, MAX_PATHCONF) + 1,
+				    GFP_KERNEL);
+			if (tmp_path == NULL) {
+				FreeXid(xid);
+				return -ENOMEM;
+			}
+        /* have to skip first of the double backslash of UNC name */
+			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);	
+			strncat(tmp_path, search_path, MAX_PATHCONF);
+			rc = connect_to_dfs_path(xid, pTcon->ses,
+						 /* treename + */ tmp_path,
+						 cifs_sb->local_nls);
+			kfree(tmp_path);
+
+			/* BB fix up inode etc. */
+		} else if (rc) {
+			FreeXid(xid);
+			return rc;
+		}
+
+	} else {
+		struct cifsInodeInfo *cifsInfo;
+
+		/* get new inode */
+		if (*pinode == NULL) {
+			*pinode = new_inode(sb);
+			cFYI(1, ("\nAlloc new inode %p ", *pinode));
+		}
+		inode = *pinode;
+/*        new_inode = iget(parent_dir_inode->i_sb, findData.IndexNumber); */
+        /* index number not reliable in response data */
+
+		cifsInfo = CIFS_I(inode);
+
+		cFYI(1, ("\nOld time %ld ", cifsInfo->time));
+		cifsInfo->time = jiffies;
+		cFYI(1, (" New time %ld ", cifsInfo->time));
+		atomic_inc(&cifsInfo->inUse);	/* inc on every refresh of inode */
+
+		inode->i_atime =
+		    le64_to_cpu(cifs_NTtimeToUnix(findData.LastAccessTime));
+		inode->i_mtime =
+		    le64_to_cpu(cifs_NTtimeToUnix
+				(findData.LastModificationTime));
+		inode->i_ctime =
+		    le64_to_cpu(cifs_NTtimeToUnix(findData.LastStatusChange));
+		inode->i_mode = le64_to_cpu(findData.Permissions);
+		findData.Type = le32_to_cpu(findData.Type);
+		if (findData.Type == UNIX_FILE) {
+			inode->i_mode |= S_IFREG;
+		} else if (findData.Type == UNIX_SYMLINK) {
+			inode->i_mode |= S_IFLNK;
+		} else if (findData.Type == UNIX_DIR) {
+			inode->i_mode |= S_IFDIR;
+		} else if (findData.Type == UNIX_CHARDEV) {
+			inode->i_mode |= S_IFCHR;
+		} else if (findData.Type == UNIX_BLOCKDEV) {
+			inode->i_mode |= S_IFBLK;
+		} else if (findData.Type == UNIX_FIFO) {
+			inode->i_mode |= S_IFIFO;
+		} else if (findData.Type == UNIX_SOCKET) {
+			inode->i_mode |= S_IFSOCK;
+		}
+		inode->i_uid = le64_to_cpu(findData.Uid);
+		inode->i_gid = le64_to_cpu(findData.Gid);
+		inode->i_nlink = le64_to_cpu(findData.Nlinks);
+		findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
+		findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
+		inode->i_size = findData.EndOfFile;
+		inode->i_blksize =
+		    (pTcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;
+		inode->i_blocks = do_div(findData.NumOfBytes, inode->i_blksize);
+		cFYI(1,
+		     ("\nFinddata alloc size (from smb) %lld",
+		      findData.NumOfBytes));
+		if (findData.NumOfBytes < findData.EndOfFile)
+			cFYI(1, ("\nServer inconsistency Error: it says allocation size less than end of file "));
+		cFYI(1,
+		     ("\nCIFS FFIRST: Size %ld and blocks %ld ",
+		      (unsigned long) inode->i_size, inode->i_blocks));
+		if (S_ISREG(inode->i_mode)) {
+			cFYI(1, (" File inode "));
+			inode->i_op = &cifs_file_inode_ops;
+			inode->i_fop = &cifs_file_ops;
+		} else if (S_ISDIR(inode->i_mode)) {
+			cFYI(1, (" Directory inode"));
+			inode->i_op = &cifs_dir_inode_ops;
+			inode->i_fop = &cifs_dir_ops;
+		} else if (S_ISLNK(inode->i_mode)) {
+			cFYI(1, (" Symbolic Link inode "));
+			inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+		} else {
+			cFYI(1, ("\nInit special inode "));
+			init_special_inode(inode, inode->i_mode,
+					   kdev_t_to_nr(inode->i_rdev));
+		}
+	}
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_get_inode_info(struct inode **pinode,
+		    const unsigned char *search_path, struct super_block *sb)
+{
+	int xid;
+	int rc = 0;
+	FILE_ALL_INFO findData;
+	struct cifsTconInfo *pTcon;
+	struct inode *inode;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	char *tmp_path;
+
+	xid = GetXid();
+
+	pTcon = cifs_sb->tcon;
+	cFYI(1, ("\nGetting info on %s ", search_path));
+	/* we could have done a find first instead but this returns more info */
+	rc = CIFSSMBQPathInfo(xid, pTcon, search_path, &findData,
+			      cifs_sb->local_nls);
+	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
+	if (rc) {
+		if (rc == -EREMOTE) {
+			/* BB add call to new func rc = GetDFSReferral(); */
+/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
+   &referrals,
+   &num_referrals,
+   cifs_sb->local_nls); */
+			tmp_path =
+			    kmalloc(strnlen
+				    (pTcon->treeName,
+				     MAX_TREE_SIZE + 1) +
+				    strnlen(search_path, MAX_PATHCONF) + 1,
+				    GFP_KERNEL);
+			if (tmp_path == NULL) {
+				FreeXid(xid);
+				return -ENOMEM;
+			}
+
+			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
+			strncat(tmp_path, search_path, MAX_PATHCONF);
+			rc = connect_to_dfs_path(xid, pTcon->ses,
+						 /* treename + */ tmp_path,
+						 cifs_sb->local_nls);
+			kfree(tmp_path);
+			/* BB fix up inode etc. */
+		} else if (rc) {
+			FreeXid(xid);
+			return rc;
+		}
+	} else {
+		struct cifsInodeInfo *cifsInfo;
+
+		/* get new inode */
+		if (*pinode == NULL) {
+			*pinode = new_inode(sb);
+			cFYI(1, ("\nAlloc new inode %p ", *pinode));
+		}
+
+		inode = *pinode;
+		cifsInfo = CIFS_I(inode);
+		findData.Attributes = le32_to_cpu(findData.Attributes);
+		cifsInfo->cifsAttrs = findData.Attributes;
+		cFYI(1, ("\nOld time %ld ", cifsInfo->time));
+		cifsInfo->time = jiffies;
+		cFYI(1, (" New time %ld ", cifsInfo->time));
+		atomic_inc(&cifsInfo->inUse);	/* inc on every refresh of inode */
+
+		inode->i_blksize =
+		    (pTcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;
+		/* Linux can not store file creation time unfortunately so we ignore it */
+		inode->i_atime =
+		    cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
+		inode->i_mtime =
+		    cifs_NTtimeToUnix(le64_to_cpu(findData.LastWriteTime));
+		inode->i_ctime =
+		    cifs_NTtimeToUnix(le64_to_cpu(findData.ChangeTime));
+/* inode->i_mode = S_IRWXUGO;  *//* 777 perms */
+		/* should we treat the dos attribute of read-only as read-only mode bit e.g. 555 */
+		inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);	/* 2767 perms indicate mandatory locking - will override for dirs later */
+		cFYI(0,
+		     ("\nAttributes came in as 0x%x\n", findData.Attributes));
+		if (findData.Attributes & ATTR_REPARSE) {	
+   /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
+			inode->i_mode |= S_IFLNK;
+		} else if (findData.Attributes & ATTR_DIRECTORY) {
+   /* override default perms since we do not do byte range locking on dirs */
+			inode->i_mode = S_IRWXUGO;	
+            inode->i_mode |= S_IFDIR;
+		} else {
+			inode->i_mode |= S_IFREG;
+   /* BB add code here - validate if device or weird share or device type? */
+		}
+		inode->i_size = le64_to_cpu(findData.EndOfFile);
+		findData.AllocationSize = le64_to_cpu(findData.AllocationSize);
+		inode->i_blocks =
+		    do_div(findData.AllocationSize, inode->i_blksize);
+		cFYI(1,
+		     ("\n Size %ld and blocks %ld ",
+		      (unsigned long) inode->i_size, inode->i_blocks));
+		inode->i_nlink = le32_to_cpu(findData.NumberOfLinks);
+
+		/* BB fill in uid and gid here? with help from winbind? */
+
+		if (S_ISREG(inode->i_mode)) {
+			cFYI(1, (" File inode "));
+			inode->i_op = &cifs_file_inode_ops;
+			inode->i_fop = &cifs_file_ops;
+		} else if (S_ISDIR(inode->i_mode)) {
+			cFYI(1, (" Directory inode "));
+			inode->i_op = &cifs_dir_inode_ops;
+			inode->i_fop = &cifs_dir_ops;
+		} else if (S_ISLNK(inode->i_mode)) {
+			cFYI(1, (" Symbolic Link inode "));
+			inode->i_op = &cifs_symlink_inode_ops;
+		} else {
+			init_special_inode(inode, inode->i_mode,
+					   kdev_t_to_nr(inode->i_rdev));
+		}
+	}
+	FreeXid(xid);
+	return rc;
+}
+
+void
+cifs_read_inode(struct inode *inode)
+{				/* gets root inode */
+
+	struct cifs_sb_info *cifs_sb;
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+
+	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+		cifs_get_inode_info_unix(&inode, "", inode->i_sb);
+	else
+		cifs_get_inode_info(&inode, "", inode->i_sb);
+}
+
+int
+cifs_unlink(struct inode *inode, struct dentry *direntry)
+{
+	int rc = 0;
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+	struct cifsInodeInfo *cifsInode;
+
+	cFYI(1, ("\n cifs_unlink, inode = 0x%p with ", inode));
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	/* BB Should we close the file if it is already open from our client? */
+
+	full_path = build_path_from_dentry(direntry);
+
+	rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
+
+	if (!rc) {
+		direntry->d_inode->i_nlink--;
+	}
+	cifsInode = CIFS_I(direntry->d_inode);
+	cifsInode->time = 0;	/* will force revalidate to get info when needed */
+	direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
+	    CURRENT_TIME;
+	cifsInode = CIFS_I(inode);
+	cifsInode->time = 0;	/* force revalidate of dir as well */
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
+{
+	int rc = 0;
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+	struct inode *newinode = NULL;
+
+	cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p\n", mode, inode));
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_path_from_dentry(direntry);
+	/* BB add setting the equivalent of mode via CreateX w/ACLs */
+	rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
+	if (rc) {
+		cFYI(1, ("\ncifs_mkdir returned 0x%x ", rc));
+	} else {
+		inode->i_nlink++;
+		if (pTcon->ses->capabilities & CAP_UNIX)
+			rc = cifs_get_inode_info_unix(&newinode, full_path,
+						      inode->i_sb);
+		else
+			rc = cifs_get_inode_info(&newinode, full_path,
+						 inode->i_sb);
+
+		direntry->d_op = &cifs_dentry_ops;
+		d_instantiate(direntry, newinode);
+		direntry->d_inode->i_nlink = 2;
+        if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)                
+            CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
+                        0xFFFFFFFFFFFFFFFF,  
+                        0xFFFFFFFFFFFFFFFF,
+                        cifs_sb->local_nls);
+        else { /* BB to be implemented via Windows secrty descriptors*/
+        /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
+        }
+
+	}
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+
+	return rc;
+}
+
+int
+cifs_rmdir(struct inode *inode, struct dentry *direntry)
+{
+	int rc = 0;
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+	struct cifsInodeInfo *cifsInode;
+
+	cFYI(1, ("\nn cifs_rmdir, inode = 0x%p with ", inode));
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_path_from_dentry(direntry);
+
+	rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
+
+	if (!rc) {
+		inode->i_nlink--;
+		direntry->d_inode->i_size = 0;
+		direntry->d_inode->i_nlink = 0;
+	}
+
+	cifsInode = CIFS_I(direntry->d_inode);
+	cifsInode->time = 0;	/* force revalidate to go get info when needed */
+	direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
+	    CURRENT_TIME;
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
+	    struct inode *target_inode, struct dentry *target_direntry)
+{
+	char *fromName;
+	char *toName;
+	struct cifs_sb_info *cifs_sb_source;
+	struct cifs_sb_info *cifs_sb_target;
+	struct cifsTconInfo *pTcon;
+	int xid;
+	int rc = 0;
+
+	xid = GetXid();
+
+	cifs_sb_target = CIFS_SB(target_inode->i_sb);
+	cifs_sb_source = CIFS_SB(source_inode->i_sb);
+	pTcon = cifs_sb_source->tcon;
+
+	if (pTcon != cifs_sb_target->tcon)
+		return -EXDEV;	/* BB actually could be allowed if same server, but
+                     different share. Might eventually add support for this */
+
+	fromName = build_path_from_dentry(source_direntry);
+	toName = build_path_from_dentry(target_direntry);
+
+	rc = CIFSSMBRename(xid, pTcon, fromName, toName,
+			   cifs_sb_source->local_nls);
+	if (fromName)
+		kfree(fromName);
+	if (toName)
+		kfree(toName);
+
+	return rc;
+}
+
+int
+cifs_revalidate(struct dentry *direntry)
+{
+	int xid;
+	int rc = 0;
+	char *full_path;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsInodeInfo *cifsInode;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(direntry->d_sb);
+
+	full_path = build_path_from_dentry(direntry);
+	cFYI(1,
+	     (" full path: %s for inode 0x%p with count %d dentry: 0x%p d_time %ld at time %ld \n",
+	      full_path, direntry->d_inode,
+	      direntry->d_inode->i_count.counter, direntry,
+	      direntry->d_time, jiffies));
+
+	cifsInode = CIFS_I(direntry->d_inode);
+
+	if ((time_before(jiffies, cifsInode->time + HZ))
+	    && (direntry->d_inode->i_nlink == 1)) {
+		cFYI(1, (" Do not need to revalidate "));
+		if (full_path)
+			kfree(full_path);
+		FreeXid(xid);
+		return rc;
+	}
+
+	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+		cifs_get_inode_info_unix(&direntry->d_inode, full_path,
+					 direntry->d_sb);
+	else
+		cifs_get_inode_info(&direntry->d_inode, full_path,
+				    direntry->d_sb);
+
+	/* BB if not oplocked, invalidate inode pages if mtime has changed */
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+
+	return rc;
+}
+
+void
+cifs_truncate_file(struct inode *inode)
+{				/* BB remove - may not need this function after all BB */
+	int xid;
+	int rc = 0;
+    struct cifsFileInfo *open_file = NULL;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	struct cifsInodeInfo *cifsInode;
+	struct dentry *dirent;
+	char *full_path = NULL;   
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	if (list_empty(&inode->i_dentry)) {
+		cERROR(1,
+		       ("Can not get pathname from empty dentry in inode 0x%p ",
+			inode));
+		FreeXid(xid);
+		return;
+	}
+	dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias);
+	if (dirent) {
+		full_path = build_path_from_dentry(dirent);
+		rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE,
+				   cifs_sb->local_nls);
+        cFYI(1,("\nSetEOF (truncate) rc = %d",rc));
+        if(rc == -ETXTBSY) {        
+            cifsInode = CIFS_I(inode);
+            if(!list_empty(&(cifsInode->openFileList))) {            
+	            open_file = list_entry(cifsInode->openFileList.next,
+                                       struct cifsFileInfo, flist);           
+                /* We could check if file is open for writing first and 
+                   also we could also override the smb pid with the pid 
+                   of the file opener when sending the CIFS request */
+                rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size,
+                                        open_file->netfid,open_file->pid,FALSE);
+            } else {
+                cFYI(1,("\nNo open files to get file handle from"));
+            }
+        }
+		if (!rc)
+			CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls);
+           /* allocation size setting seems optional so ignore return code */
+	}
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return;
+}
+
+int
+cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+{
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+	int rc = -EACCES;
+    struct cifsFileInfo *open_file = NULL;
+	FILE_BASIC_INFO time_buf;
+	int set_time = FALSE;
+	__u64 mode = 0xFFFFFFFFFFFFFFFF;
+	__u64 uid = 0xFFFFFFFFFFFFFFFF;
+	__u64 gid = 0xFFFFFFFFFFFFFFFF;
+	struct cifsInodeInfo *cifsInode;
+
+	xid = GetXid();
+
+	cFYI(1,
+	     ("\nIn cifs_setattr, name = %s attrs->iavalid 0x%x\n",
+	      direntry->d_name.name, attrs->ia_valid));
+	cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_path_from_dentry(direntry);
+	cifsInode = CIFS_I(direntry->d_inode);
+
+	/* BB check if we need to refresh inode from server now ? BB */
+
+	cFYI(1, ("\nChanging attributes 0x%x", attrs->ia_valid));
+
+	if (attrs->ia_valid & ATTR_SIZE) {
+		rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
+				   cifs_sb->local_nls);
+        cFYI(1,("\nSetEOF (setattrs) rc = %d",rc));
+
+        if(rc == -ETXTBSY) {
+            if(!list_empty(&(cifsInode->openFileList))) {            
+                open_file = list_entry(cifsInode->openFileList.next, 
+                               struct cifsFileInfo, flist);           
+    /* We could check if file is open for writing first */
+                rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
+                                        open_file->netfid,open_file->pid,FALSE);           
+            } else {
+                cFYI(1,("\nNo open files to get file handle from"));
+            }
+        }
+        /*  Set Allocation Size of file - might not even need to call the
+            following but might as well and it does not hurt if it fails */
+		CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);
+		if (rc == 0)
+			vmtruncate(direntry->d_inode, attrs->ia_size);
+		/* BB add special case to handle sharing violation (due to Samba bug)
+		   by calling SetFileInfo to set the sizes */
+	}
+	if (attrs->ia_valid & ATTR_UID) {
+		cFYI(1, ("\nCIFS - UID changed to %d", attrs->ia_uid));
+		uid = attrs->ia_uid;
+		/*        entry->uid = cpu_to_le16(attr->ia_uid); */
+	}
+	if (attrs->ia_valid & ATTR_GID) {
+		cFYI(1, ("\nCIFS - GID changed to %d", attrs->ia_gid));
+		gid = attrs->ia_gid;
+		/*      entry->gid = cpu_to_le16(attr->ia_gid); */
+	}
+	if (attrs->ia_valid & ATTR_MODE) {
+		cFYI(1, ("\nCIFS - Mode changed to 0x%x", attrs->ia_mode));
+		mode = attrs->ia_mode;
+		/*      entry->mode = cpu_to_le16(attr->ia_mode); */
+	}
+
+	if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+	    && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
+		CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
+				    cifs_sb->local_nls);
+	else {			/* BB to be implemented - via Windows security descriptors */
+		/* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
+	}
+
+	if (attrs->ia_valid & ATTR_ATIME) {
+		set_time = TRUE;
+		time_buf.LastAccessTime =
+		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
+	} else
+		time_buf.LastAccessTime = 0;
+
+	if (attrs->ia_valid & ATTR_MTIME) {
+		set_time = TRUE;
+		time_buf.LastWriteTime =
+		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
+	} else
+		time_buf.LastWriteTime = 0;
+
+	if (attrs->ia_valid & ATTR_CTIME) {
+		set_time = TRUE;
+		cFYI(1, ("\nCIFS - CTIME changed ")); /* BB probably do not need */
+		time_buf.ChangeTime =
+		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
+	} else
+		time_buf.ChangeTime = 0;
+
+	if (set_time) {		
+        /* BB handle errors better if one attribute not set 
+            (such as size) but time setting works */
+		time_buf.CreationTime = 0;	/* do not change */
+		time_buf.Attributes = 0;	/* BB is this ignored by server?  
+                        or do I have to query and reset anyway BB */
+		rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
+				     cifs_sb->local_nls);
+	}
+	cifsInode->time = 0; /* force revalidate to get attributes when needed */
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
+
+void
+cifs_delete_inode(struct inode *inode)
+{
+	/* Note: called without the big kernel filelock - remember spinlocks! */
+	cFYI(1, ("In cifs_delete_inode, inode = 0x%p\n", inode));
+	/* may have to add back in when safe distributed caching of
+             directories via e.g. FindNotify added */
+
+}
diff -Nru a/fs/cifs/link.c b/fs/cifs/link.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/link.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,219 @@
+/*
+ *   fs/cifs/link.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+
+int
+cifs_hardlink(struct dentry *old_file, struct inode *inode,
+	      struct dentry *direntry)
+{
+	int rc = -EACCES;
+	int xid;
+	char *fromName = NULL;
+	char *toName = NULL;
+	struct cifs_sb_info *cifs_sb_target;
+	struct cifsTconInfo *pTcon;
+	struct cifsInodeInfo *cifsInode;
+
+	xid = GetXid();
+
+	cifs_sb_target = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb_target->tcon;
+
+/* No need to check for cross device links since server will do that - BB note DFS case in future though (when we may have to check) */
+
+	fromName = build_path_from_dentry(old_file);
+	toName = build_path_from_dentry(direntry);
+	if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
+		rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
+					    cifs_sb_target->local_nls);
+	else
+		rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
+					cifs_sb_target->local_nls);
+
+/* if (!rc)     */
+	{
+		/*   renew_parental_timestamps(old_file);
+		   inode->i_nlink++;
+		   mark_inode_dirty(inode);
+		   d_instantiate(direntry, inode); */
+		/* BB add call to either mark inode dirty or refresh its data and timestamp to current time */
+	}
+	d_drop(direntry);	/* force new lookup from server */
+	cifsInode = CIFS_I(old_file->d_inode);
+	cifsInode->time = 0;	/* will force revalidate to go get info when needed */
+
+	if (fromName)
+		kfree(fromName);
+	if (toName)
+		kfree(toName);
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
+{
+	struct inode *inode = direntry->d_inode;
+	int rc = -EACCES;
+	int xid;
+	char *full_path = NULL;
+	char target_path[257];
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+
+	xid = GetXid();
+	full_path = build_path_from_dentry(direntry);
+	cFYI(1, ("\nFull path: %s inode = 0x%p\n", full_path, inode));
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	/* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */
+	/* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1);    */
+
+/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+	if (pTcon->ses->capabilities & CAP_UNIX)
+		rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
+					     target_path,
+					     sizeof (target_path) - 1,
+					     cifs_sb->local_nls);
+	else {
+		/* rc = CIFSSMBQueryReparseLinkInfo */
+		/* BB Add code to Query ReparsePoint info */
+	}
+	/* BB Anything else to do to handle recursive links? */
+	/* BB Should we be using page symlink ops here? */
+
+	if (rc == 0) {
+		target_path[256] = 0;
+		rc = vfs_follow_link(nd, target_path);
+	}
+	/* else EACCESS */
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
+{
+	int rc = -EOPNOTSUPP;
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+	struct inode *newinode = NULL;
+
+	xid = GetXid();
+
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+
+	full_path = build_path_from_dentry(direntry);
+	cFYI(1, ("\nFull path: %s ", full_path));
+	cFYI(1, (" symname is %s\n", symname));
+
+	/* BB what if DFS and this volume is on different share? BB */
+	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+		rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
+					   cifs_sb->local_nls);
+	/* else
+	   rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */
+
+	if (rc == 0) {
+		if (pTcon->ses->capabilities & CAP_UNIX)
+			rc = cifs_get_inode_info_unix(&newinode, full_path,
+						      inode->i_sb);
+		else
+			rc = cifs_get_inode_info(&newinode, full_path,
+						 inode->i_sb);
+
+		if (rc != 0) {
+			cFYI(1,
+			     ("\nCreate symlink worked but get_inode_info failed with rc = %d ",
+			      rc));
+		} else {
+			direntry->d_op = &cifs_dentry_ops;
+			d_instantiate(direntry, newinode);
+		}
+	}
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
+
+int
+cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
+{
+	struct inode *inode = direntry->d_inode;
+	int rc = -EACCES;
+	int xid;
+	struct cifs_sb_info *cifs_sb;
+	struct cifsTconInfo *pTcon;
+	char *full_path = NULL;
+	char tmpbuffer[256];
+
+	xid = GetXid();
+	cifs_sb = CIFS_SB(inode->i_sb);
+	pTcon = cifs_sb->tcon;
+	full_path = build_path_from_dentry(direntry);
+	cFYI(1,
+	     ("\nFull path: %s inode = 0x%p pBuffer = 0x%p buflen = %d\n",
+	      full_path, inode, pBuffer, buflen));
+
+/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+		rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
+					     tmpbuffer,
+					     sizeof (tmpbuffer) - 1,
+					     cifs_sb->local_nls);
+	else {
+		/* rc = CIFSSMBQueryReparseLinkInfo */
+		/* BB Add code to Query ReparsePoint info */
+	}
+	/* BB Anything else to do to handle recursive links? */
+	/* BB Should we be using page ops here? */
+
+	/* BB null terminate returned string in pBuffer? BB */
+	if (buflen > sizeof (tmpbuffer))
+		buflen = sizeof (tmpbuffer);
+	if (rc == 0) {
+		rc = vfs_readlink(direntry, pBuffer, buflen, tmpbuffer);
+		cFYI(1,
+		     ("vfs_readlink called from cifs_readlink returned %d",
+		      rc));
+	}
+
+	if (full_path)
+		kfree(full_path);
+	FreeXid(xid);
+	return rc;
+}
diff -Nru a/fs/cifs/md4.c b/fs/cifs/md4.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/md4.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,209 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   a implementation of MD4 designed for use in the SMB authentication protocol
+   Copyright (C) Andrew Tridgell 1997-1998.
+   Modified by Steve French (sfrench@us.ibm.com) 2002
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include <linux/module.h>
+#include <linux/fs.h>
+
+/* NOTE: This code makes no attempt to be fast! 
+
+   It assumes that a int is at least 32 bits long
+*/
+
+static __u32 A, B, C, D;
+
+static __u32
+F(__u32 X, __u32 Y, __u32 Z)
+{
+	return (X & Y) | ((~X) & Z);
+}
+
+static __u32
+G(__u32 X, __u32 Y, __u32 Z)
+{
+	return (X & Y) | (X & Z) | (Y & Z);
+}
+
+static __u32
+H(__u32 X, __u32 Y, __u32 Z)
+{
+	return X ^ Y ^ Z;
+}
+
+static __u32
+lshift(__u32 x, int s)
+{
+	x &= 0xFFFFFFFF;
+	return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (__u32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (__u32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void
+mdfour64(__u32 * M)
+{
+	int j;
+	__u32 AA, BB, CC, DD;
+	__u32 X[16];
+
+	for (j = 0; j < 16; j++)
+		X[j] = M[j];
+
+	AA = A;
+	BB = B;
+	CC = C;
+	DD = D;
+
+	ROUND1(A, B, C, D, 0, 3);
+	ROUND1(D, A, B, C, 1, 7);
+	ROUND1(C, D, A, B, 2, 11);
+	ROUND1(B, C, D, A, 3, 19);
+	ROUND1(A, B, C, D, 4, 3);
+	ROUND1(D, A, B, C, 5, 7);
+	ROUND1(C, D, A, B, 6, 11);
+	ROUND1(B, C, D, A, 7, 19);
+	ROUND1(A, B, C, D, 8, 3);
+	ROUND1(D, A, B, C, 9, 7);
+	ROUND1(C, D, A, B, 10, 11);
+	ROUND1(B, C, D, A, 11, 19);
+	ROUND1(A, B, C, D, 12, 3);
+	ROUND1(D, A, B, C, 13, 7);
+	ROUND1(C, D, A, B, 14, 11);
+	ROUND1(B, C, D, A, 15, 19);
+
+	ROUND2(A, B, C, D, 0, 3);
+	ROUND2(D, A, B, C, 4, 5);
+	ROUND2(C, D, A, B, 8, 9);
+	ROUND2(B, C, D, A, 12, 13);
+	ROUND2(A, B, C, D, 1, 3);
+	ROUND2(D, A, B, C, 5, 5);
+	ROUND2(C, D, A, B, 9, 9);
+	ROUND2(B, C, D, A, 13, 13);
+	ROUND2(A, B, C, D, 2, 3);
+	ROUND2(D, A, B, C, 6, 5);
+	ROUND2(C, D, A, B, 10, 9);
+	ROUND2(B, C, D, A, 14, 13);
+	ROUND2(A, B, C, D, 3, 3);
+	ROUND2(D, A, B, C, 7, 5);
+	ROUND2(C, D, A, B, 11, 9);
+	ROUND2(B, C, D, A, 15, 13);
+
+	ROUND3(A, B, C, D, 0, 3);
+	ROUND3(D, A, B, C, 8, 9);
+	ROUND3(C, D, A, B, 4, 11);
+	ROUND3(B, C, D, A, 12, 15);
+	ROUND3(A, B, C, D, 2, 3);
+	ROUND3(D, A, B, C, 10, 9);
+	ROUND3(C, D, A, B, 6, 11);
+	ROUND3(B, C, D, A, 14, 15);
+	ROUND3(A, B, C, D, 1, 3);
+	ROUND3(D, A, B, C, 9, 9);
+	ROUND3(C, D, A, B, 5, 11);
+	ROUND3(B, C, D, A, 13, 15);
+	ROUND3(A, B, C, D, 3, 3);
+	ROUND3(D, A, B, C, 11, 9);
+	ROUND3(C, D, A, B, 7, 11);
+	ROUND3(B, C, D, A, 15, 15);
+
+	A += AA;
+	B += BB;
+	C += CC;
+	D += DD;
+
+	A &= 0xFFFFFFFF;
+	B &= 0xFFFFFFFF;
+	C &= 0xFFFFFFFF;
+	D &= 0xFFFFFFFF;
+
+	for (j = 0; j < 16; j++)
+		X[j] = 0;
+}
+
+static void
+copy64(__u32 * M, unsigned char *in)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
+		    (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
+}
+
+static void
+copy4(unsigned char *out, __u32 x)
+{
+	out[0] = x & 0xFF;
+	out[1] = (x >> 8) & 0xFF;
+	out[2] = (x >> 16) & 0xFF;
+	out[3] = (x >> 24) & 0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void
+mdfour(unsigned char *out, unsigned char *in, int n)
+{
+	unsigned char buf[128];
+	__u32 M[16];
+	__u32 b = n * 8;
+	int i;
+
+	A = 0x67452301;
+	B = 0xefcdab89;
+	C = 0x98badcfe;
+	D = 0x10325476;
+
+	while (n > 64) {
+		copy64(M, in);
+		mdfour64(M);
+		in += 64;
+		n -= 64;
+	}
+
+	for (i = 0; i < 128; i++)
+		buf[i] = 0;
+	memcpy(buf, in, n);
+	buf[n] = 0x80;
+
+	if (n <= 55) {
+		copy4(buf + 56, b);
+		copy64(M, buf);
+		mdfour64(M);
+	} else {
+		copy4(buf + 120, b);
+		copy64(M, buf);
+		mdfour64(M);
+		copy64(M, buf + 64);
+		mdfour64(M);
+	}
+
+	for (i = 0; i < 128; i++)
+		buf[i] = 0;
+	copy64(M, buf);
+
+	copy4(out, A);
+	copy4(out + 4, B);
+	copy4(out + 8, C);
+	copy4(out + 12, D);
+
+	A = B = C = D = 0;
+}
diff -Nru a/fs/cifs/md5.c b/fs/cifs/md5.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/md5.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,363 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code slightly modified to fit into Samba by 
+   abartlet@samba.org Jun 2001 
+   and to fit the cifs vfs by 
+   Steve French sfrench@us.ibm.com */
+
+#include <linux/fs.h>
+#include "md5.h"
+
+static void MD5Transform(__u32 buf[4], __u32 const in[16]);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void
+byteReverse(unsigned char *buf, unsigned longs)
+{
+	__u32 t;
+	do {
+		t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+		    ((unsigned) buf[1] << 8 | buf[0]);
+		*(__u32 *) buf = t;
+		buf += 4;
+	} while (--longs);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+	ctx->buf[0] = 0x67452301;
+	ctx->buf[1] = 0xefcdab89;
+	ctx->buf[2] = 0x98badcfe;
+	ctx->buf[3] = 0x10325476;
+
+	ctx->bits[0] = 0;
+	ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+	register __u32 t;
+
+	/* Update bitcount */
+
+	t = ctx->bits[0];
+	if ((ctx->bits[0] = t + ((__u32) len << 3)) < t)
+		ctx->bits[1]++;	/* Carry from low to high */
+	ctx->bits[1] += len >> 29;
+
+	t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+	/* Handle any leading odd-sized chunks */
+
+	if (t) {
+		unsigned char *p = (unsigned char *) ctx->in + t;
+
+		t = 64 - t;
+		if (len < t) {
+			memmove(p, buf, len);
+			return;
+		}
+		memmove(p, buf, t);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (__u32 *) ctx->in);
+		buf += t;
+		len -= t;
+	}
+	/* Process data in 64-byte chunks */
+
+	while (len >= 64) {
+		memmove(ctx->in, buf, 64);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (__u32 *) ctx->in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* Handle any remaining bytes of data. */
+
+	memmove(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+	unsigned int count;
+	unsigned char *p;
+
+	/* Compute number of bytes mod 64 */
+	count = (ctx->bits[0] >> 3) & 0x3F;
+
+	/* Set the first char of padding to 0x80.  This is safe since there is
+	   always at least one byte free */
+	p = ctx->in + count;
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 64 bytes */
+	count = 64 - 1 - count;
+
+	/* Pad out to 56 mod 64 */
+	if (count < 8) {
+		/* Two lots of padding:  Pad the first block to 64 bytes */
+		memset(p, 0, count);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (__u32 *) ctx->in);
+
+		/* Now fill the next block with 56 bytes */
+		memset(ctx->in, 0, 56);
+	} else {
+		/* Pad block to 56 bytes */
+		memset(p, 0, count - 8);
+	}
+	byteReverse(ctx->in, 14);
+
+	/* Append length in bits and transform */
+	((__u32 *) ctx->in)[14] = ctx->bits[0];
+	((__u32 *) ctx->in)[15] = ctx->bits[1];
+
+	MD5Transform(ctx->buf, (__u32 *) ctx->in);
+	byteReverse((unsigned char *) ctx->buf, 4);
+	memmove(digest, ctx->buf, 16);
+	memset(ctx, 0, sizeof (ctx));	/* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD5Transform(__u32 buf[4], __u32 const in[16])
+{
+	register __u32 a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+/***********************************************************************
+ the rfc 2104 version of hmac_md5 initialisation.
+***********************************************************************/
+void
+hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+		      struct HMACMD5Context *ctx)
+{
+	int i;
+
+	/* if key is longer than 64 bytes reset it to key=MD5(key) */
+	if (key_len > 64) {
+		unsigned char tk[16];
+		struct MD5Context tctx;
+
+		MD5Init(&tctx);
+		MD5Update(&tctx, key, key_len);
+		MD5Final(tk, &tctx);
+
+		key = tk;
+		key_len = 16;
+	}
+
+	/* start out by storing key in pads */
+	memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
+	memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
+	memcpy(ctx->k_ipad, key, key_len);
+	memcpy(ctx->k_opad, key, key_len);
+
+	/* XOR key with ipad and opad values */
+	for (i = 0; i < 64; i++) {
+		ctx->k_ipad[i] ^= 0x36;
+		ctx->k_opad[i] ^= 0x5c;
+	}
+
+	MD5Init(&ctx->ctx);
+	MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ the microsoft version of hmac_md5 initialisation.
+***********************************************************************/
+void
+hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
+			 struct HMACMD5Context *ctx)
+{
+	int i;
+
+	/* if key is longer than 64 bytes truncate it */
+	if (key_len > 64) {
+		key_len = 64;
+	}
+
+	/* start out by storing key in pads */
+	memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
+	memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
+	memcpy(ctx->k_ipad, key, key_len);
+	memcpy(ctx->k_opad, key, key_len);
+
+	/* XOR key with ipad and opad values */
+	for (i = 0; i < 64; i++) {
+		ctx->k_ipad[i] ^= 0x36;
+		ctx->k_opad[i] ^= 0x5c;
+	}
+
+	MD5Init(&ctx->ctx);
+	MD5Update(&ctx->ctx, ctx->k_ipad, 64);
+}
+
+/***********************************************************************
+ update hmac_md5 "inner" buffer
+***********************************************************************/
+void
+hmac_md5_update(const unsigned char *text, int text_len,
+		struct HMACMD5Context *ctx)
+{
+	MD5Update(&ctx->ctx, text, text_len);	/* then text of datagram */
+}
+
+/***********************************************************************
+ finish off hmac_md5 "inner" buffer and generate outer one.
+***********************************************************************/
+void
+hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
+{
+	struct MD5Context ctx_o;
+
+	MD5Final(digest, &ctx->ctx);
+
+	MD5Init(&ctx_o);
+	MD5Update(&ctx_o, ctx->k_opad, 64);
+	MD5Update(&ctx_o, digest, 16);
+	MD5Final(digest, &ctx_o);
+}
+
+/***********************************************************
+ single function to calculate an HMAC MD5 digest from data.
+ use the microsoft hmacmd5 init method because the key is 16 bytes.
+************************************************************/
+void
+hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+	 unsigned char *digest)
+{
+	struct HMACMD5Context ctx;
+	hmac_md5_init_limK_to_64(key, 16, &ctx);
+	if (data_len != 0) {
+		hmac_md5_update(data, data_len, &ctx);
+	}
+	hmac_md5_final(digest, &ctx);
+}
diff -Nru a/fs/cifs/md5.h b/fs/cifs/md5.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/md5.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,38 @@
+#ifndef MD5_H
+#define MD5_H
+#ifndef HEADER_MD5_H
+/* Try to avoid clashes with OpenSSL */
+#define HEADER_MD5_H
+#endif
+
+struct MD5Context {
+	__u32 buf[4];
+	__u32 bits[2];
+	unsigned char in[64];
+};
+#endif				/* !MD5_H */
+
+#ifndef _HMAC_MD5_H
+struct HMACMD5Context {
+	struct MD5Context ctx;
+	unsigned char k_ipad[65];
+	unsigned char k_opad[65];
+};
+#endif				/* _HMAC_MD5_H */
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+/* The following definitions come from lib/hmacmd5.c  */
+
+void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+			   struct HMACMD5Context *ctx);
+void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
+			      struct HMACMD5Context *ctx);
+void hmac_md5_update(const unsigned char *text, int text_len,
+		     struct HMACMD5Context *ctx);
+void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
+void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+	      unsigned char *digest);
diff -Nru a/fs/cifs/misc.c b/fs/cifs/misc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/misc.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,362 @@
+/*
+ *   fs/cifs/misc.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+
+extern kmem_cache_t *cifs_req_cachep;
+
+static DECLARE_MUTEX(GlobalMid_Sem);	/* also protects XID globals */
+__u16 GlobalMid;		/* multiplex id - rotating counter */
+
+/* The xid serves as a useful identifier for each incoming vfs request, 
+   in a similar way to the mid which is useful to track each sent smb, 
+   and CurrentXid can also provide a running counter (although it 
+   will eventually wrap past zero) of the total vfs operations handled 
+   since the cifs fs was mounted */
+
+unsigned int
+_GetXid(void)
+{
+	unsigned int xid;
+
+	down(&GlobalMid_Sem);
+	GlobalTotalActiveXid++;
+	if (GlobalTotalActiveXid > GlobalMaxActiveXid)
+		GlobalMaxActiveXid = GlobalTotalActiveXid;	/* keep high water mark for number of simultaneous vfs ops in our filesystem */
+	xid = GlobalCurrentXid++;
+	up(&GlobalMid_Sem);
+	return xid;
+}
+
+void
+_FreeXid(unsigned int xid)
+{
+	down(&GlobalMid_Sem);
+	GlobalTotalActiveXid--;
+	up(&GlobalMid_Sem);
+}
+
+struct cifsSesInfo *
+sesInfoAlloc(void)
+{
+	struct cifsSesInfo *ret_buf;
+
+	ret_buf =
+	    (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo),
+					   GFP_KERNEL);
+	if (ret_buf) {
+		memset(ret_buf, 0, sizeof (struct cifsSesInfo));
+		atomic_inc(&sesInfoAllocCount);
+		list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
+		init_MUTEX(&ret_buf->sesSem);
+	}
+	return ret_buf;
+}
+
+void
+sesInfoFree(struct cifsSesInfo *buf_to_free)
+{
+	if (buf_to_free == NULL) {
+		cFYI(1, ("\nNull buffer passed to sesInfoFree"));
+		return;
+	}
+
+	atomic_dec(&sesInfoAllocCount);
+	list_del(&buf_to_free->cifsSessionList);
+	if (buf_to_free->serverOS)
+		kfree(buf_to_free->serverOS);
+	if (buf_to_free->serverDomain)
+		kfree(buf_to_free->serverDomain);
+	if (buf_to_free->serverNOS)
+		kfree(buf_to_free->serverNOS);
+	kfree(buf_to_free);
+}
+
+struct cifsTconInfo *
+tconInfoAlloc(void)
+{
+	struct cifsTconInfo *ret_buf;
+	ret_buf =
+	    (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo),
+					    GFP_KERNEL);
+	if (ret_buf) {
+		memset(ret_buf, 0, sizeof (struct cifsTconInfo));
+		atomic_inc(&tconInfoAllocCount);
+		list_add(&ret_buf->cifsConnectionList,
+			 &GlobalTreeConnectionList);
+        INIT_LIST_HEAD(&ret_buf->openFileList);
+		init_MUTEX(&ret_buf->tconSem);
+	}
+	return ret_buf;
+}
+
+void
+tconInfoFree(struct cifsTconInfo *buf_to_free)
+{
+	if (buf_to_free == NULL) {
+		cFYI(1, ("\nNull buffer passed to tconInfoFree"));
+		return;
+	}
+
+	atomic_dec(&tconInfoAllocCount);
+	list_del(&buf_to_free->cifsConnectionList);
+	if (buf_to_free->nativeFileSystem)
+		kfree(buf_to_free->nativeFileSystem);
+	kfree(buf_to_free);
+}
+
+void *
+kcalloc(size_t size, int type)
+{
+	void *addr;
+	addr = kmalloc(size, type);
+	if (addr)
+		memset(addr, 0, size);
+	return addr;
+}
+
+struct smb_hdr *
+buf_get(void)
+{
+	struct smb_hdr *ret_buf;
+
+/* We could use negotiated size instead of max_msgsize - 
+   but it may be more efficient to always alloc same size 
+   albeit slightly larger */
+	ret_buf =
+	    (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL);
+
+	/* clear the first few header bytes */
+	if (ret_buf) {
+		memset(ret_buf, 0, sizeof (struct smb_hdr));
+		atomic_inc(&bufAllocCount);
+	}
+
+	return ret_buf;
+}
+
+void
+buf_release(void *buf_to_free)
+{
+
+	if (buf_to_free == NULL) {
+		cFYI(1, ("\nNull buffer passed to buf_release"));
+		return;
+	}
+	kmem_cache_free(cifs_req_cachep, buf_to_free);
+
+	atomic_dec(&bufAllocCount);
+	return;
+}
+
+void
+header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
+		const struct cifsTconInfo *treeCon, int word_count
+		/* length of fixed section (word count) in two byte units  */
+    )
+{
+	int i;
+	__u32 tmp;
+	char *temp = (char *) buffer;
+
+	for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) {
+		temp[i] = 0;	/* BB is this needed ?? */
+	}
+
+	buffer->smb_buf_length =
+	    (2 * word_count) + sizeof (struct smb_hdr) -
+	    4 /*  RFC 1001 length field does not count */  +
+	    2 /* for bcc field itself */ ;
+	/* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
+
+	buffer->Protocol[0] = 0xFF;
+	buffer->Protocol[1] = 'S';
+	buffer->Protocol[2] = 'M';
+	buffer->Protocol[3] = 'B';
+	buffer->Command = smb_command;
+	buffer->Flags = 0x00;	/* case sensitive */
+	buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
+	tmp = cpu_to_le32(current->pid);
+	buffer->Pid = tmp & 0xFFFF;
+	tmp >>= 16;
+	buffer->PidHigh = tmp & 0xFFFF;
+	down(&GlobalMid_Sem);
+	GlobalMid++;
+	buffer->Mid = GlobalMid;
+	if (treeCon) {
+		buffer->Tid = treeCon->tid;
+		if (treeCon->ses) {
+			if (treeCon->ses->capabilities & CAP_UNICODE)
+				buffer->Flags2 |= SMBFLG2_UNICODE;
+			if (treeCon->ses->capabilities & CAP_STATUS32) {
+				buffer->Flags2 |= SMBFLG2_ERR_STATUS;
+			}
+			buffer->Uid = treeCon->ses->Suid;	/* always in LE format */
+		}
+		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
+			buffer->Flags2 |= SMBFLG2_DFS;
+        if(treeCon->ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+            buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	}
+
+/*  endian conversion of flags is now done just before sending */
+	up(&GlobalMid_Sem);
+	buffer->WordCount = (char) word_count;
+	return;
+}
+
+int
+checkSMBhdr(struct smb_hdr *smb, __u16 mid)
+{
+	/* Make sure that this really is an SMB, that it is a response, 
+        and that the message ids match */
+	if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && (mid == smb->Mid)) {    
+        if(smb->Flags & SMBFLG_RESPONSE)
+            return 0;                    
+        else {        
+    /* only one valid case where server sends us request */
+            if(smb->Command == SMB_COM_LOCKING_ANDX)
+                return 0;
+            else
+                cERROR(1, ("\n Rcvd Request not response "));         
+        }
+	} else { /* bad signature or mid */
+		if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff))
+			cERROR(1,
+			       ("\nBad protocol string signature header %x ",
+				*(unsigned int *) smb->Protocol));
+		if (mid != smb->Mid)
+			cERROR(1, ("\n Mids do not match \n"));
+	}
+    cERROR(1, ("\nCIFS: bad smb detected. The Mid=%d\n", smb->Mid));
+    return 1;
+}
+
+int
+checkSMB(struct smb_hdr *smb, __u16 mid, int length)
+{
+	cFYI(0,
+	     ("\nEntering checkSMB with Length: %x, smb_buf_length: %x ",
+	      length, ntohl(smb->smb_buf_length)));
+	if ((length < 2 + sizeof (struct smb_hdr))
+	    || (4 + ntohl(smb->smb_buf_length) >
+		CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)) {
+		if (length < 2 + sizeof (struct smb_hdr)) {
+			cERROR(1, ("\n Length less than 2 + sizeof smb_hdr "));
+			if ((length >= sizeof (struct smb_hdr) - 1)
+			    && (smb->Status.CifsError != 0))
+				return 0;	/* this is ok - some error cases do not return wct and bcc */
+
+		}
+		if (4 + ntohl(smb->smb_buf_length) >
+		    CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
+			cERROR(1,
+			       ("\n smb_buf_length greater than CIFS_MAX_MSGSIZE ... "));
+		cERROR(1,
+		       ("CIFS: bad smb detected. Illegal length. The mid=%d\n",
+			smb->Mid));
+		return 1;
+	}
+
+	if (checkSMBhdr(smb, mid))
+		return 1;
+
+	if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb))
+	    || (4 + ntohl(smb->smb_buf_length) != length)) {
+		return 0;
+	} else {
+		cERROR(1, ("\nCIFS: smbCalcSize %x ", smbCalcSize(smb)));
+		cERROR(1,
+		       ("CIFS: bad smb size detected. The Mid=%d\n", smb->Mid));
+		return 1;
+	}
+}
+int
+is_valid_oplock_break(struct smb_hdr *buf)
+{    
+    struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
+
+    /* could add check for smb response flag 0x80 */
+    cFYI(1,("\nChecking for oplock break"));    
+    if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
+        return FALSE;
+    if(pSMB->hdr.Flags & SMBFLG_RESPONSE)
+        return FALSE; /* server sends us "request" here */
+    if(pSMB->hdr.WordCount != 8)
+        return FALSE;
+
+    cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
+    if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
+        return FALSE;    
+
+    /* BB Add following logic: 
+       1) look up tcon based on tid & uid 
+       2) look up inode from tcon->openFileList->file->f_dentry->d_inode 
+       3) flush dirty pages and cached byte range locks and mark inode   
+       4) depending on break type change to r/o caching or no caching
+       5) send oplock break response to server */
+    cFYI(1,("\nNeed to process oplock break "));
+
+    return TRUE;
+}
+
+void
+dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
+{
+	int i, j;
+	char debug_line[17];
+	unsigned char *buffer;
+
+	if (traceSMB == 0)
+		return;
+
+	buffer = (unsigned char *) smb_buf;
+	for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
+		if (i % 8 == 0) {	/* we have reached the beginning of line  */
+			printk("\n| ");
+			j = 0;
+		}
+		printk("%0#4x ", buffer[i]);
+		debug_line[2 * j] = ' ';
+		if (isprint(buffer[i]))
+			debug_line[1 + (2 * j)] = buffer[i];
+		else
+			debug_line[1 + (2 * j)] = '_';
+
+		if (i % 8 == 7) {	/* we have reached end of line, time to print ascii */
+			debug_line[16] = 0;
+			printk(" | %s", debug_line);
+		}
+	}
+	for (; j < 8; j++) {
+		printk("     ");
+		debug_line[2 * j] = ' ';
+		debug_line[1 + (2 * j)] = ' ';
+	}
+	printk(" | %s\n", debug_line);
+	return;
+}
diff -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/netmisc.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,879 @@
+/*
+ *   fs/cifs/netmisc.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ * 
+ *   Error mapping routines from Samba libsmb/errormap.c
+ *   Copyright (C) Andrew Tridgell 2001
+ *
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <asm/div64.h>
+#include <asm/byteorder.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "smberr.h"
+#include "cifs_debug.h"
+#include "nterr.h"
+
+struct smb_to_posix_error {
+	__u16 smb_err;
+	int posix_code;
+};
+
+const struct smb_to_posix_error mapping_table_ERRDOS[] = {
+	{ERRbadfunc, -EINVAL},
+	{ERRbadfile, -ENOENT},
+	{ERRbadpath, -ENOENT},
+	{ERRnofids, -EMFILE},
+	{ERRnoaccess, -EACCES},
+	{ERRbadfid, -EBADF},
+	{ERRbadmcb, -EIO},
+	{ERRnomem, -ENOMEM},
+	{ERRbadmem, -EFAULT},
+	{ERRbadenv, -EFAULT},
+	{ERRbadformat, -EINVAL},
+	{ERRbadaccess, -EACCES},
+	{ERRbaddata, -EIO},
+	{ERRbaddrive, -ENXIO},
+	{ERRremcd, -EACCES},
+	{ERRdiffdevice, -EXDEV},
+	{ERRnofiles, -ENOENT},
+	{ERRbadshare, -ETXTBSY},
+	{ERRlock, -EACCES},
+	{ERRfilexists, -EINVAL},
+	{ERRinvparm, -EINVAL},
+	{ERRdiskfull, -ENOSPC},
+	{ERRinvnum, -EINVAL},
+	{ERRdirnotempty, -ENOTEMPTY},
+	{ERRnotlocked, -ENOLCK},
+	{ERRalreadyexists, -EEXIST},
+	{ERRmoredata, -EOVERFLOW},
+	{ErrQuota, -EDQUOT},
+	{ErrNotALink, -ENOLINK},
+	{0, 0}
+};
+
+const struct smb_to_posix_error mapping_table_ERRSRV[] = {
+	{ERRerror, -EIO},
+	{ERRbadpw, -EACCES},
+	{ERRbadtype, -EREMOTE},
+	{ERRaccess, -EACCES},
+	{ERRinvtid, -ENXIO},
+	{ERRinvnetname, -ENOENT},
+	{ERRinvdevice, -ENXIO},
+	{ERRqfull, -ENOSPC},
+	{ERRqtoobig, -ENOSPC},
+	{ERRqeof, -EIO},
+	{ERRinvpfid, -EBADF},
+	{ERRsmbcmd, -EBADRQC},
+	{ERRsrverror, -EIO},
+	{ERRbadBID, -EIO},
+	{ERRfilespecs, -EINVAL},
+	{ERRbadLink, -EIO},
+	{ERRbadpermits, -EINVAL},
+	{ERRbadPID, -ESRCH},
+	{ERRsetattrmode, -EINVAL},
+	{ERRpaused, -EHOSTDOWN},
+	{ERRmsgoff, -EHOSTDOWN},
+	{ERRnoroom, -ENOSPC},
+	{ERRrmuns, -EUSERS},
+	{ERRtimeout, -ETIME},
+	{ERRnoresource, -ENOBUFS},
+	{ERRtoomanyuids, -EUSERS},
+	{ERRbaduid, -EACCES},
+	{ERRusempx, -EIO},
+	{ERRusestd, -EIO},
+	{ERR_NOTIFY_ENUM_DIR, -ENOBUFS},
+	{ERRaccountexpired, -EACCES},
+	{ERRbadclient, -EACCES},
+	{ERRbadLogonTime, -EACCES},
+	{ERRpasswordExpired, -EACCES},
+	{ERRnosupport, -EINVAL},
+	{0, 0}
+};
+
+const struct smb_to_posix_error mapping_table_ERRHRD[] = {
+	{0, 0}
+};
+
+/* Convert string containing dotted ip address to binary form */
+/* returns 0 if invalid address */
+
+/* BB add address family, change rc to status flag and return *//* also see inet_pton */
+/* To identify v4 vs. v6 - 1) check for colon (v6 only) 2) then call inet_pton to parse for bad address  */
+int
+inet_addr(char *cp)
+{
+	struct in_addr address;
+	int value;
+	int digit;
+	int i;
+	char temp;
+	char bytes[4];
+	char *end = bytes;
+	static const int addr_class_max[4] =
+	    { 0xffffffff, 0xffffff, 0xffff, 0xff };
+
+	for (i = 0; i < 4; i++) {
+		bytes[i] = 0;
+	}
+
+	temp = *cp;
+
+	while (TRUE) {
+		if (!isdigit(temp))
+			return 0;
+
+		value = 0;
+		digit = 0;
+		for (;;) {
+			if (isascii(temp) && isdigit(temp)) {
+				value = (value * 10) + temp - '0';
+				temp = *++cp;
+				digit = 1;
+			} else
+				break;
+		}
+
+		if (temp == '.') {
+			if ((end > bytes + 2) || (value > 255))
+				return 0;
+			*end++ = value;
+			temp = *++cp;
+		} else
+			break;
+	}
+
+	/* check for last characters */
+	if (temp != '\0' && (!isascii(temp) || !isspace(temp)))
+		if (temp != '\\') {
+			if (temp != '/')
+				return 0;
+			else
+				(*cp = '\\');	/* switch the slash the expected way */
+		}
+	if (value > addr_class_max[end - bytes])
+		return 0;
+
+	address.s_addr = *((int *) bytes) | htonl(value);
+	return address.s_addr;
+
+}
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+/* NT status -> dos error map */
+const static struct {
+	__u8 dos_class;
+	__u16 dos_code;
+	__u32 ntstatus;
+} ntstatus_to_dos_map[] = {
+	{
+	ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
+	ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
+	ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, {
+	ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, {
+	ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, {
+	ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, {
+	ERRDOS, 87, NT_STATUS_INVALID_CID}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, {
+	ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, {
+	ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, {
+	ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, {
+	ERRDOS, 38, NT_STATUS_END_OF_FILE}, {
+	ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, {
+	ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, {
+	ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+/*	{ This NT error code was 'sqashed'
+	 from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK 
+	 during the session setup } */
+	{
+	ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, {
+	ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, {
+	ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, {
+	ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, {
+	ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, {
+	ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, {
+	ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
+/*	{ This NT error code was 'sqashed'
+	 from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 
+	 during the session setup }   */
+	{
+	ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, {
+	ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, {
+	ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, {
+	ERRDOS, 158, NT_STATUS_NOT_LOCKED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, {
+	ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, {
+	ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, {
+	ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, {	/* mapping changed since shell does lookup on * and expects file not found */
+	ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, {
+	ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, {
+	ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, {
+	ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, {
+	ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, {
+	ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, {
+	ERRDOS, 23, NT_STATUS_DATA_ERROR}, {
+	ERRDOS, 23, NT_STATUS_CRC_ERROR}, {
+	ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, {
+	ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, {
+	ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, {
+	ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, {
+	ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, {
+	ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, {
+	ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, {
+	ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, {
+	ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, {
+	ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, {
+	ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, {
+	ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, {
+	ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, {
+	ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, {
+	ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_DELETE_PENDING}, {
+	ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, {
+	ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, {
+	ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
+/*	{ This NT error code was 'sqashed'
+	 from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE 
+	 during the session setup } */
+	{
+	ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
+/*	{ This NT error code was 'sqashed'
+	 from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE 
+	 during the session setup } */
+	{
+	ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
+	ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
+	ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
+	ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, {
+	ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, {
+	ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, {
+	ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, {
+	ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, {
+	ERRDOS, 112, NT_STATUS_DISK_FULL}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, {
+	ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, {
+	ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, {
+	ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, {
+	ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, {
+	ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, {
+	ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, {
+	ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, {
+	ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+/*	{ This NT error code was 'sqashed'
+	 from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES 
+	 during the session setup } */
+	{
+	ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
+	ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
+	ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, {
+	ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, {
+	ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, {
+	ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, {
+	ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, {
+	ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, {
+	ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, {
+	ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, {
+	ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, {
+	ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, {
+	ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, {
+	ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, {
+	ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, {
+	ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, {
+	ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, {
+	ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, {
+	ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, {
+	ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, {
+	ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, {
+	ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, {
+	ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, {
+	ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, {
+	ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, {
+	ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, {
+	ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, {
+	ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, {
+	ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, {
+	ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, {
+	ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, {
+	ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, {
+	ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, {
+	ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, {
+	ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, {
+	ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, {
+	ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, {
+	ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, {
+	ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, {
+	ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, {
+	ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, {
+	ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, {
+	ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, {
+	ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, {
+	ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, {
+	ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, {
+	ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, {
+	ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, {
+	ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, {
+	ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, {
+	ERRDOS, 203, 0xc0000100}, {
+	ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, {
+	ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, {
+	ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, {
+	ERRDOS, 2401, NT_STATUS_FILES_OPEN}, {
+	ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, {
+	ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, {
+	ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, {
+	ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, {
+	ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, {
+	ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, {
+	ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, {
+	ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, {
+	ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, {
+	ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, {
+	ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, {
+	ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, {
+	ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, {
+	ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, {
+	ERRDOS, 59, NT_STATUS_LINK_FAILED}, {
+	ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, {
+	ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, {
+	ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, {
+	ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, {
+	ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, {
+	ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, {
+	ERRHRD, ERRgeneral, 0xc000016e}, {
+	ERRHRD, ERRgeneral, 0xc000016f}, {
+	ERRHRD, ERRgeneral, 0xc0000170}, {
+	ERRHRD, ERRgeneral, 0xc0000171}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, {
+	ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, {
+	ERRHRD, ERRgeneral, 0xc0000179}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, {
+	ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, {
+	ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, {
+	ERRDOS, 19, NT_STATUS_TOO_LATE}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
+/*	{ This NT error code was 'sqashed'
+	 from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 
+	 during the session setup } */
+	{
+	ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, {
+	ERRDOS, 2455, NT_STATUS_NETLOGON_NOT_STARTED}, {
+	ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+/*	{ This NT error code was 'sqashed'
+	 from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE 
+	 during the session setup }  */
+	{
+	ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, {
+	ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, {
+	ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, {
+	ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, {
+	ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, {
+	ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, {
+	ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, {
+	ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, {
+	ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, {
+	ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, {
+	ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, {
+	ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, {
+	ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, {
+	ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, {
+	ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, {
+	ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, {
+	ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, {
+	ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, {
+	ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
+	ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, {
+	ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_RETRY}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, {
+	ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, {
+	ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, {
+	ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, {
+	ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, {
+	ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, {
+	ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, {
+	ERRHRD, ERRgeneral, 0xc000024a}, {
+	ERRHRD, ERRgeneral, 0xc000024b}, {
+	ERRHRD, ERRgeneral, 0xc000024c}, {
+	ERRHRD, ERRgeneral, 0xc000024d}, {
+	ERRHRD, ERRgeneral, 0xc000024e}, {
+	ERRHRD, ERRgeneral, 0xc000024f}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, {
+	ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, {
+	ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, {
+	ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, {
+	ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, {
+	ERRHRD, ERRgeneral, 0xc000025d}, {
+	ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, {
+	ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, {
+	ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, {
+	ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, {
+	ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, {
+	ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, {
+	ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, {
+	ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, {
+	ERRDOS, 21, 0xc000026e}, {
+	ERRDOS, 161, 0xc0000281}, {
+	ERRDOS, ERRnoaccess, 0xc000028a}, {
+	ERRDOS, ERRnoaccess, 0xc000028b}, {
+	ERRHRD, ERRgeneral, 0xc000028c}, {
+	ERRDOS, ERRnoaccess, 0xc000028d}, {
+	ERRDOS, ERRnoaccess, 0xc000028e}, {
+	ERRDOS, ERRnoaccess, 0xc000028f}, {
+	ERRDOS, ERRnoaccess, 0xc0000290}, {
+ERRDOS, ERRbadfunc, 0xc000029c},};
+
+void
+ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode)
+{
+	int i;
+	if (ntstatus == 0) {
+		*eclass = 0;
+		*ecode = 0;
+		return;
+	}
+	for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) {
+		if (ntstatus == ntstatus_to_dos_map[i].ntstatus) {
+			*eclass = ntstatus_to_dos_map[i].dos_class;
+			*ecode = ntstatus_to_dos_map[i].dos_code;
+			return;
+		}
+	}
+	*eclass = ERRHRD;
+	*ecode = ERRgeneral;
+}
+
+int
+map_smb_to_linux_error(struct smb_hdr *smb)
+{
+	int i;
+	int rc = -EIO;		/* if transport error smb error may not be set */
+	__u8 smberrclass;
+	__u16 smberrcode;
+
+	/* BB if NT Status codes - map NT BB */
+
+	/* old style smb error codes */
+	if (smb->Status.CifsError == 0)
+		return 0;
+
+	if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
+		/* translate the newer STATUS codes to old style errors and then to POSIX errors */
+		cFYI(1,
+		     (" !!Mapping cifs error code %d ", smb->Status.CifsError));
+		smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError);
+		ntstatus_to_dos(smb->Status.CifsError, &smberrclass,
+				&smberrcode);
+	} else {
+		smberrclass = smb->Status.DosError.ErrorClass;
+		smb->Status.DosError.Error =
+		    le16_to_cpu(smb->Status.DosError.Error);
+		smberrcode = smb->Status.DosError.Error;
+	}
+
+	/* old style errors */
+	cFYI(1, (" !!Mapping smb error code %d ", smberrcode));
+	/* DOS class smb error codes - map DOS */
+
+	/* BB special case reconnect tid and reconnect uid here? */
+
+	if (smberrclass == ERRDOS) {	/* one byte field no need to byte reverse */
+		for (i = 0;
+		     i <
+		     sizeof (mapping_table_ERRDOS) /
+		     sizeof (struct smb_to_posix_error); i++) {
+			if (mapping_table_ERRDOS[i].smb_err == 0)
+				break;
+			else if (mapping_table_ERRDOS[i].smb_err == smberrcode) {
+				rc = mapping_table_ERRDOS[i].posix_code;
+				break;
+			}
+			/* else try the next error mapping one to see if it will match */
+		}
+	} else if (smberrclass == ERRSRV) {	/* server class of error codes */
+		for (i = 0;
+		     i <
+		     sizeof (mapping_table_ERRSRV) /
+		     sizeof (struct smb_to_posix_error); i++) {
+			if (mapping_table_ERRSRV[i].smb_err == 0)
+				break;
+			else if (mapping_table_ERRSRV[i].smb_err == smberrcode) {
+				rc = mapping_table_ERRSRV[i].posix_code;
+				break;
+			}
+			/* else try the next error mapping one to see if it will match */
+		}
+	}
+	/* else ERRHRD class errors or junk  - return EIO */
+
+	/* BB get smb->error_class and code lookup in table if ERR_STATUS is not
+	   set in this frame else translate newer NT Status code - in both cases 
+	   change to equivalent posix error BB */
+	cFYI(1, (" to POSIX err %d !!", rc));
+
+	/* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */
+
+	return rc;
+}
+
+/*
+ * calculate the size of the SMB message based on the fixed header
+ * portion, the number of word parameters and the data portion of the message
+ */
+int
+smbCalcSize(struct smb_hdr *ptr)
+{
+	return (sizeof (struct smb_hdr) + (int) (2 * ptr->WordCount) +
+		BCC(ptr));
+}
+
+/* The following are taken from fs/ntfs/util.c */
+
+#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
+
+    /*
+     * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
+     * into Unix UTC (based 1970-01-01, in seconds).
+     */
+time_t
+cifs_NTtimeToUnix(u64 ntutc)
+{
+	/* BB what about the timezone? BB */
+
+	/* Subtract the NTFS time offset, then convert to 1s intervals. */
+	u64 t;
+
+	t = ntutc - NTFS_TIME_OFFSET;
+	do_div(t, 10000000);
+	return (time_t) t;
+}
+
+/* Convert the Unix UTC into NT UTC. */
+u64
+cifs_UnixTimeToNT(time_t t)
+{
+	/* Convert to 100ns intervals and then add the NTFS time offset. */
+	return (u64) t *10000000 + NTFS_TIME_OFFSET;
+}
diff -Nru a/fs/cifs/nterr.c b/fs/cifs/nterr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/nterr.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,712 @@
+/* 
+ *  Unix SMB/Netbios implementation.
+ *  Version 1.9.
+ *  RPC Pipe client / server routines
+ *  Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
+ *  
+ *  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.
+ */
+
+/* NT error codes - see nterr.h */
+#include "nterr.h"
+#include <linux/types.h>
+#include <linux/fs.h>
+
+struct nt_err_code_struct {
+	char *nt_errstr;
+	__u32 nt_errcode;
+};
+
+const struct nt_err_code_struct nt_errs[] = {
+	{"NT_STATUS_OK", NT_STATUS_OK},
+	{"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL},
+	{"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED},
+	{"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS},
+	{"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH},
+	{"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION},
+	{"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW},
+	{"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR},
+	{"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA},
+	{"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE},
+	{"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK},
+	{"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC},
+	{"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID},
+	{"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED},
+	{"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER},
+	{"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE},
+	{"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE},
+	{"NT_STATUS_INVALID_DEVICE_REQUEST",
+	 NT_STATUS_INVALID_DEVICE_REQUEST},
+	{"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE},
+	{"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME},
+	{"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE},
+	{"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA},
+	{"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR},
+	{"NT_STATUS_MORE_PROCESSING_REQUIRED",
+	 NT_STATUS_MORE_PROCESSING_REQUIRED},
+	{"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY},
+	{"NT_STATUS_CONFLICTING_ADDRESSES",
+	 NT_STATUS_CONFLICTING_ADDRESSES},
+	{"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW},
+	{"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM},
+	{"NT_STATUS_UNABLE_TO_DELETE_SECTION",
+	 NT_STATUS_UNABLE_TO_DELETE_SECTION},
+	{"NT_STATUS_INVALID_SYSTEM_SERVICE",
+	 NT_STATUS_INVALID_SYSTEM_SERVICE},
+	{"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION},
+	{"NT_STATUS_INVALID_LOCK_SEQUENCE",
+	 NT_STATUS_INVALID_LOCK_SEQUENCE},
+	{"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE},
+	{"NT_STATUS_INVALID_FILE_FOR_SECTION",
+	 NT_STATUS_INVALID_FILE_FOR_SECTION},
+	{"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED},
+	{"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED},
+	{"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL},
+	{"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH},
+	{"NT_STATUS_NONCONTINUABLE_EXCEPTION",
+	 NT_STATUS_NONCONTINUABLE_EXCEPTION},
+	{"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION},
+	{"NT_STATUS_UNWIND", NT_STATUS_UNWIND},
+	{"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK},
+	{"NT_STATUS_INVALID_UNWIND_TARGET",
+	 NT_STATUS_INVALID_UNWIND_TARGET},
+	{"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED},
+	{"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR},
+	{"NT_STATUS_UNABLE_TO_DECOMMIT_VM",
+	 NT_STATUS_UNABLE_TO_DECOMMIT_VM},
+	{"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED},
+	{"NT_STATUS_INVALID_PORT_ATTRIBUTES",
+	 NT_STATUS_INVALID_PORT_ATTRIBUTES},
+	{"NT_STATUS_PORT_MESSAGE_TOO_LONG",
+	 NT_STATUS_PORT_MESSAGE_TOO_LONG},
+	{"NT_STATUS_INVALID_PARAMETER_MIX",
+	 NT_STATUS_INVALID_PARAMETER_MIX},
+	{"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER},
+	{"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR},
+	{"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID},
+	{"NT_STATUS_OBJECT_NAME_NOT_FOUND",
+	 NT_STATUS_OBJECT_NAME_NOT_FOUND},
+	{"NT_STATUS_OBJECT_NAME_COLLISION",
+	 NT_STATUS_OBJECT_NAME_COLLISION},
+	{"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE},
+	{"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED},
+	{"NT_STATUS_DEVICE_ALREADY_ATTACHED",
+	 NT_STATUS_DEVICE_ALREADY_ATTACHED},
+	{"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID},
+	{"NT_STATUS_OBJECT_PATH_NOT_FOUND",
+	 NT_STATUS_OBJECT_PATH_NOT_FOUND},
+	{"NT_STATUS_OBJECT_PATH_SYNTAX_BAD",
+	 NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
+	{"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN},
+	{"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR},
+	{"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR},
+	{"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR},
+	{"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG},
+	{"NT_STATUS_PORT_CONNECTION_REFUSED",
+	 NT_STATUS_PORT_CONNECTION_REFUSED},
+	{"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE},
+	{"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION},
+	{"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED},
+	{"NT_STATUS_INVALID_PAGE_PROTECTION",
+	 NT_STATUS_INVALID_PAGE_PROTECTION},
+	{"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED},
+	{"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED",
+	 NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+	{"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET},
+	{"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE},
+	{"NT_STATUS_SUSPEND_COUNT_EXCEEDED",
+	 NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+	{"NT_STATUS_THREAD_IS_TERMINATING",
+	 NT_STATUS_THREAD_IS_TERMINATING},
+	{"NT_STATUS_BAD_WORKING_SET_LIMIT",
+	 NT_STATUS_BAD_WORKING_SET_LIMIT},
+	{"NT_STATUS_INCOMPATIBLE_FILE_MAP",
+	 NT_STATUS_INCOMPATIBLE_FILE_MAP},
+	{"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION},
+	{"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED},
+	{"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE},
+	{"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY},
+	{"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE},
+	{"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR},
+	{"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT},
+	{"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED},
+	{"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING},
+	{"NT_STATUS_CTL_FILE_NOT_SUPPORTED",
+	 NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+	{"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION},
+	{"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH},
+	{"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER},
+	{"NT_STATUS_INVALID_PRIMARY_GROUP",
+	 NT_STATUS_INVALID_PRIMARY_GROUP},
+	{"NT_STATUS_NO_IMPERSONATION_TOKEN",
+	 NT_STATUS_NO_IMPERSONATION_TOKEN},
+	{"NT_STATUS_CANT_DISABLE_MANDATORY",
+	 NT_STATUS_CANT_DISABLE_MANDATORY},
+	{"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS},
+	{"NT_STATUS_NO_SUCH_LOGON_SESSION",
+	 NT_STATUS_NO_SUCH_LOGON_SESSION},
+	{"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE},
+	{"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD},
+	{"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME},
+	{"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS},
+	{"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER},
+	{"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS},
+	{"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP},
+	{"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP},
+	{"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP},
+	{"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN},
+	{"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD},
+	{"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD},
+	{"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION},
+	{"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE},
+	{"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION},
+	{"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS},
+	{"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION},
+	{"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED},
+	{"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED},
+	{"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED},
+	{"NT_STATUS_TOO_MANY_LUIDS_REQUESTED",
+	 NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
+	{"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED},
+	{"NT_STATUS_INVALID_SUB_AUTHORITY",
+	 NT_STATUS_INVALID_SUB_AUTHORITY},
+	{"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL},
+	{"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID},
+	{"NT_STATUS_INVALID_SECURITY_DESCR",
+	 NT_STATUS_INVALID_SECURITY_DESCR},
+	{"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND},
+	{"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT},
+	{"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN},
+	{"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL},
+	{"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED},
+	{"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL},
+	{"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED},
+	{"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED},
+	{"NT_STATUS_TOO_MANY_GUIDS_REQUESTED",
+	 NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+	{"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED},
+	{"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY},
+	{"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED},
+	{"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL},
+	{"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED},
+	{"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA},
+	{"NT_STATUS_RESOURCE_DATA_NOT_FOUND",
+	 NT_STATUS_RESOURCE_DATA_NOT_FOUND},
+	{"NT_STATUS_RESOURCE_TYPE_NOT_FOUND",
+	 NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
+	{"NT_STATUS_RESOURCE_NAME_NOT_FOUND",
+	 NT_STATUS_RESOURCE_NAME_NOT_FOUND},
+	{"NT_STATUS_ARRAY_BOUNDS_EXCEEDED",
+	 NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
+	{"NT_STATUS_FLOAT_DENORMAL_OPERAND",
+	 NT_STATUS_FLOAT_DENORMAL_OPERAND},
+	{"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
+	{"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT},
+	{"NT_STATUS_FLOAT_INVALID_OPERATION",
+	 NT_STATUS_FLOAT_INVALID_OPERATION},
+	{"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW},
+	{"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK},
+	{"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW},
+	{"NT_STATUS_INTEGER_DIVIDE_BY_ZERO",
+	 NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
+	{"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW},
+	{"NT_STATUS_PRIVILEGED_INSTRUCTION",
+	 NT_STATUS_PRIVILEGED_INSTRUCTION},
+	{"NT_STATUS_TOO_MANY_PAGING_FILES",
+	 NT_STATUS_TOO_MANY_PAGING_FILES},
+	{"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID},
+	{"NT_STATUS_ALLOTTED_SPACE_EXCEEDED",
+	 NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+	{"NT_STATUS_INSUFFICIENT_RESOURCES",
+	 NT_STATUS_INSUFFICIENT_RESOURCES},
+	{"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND},
+	{"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR},
+	{"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED},
+	{"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE},
+	{"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE},
+	{"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED},
+	{"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA},
+	{"NT_STATUS_MEDIA_WRITE_PROTECTED",
+	 NT_STATUS_MEDIA_WRITE_PROTECTED},
+	{"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY},
+	{"NT_STATUS_INVALID_GROUP_ATTRIBUTES",
+	 NT_STATUS_INVALID_GROUP_ATTRIBUTES},
+	{"NT_STATUS_BAD_IMPERSONATION_LEVEL",
+	 NT_STATUS_BAD_IMPERSONATION_LEVEL},
+	{"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS},
+	{"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS},
+	{"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE},
+	{"NT_STATUS_BAD_MASTER_BOOT_RECORD",
+	 NT_STATUS_BAD_MASTER_BOOT_RECORD},
+	{"NT_STATUS_INSTRUCTION_MISALIGNMENT",
+	 NT_STATUS_INSTRUCTION_MISALIGNMENT},
+	{"NT_STATUS_INSTANCE_NOT_AVAILABLE",
+	 NT_STATUS_INSTANCE_NOT_AVAILABLE},
+	{"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE},
+	{"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE},
+	{"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY},
+	{"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION},
+	{"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED},
+	{"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING},
+	{"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED},
+	{"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING},
+	{"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE},
+	{"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT},
+	{"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED},
+	{"NT_STATUS_PROFILING_NOT_STARTED",
+	 NT_STATUS_PROFILING_NOT_STARTED},
+	{"NT_STATUS_PROFILING_NOT_STOPPED",
+	 NT_STATUS_PROFILING_NOT_STOPPED},
+	{"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET},
+	{"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY},
+	{"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED},
+	{"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING},
+	{"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME},
+	{"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH},
+	{"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY},
+	{"NT_STATUS_DEVICE_DOES_NOT_EXIST",
+	 NT_STATUS_DEVICE_DOES_NOT_EXIST},
+	{"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS},
+	{"NT_STATUS_ADAPTER_HARDWARE_ERROR",
+	 NT_STATUS_ADAPTER_HARDWARE_ERROR},
+	{"NT_STATUS_INVALID_NETWORK_RESPONSE",
+	 NT_STATUS_INVALID_NETWORK_RESPONSE},
+	{"NT_STATUS_UNEXPECTED_NETWORK_ERROR",
+	 NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+	{"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER},
+	{"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL},
+	{"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE},
+	{"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED},
+	{"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED},
+	{"NT_STATUS_NETWORK_ACCESS_DENIED",
+	 NT_STATUS_NETWORK_ACCESS_DENIED},
+	{"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE},
+	{"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME},
+	{"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES},
+	{"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS},
+	{"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED},
+	{"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED},
+	{"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED},
+	{"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT},
+	{"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT},
+	{"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE},
+	{"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED},
+	{"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED",
+	 NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+	{"NT_STATUS_NO_SECURITY_ON_OBJECT",
+	 NT_STATUS_NO_SECURITY_ON_OBJECT},
+	{"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT},
+	{"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY},
+	{"NT_STATUS_CANT_ACCESS_DOMAIN_INFO",
+	 NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
+	{"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF},
+	{"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE},
+	{"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE},
+	{"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE},
+	{"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN},
+	{"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS},
+	{"NT_STATUS_DOMAIN_LIMIT_EXCEEDED",
+	 NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
+	{"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED},
+	{"NT_STATUS_INVALID_OPLOCK_PROTOCOL",
+	 NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+	{"NT_STATUS_INTERNAL_DB_CORRUPTION",
+	 NT_STATUS_INTERNAL_DB_CORRUPTION},
+	{"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR},
+	{"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED},
+	{"NT_STATUS_BAD_DESCRIPTOR_FORMAT",
+	 NT_STATUS_BAD_DESCRIPTOR_FORMAT},
+	{"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER},
+	{"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR},
+	{"NT_STATUS_UNEXPECTED_MM_CREATE_ERR",
+	 NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
+	{"NT_STATUS_UNEXPECTED_MM_MAP_ERROR",
+	 NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
+	{"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR",
+	 NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
+	{"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS},
+	{"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS},
+	{"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1},
+	{"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2},
+	{"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3},
+	{"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4},
+	{"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5},
+	{"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6},
+	{"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7},
+	{"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8},
+	{"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9},
+	{"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10},
+	{"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11},
+	{"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12},
+	{"NT_STATUS_REDIRECTOR_NOT_STARTED",
+	 NT_STATUS_REDIRECTOR_NOT_STARTED},
+	{"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED},
+	{"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW},
+	{"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE},
+	{"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE},
+	{"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY},
+	{"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR},
+	{"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY},
+	{"NT_STATUS_BAD_LOGON_SESSION_STATE",
+	 NT_STATUS_BAD_LOGON_SESSION_STATE},
+	{"NT_STATUS_LOGON_SESSION_COLLISION",
+	 NT_STATUS_LOGON_SESSION_COLLISION},
+	{"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG},
+	{"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN},
+	{"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE},
+	{"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND},
+	{"NT_STATUS_PROCESS_IS_TERMINATING",
+	 NT_STATUS_PROCESS_IS_TERMINATING},
+	{"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE},
+	{"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION},
+	{"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE},
+	{"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED},
+	{"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT},
+	{"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST},
+	{"NT_STATUS_ABIOS_LID_ALREADY_OWNED",
+	 NT_STATUS_ABIOS_LID_ALREADY_OWNED},
+	{"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER},
+	{"NT_STATUS_ABIOS_INVALID_COMMAND",
+	 NT_STATUS_ABIOS_INVALID_COMMAND},
+	{"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID},
+	{"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE",
+	 NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
+	{"NT_STATUS_ABIOS_INVALID_SELECTOR",
+	 NT_STATUS_ABIOS_INVALID_SELECTOR},
+	{"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT},
+	{"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE},
+	{"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET},
+	{"NT_STATUS_INVALID_LDT_DESCRIPTOR",
+	 NT_STATUS_INVALID_LDT_DESCRIPTOR},
+	{"NT_STATUS_INVALID_IMAGE_NE_FORMAT",
+	 NT_STATUS_INVALID_IMAGE_NE_FORMAT},
+	{"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE},
+	{"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE},
+	{"NT_STATUS_MAPPED_FILE_SIZE_ZERO",
+	 NT_STATUS_MAPPED_FILE_SIZE_ZERO},
+	{"NT_STATUS_TOO_MANY_OPENED_FILES",
+	 NT_STATUS_TOO_MANY_OPENED_FILES},
+	{"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED},
+	{"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE},
+	{"NT_STATUS_INVALID_COMPUTER_NAME",
+	 NT_STATUS_INVALID_COMPUTER_NAME},
+	{"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED},
+	{"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT},
+	{"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP},
+	{"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER},
+	{"NT_STATUS_MEMBERS_PRIMARY_GROUP",
+	 NT_STATUS_MEMBERS_PRIMARY_GROUP},
+	{"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED},
+	{"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS},
+	{"NT_STATUS_THREAD_NOT_IN_PROCESS",
+	 NT_STATUS_THREAD_NOT_IN_PROCESS},
+	{"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE},
+	{"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED",
+	 NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
+	{"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT},
+	{"NT_STATUS_INVALID_IMAGE_LE_FORMAT",
+	 NT_STATUS_INVALID_IMAGE_LE_FORMAT},
+	{"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ},
+	{"NT_STATUS_INVALID_IMAGE_PROTECT",
+	 NT_STATUS_INVALID_IMAGE_PROTECT},
+	{"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16},
+	{"NT_STATUS_LOGON_SERVER_CONFLICT",
+	 NT_STATUS_LOGON_SERVER_CONFLICT},
+	{"NT_STATUS_TIME_DIFFERENCE_AT_DC",
+	 NT_STATUS_TIME_DIFFERENCE_AT_DC},
+	{"NT_STATUS_SYNCHRONIZATION_REQUIRED",
+	 NT_STATUS_SYNCHRONIZATION_REQUIRED},
+	{"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND},
+	{"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED},
+	{"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED},
+	{"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND},
+	{"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND},
+	{"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT},
+	{"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT},
+	{"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT},
+	{"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES},
+	{"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED},
+	{"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT},
+	{"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION},
+	{"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS},
+	{"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED},
+	{"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE},
+	{"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION},
+	{"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE},
+	{"NT_STATUS_PAGEFILE_CREATE_FAILED",
+	 NT_STATUS_PAGEFILE_CREATE_FAILED},
+	{"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE},
+	{"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL},
+	{"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE},
+	{"NT_STATUS_ILLEGAL_FLOAT_CONTEXT",
+	 NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
+	{"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN},
+	{"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT},
+	{"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED},
+	{"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR},
+	{"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME},
+	{"NT_STATUS_SERIAL_NO_DEVICE_INITED",
+	 NT_STATUS_SERIAL_NO_DEVICE_INITED},
+	{"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS},
+	{"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS},
+	{"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS},
+	{"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS},
+	{"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED},
+	{"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS},
+	{"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG},
+	{"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR},
+	{"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE},
+	{"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS},
+	{"NT_STATUS_LOGON_TYPE_NOT_GRANTED",
+	 NT_STATUS_LOGON_TYPE_NOT_GRANTED},
+	{"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE},
+	{"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED",
+	 NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
+	{"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR",
+	 NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
+	{"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER},
+	{"NT_STATUS_ILL_FORMED_SERVICE_ENTRY",
+	 NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
+	{"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER},
+	{"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER},
+	{"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER},
+	{"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME},
+	{"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND",
+	 NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
+	{"NT_STATUS_FLOPPY_WRONG_CYLINDER",
+	 NT_STATUS_FLOPPY_WRONG_CYLINDER},
+	{"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR},
+	{"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS},
+	{"NT_STATUS_DISK_RECALIBRATE_FAILED",
+	 NT_STATUS_DISK_RECALIBRATE_FAILED},
+	{"NT_STATUS_DISK_OPERATION_FAILED",
+	 NT_STATUS_DISK_OPERATION_FAILED},
+	{"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED},
+	{"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY},
+	{"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING},
+	{"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE},
+	{"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH},
+	{"NT_STATUS_DEVICE_NOT_PARTITIONED",
+	 NT_STATUS_DEVICE_NOT_PARTITIONED},
+	{"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA},
+	{"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA",
+	 NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
+	{"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW},
+	{"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA},
+	{"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER},
+	{"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER},
+	{"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED},
+	{"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE},
+	{"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS},
+	{"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED",
+	 NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
+	{"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN},
+	{"NT_STATUS_CHILD_MUST_BE_VOLATILE",
+	 NT_STATUS_CHILD_MUST_BE_VOLATILE},
+	{"NT_STATUS_DEVICE_CONFIGURATION_ERROR",
+	 NT_STATUS_DEVICE_CONFIGURATION_ERROR},
+	{"NT_STATUS_DRIVER_INTERNAL_ERROR",
+	 NT_STATUS_DRIVER_INTERNAL_ERROR},
+	{"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE},
+	{"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR},
+	{"NT_STATUS_DEVICE_PROTOCOL_ERROR",
+	 NT_STATUS_DEVICE_PROTOCOL_ERROR},
+	{"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER},
+	{"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL},
+	{"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE},
+	{"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET},
+	{"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT},
+	{"NT_STATUS_TRUSTED_DOMAIN_FAILURE",
+	 NT_STATUS_TRUSTED_DOMAIN_FAILURE},
+	{"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE",
+	 NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
+	{"NT_STATUS_EVENTLOG_FILE_CORRUPT",
+	 NT_STATUS_EVENTLOG_FILE_CORRUPT},
+	{"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START},
+	{"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE},
+	{"NT_STATUS_MUTANT_LIMIT_EXCEEDED",
+	 NT_STATUS_MUTANT_LIMIT_EXCEEDED},
+	{"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED},
+	{"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED},
+	{"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK},
+	{"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT",
+	 NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
+	{"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT},
+	{"NT_STATUS_EVENTLOG_FILE_CHANGED",
+	 NT_STATUS_EVENTLOG_FILE_CHANGED},
+	{"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT",
+	 NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
+	{"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT",
+	 NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
+	{"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT",
+	 NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+	{"NT_STATUS_DOMAIN_TRUST_INCONSISTENT",
+	 NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
+	{"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED},
+	{"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY},
+	{"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED},
+	{"NT_STATUS_RESOURCE_LANG_NOT_FOUND",
+	 NT_STATUS_RESOURCE_LANG_NOT_FOUND},
+	{"NT_STATUS_INSUFF_SERVER_RESOURCES",
+	 NT_STATUS_INSUFF_SERVER_RESOURCES},
+	{"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE},
+	{"NT_STATUS_INVALID_ADDRESS_COMPONENT",
+	 NT_STATUS_INVALID_ADDRESS_COMPONENT},
+	{"NT_STATUS_INVALID_ADDRESS_WILDCARD",
+	 NT_STATUS_INVALID_ADDRESS_WILDCARD},
+	{"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES},
+	{"NT_STATUS_ADDRESS_ALREADY_EXISTS",
+	 NT_STATUS_ADDRESS_ALREADY_EXISTS},
+	{"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED},
+	{"NT_STATUS_CONNECTION_DISCONNECTED",
+	 NT_STATUS_CONNECTION_DISCONNECTED},
+	{"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET},
+	{"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES},
+	{"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED},
+	{"NT_STATUS_TRANSACTION_TIMED_OUT",
+	 NT_STATUS_TRANSACTION_TIMED_OUT},
+	{"NT_STATUS_TRANSACTION_NO_RELEASE",
+	 NT_STATUS_TRANSACTION_NO_RELEASE},
+	{"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH},
+	{"NT_STATUS_TRANSACTION_RESPONDED",
+	 NT_STATUS_TRANSACTION_RESPONDED},
+	{"NT_STATUS_TRANSACTION_INVALID_ID",
+	 NT_STATUS_TRANSACTION_INVALID_ID},
+	{"NT_STATUS_TRANSACTION_INVALID_TYPE",
+	 NT_STATUS_TRANSACTION_INVALID_TYPE},
+	{"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION},
+	{"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION},
+	{"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE",
+	 NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
+	{"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED},
+	{"NT_STATUS_SYSTEM_PROCESS_TERMINATED",
+	 NT_STATUS_SYSTEM_PROCESS_TERMINATED},
+	{"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED},
+	{"NT_STATUS_NO_BROWSER_SERVERS_FOUND",
+	 NT_STATUS_NO_BROWSER_SERVERS_FOUND},
+	{"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR},
+	{"NT_STATUS_DRIVER_CANCEL_TIMEOUT",
+	 NT_STATUS_DRIVER_CANCEL_TIMEOUT},
+	{"NT_STATUS_REPLY_MESSAGE_MISMATCH",
+	 NT_STATUS_REPLY_MESSAGE_MISMATCH},
+	{"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT},
+	{"NT_STATUS_IMAGE_CHECKSUM_MISMATCH",
+	 NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
+	{"NT_STATUS_LOST_WRITEBEHIND_DATA",
+	 NT_STATUS_LOST_WRITEBEHIND_DATA},
+	{"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID",
+	 NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
+	{"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE},
+	{"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND},
+	{"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM},
+	{"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE},
+	{"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ},
+	{"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK},
+	{"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID},
+	{"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS},
+	{"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE},
+	{"NT_STATUS_RETRY", NT_STATUS_RETRY},
+	{"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE},
+	{"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET},
+	{"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND},
+	{"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW},
+	{"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT},
+	{"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
+	 NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+	{"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT},
+	{"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE},
+	{"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED},
+	{"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT},
+	{"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED",
+	 NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+	{"NT_STATUS_ADDRESS_NOT_ASSOCIATED",
+	 NT_STATUS_ADDRESS_NOT_ASSOCIATED},
+	{"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID},
+	{"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE},
+	{"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE},
+	{"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE},
+	{"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE},
+	{"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE},
+	{"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED},
+	{"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED},
+	{"NT_STATUS_BAD_COMPRESSION_BUFFER",
+	 NT_STATUS_BAD_COMPRESSION_BUFFER},
+	{"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE},
+	{"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED},
+	{"NT_STATUS_TIMER_RESOLUTION_NOT_SET",
+	 NT_STATUS_TIMER_RESOLUTION_NOT_SET},
+	{"NT_STATUS_CONNECTION_COUNT_LIMIT",
+	 NT_STATUS_CONNECTION_COUNT_LIMIT},
+	{"NT_STATUS_LOGIN_TIME_RESTRICTION",
+	 NT_STATUS_LOGIN_TIME_RESTRICTION},
+	{"NT_STATUS_LOGIN_WKSTA_RESTRICTION",
+	 NT_STATUS_LOGIN_WKSTA_RESTRICTION},
+	{"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH},
+	{"NT_STATUS_INSUFFICIENT_LOGON_INFO",
+	 NT_STATUS_INSUFFICIENT_LOGON_INFO},
+	{"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT},
+	{"NT_STATUS_BAD_SERVICE_ENTRYPOINT",
+	 NT_STATUS_BAD_SERVICE_ENTRYPOINT},
+	{"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST},
+	{"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1},
+	{"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2},
+	{"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT},
+	{"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED},
+	{"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE},
+	{"NT_STATUS_LICENSE_QUOTA_EXCEEDED",
+	 NT_STATUS_LICENSE_QUOTA_EXCEEDED},
+	{"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT},
+	{"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT},
+	{"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT},
+	{"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE},
+	{"NT_STATUS_UNSUPPORTED_COMPRESSION",
+	 NT_STATUS_UNSUPPORTED_COMPRESSION},
+	{"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE},
+	{"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH",
+	 NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
+	{"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND",
+	 NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
+	{"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND",
+	 NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
+	{"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED},
+	{"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS},
+	{"NT_STATUS_QUOTA_LIST_INCONSISTENT",
+	 NT_STATUS_QUOTA_LIST_INCONSISTENT},
+	{"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE},
+	{"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES},
+	{"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES},
+	{"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED},
+	{NULL, 0}
+};
+
+/*****************************************************************************
+ Print an error message from the status code
+ *****************************************************************************/
+void
+print_status(__u32 status_code)
+{
+	int idx = 0;
+
+	printk("\nStatus code returned: 0x%08x", status_code);
+
+	while (nt_errs[idx].nt_errstr != NULL) {
+		if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
+		    (status_code & 0xFFFFFF)) {
+			printk(nt_errs[idx].nt_errstr);
+		}
+		idx++;
+	}
+	return;
+}
diff -Nru a/fs/cifs/nterr.h b/fs/cifs/nterr.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/nterr.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,547 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   NT error code constants
+   Copyright (C) Andrew Tridgell              1992-2000
+   Copyright (C) John H Terpstra              1996-2000
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+   Copyright (C) Paul Ashton                  1998-2000
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   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.
+*/
+
+#ifndef _NTERR_H
+#define _NTERR_H
+
+/* Win32 Status codes. */
+
+#define STATUS_BUFFER_OVERFLOW            0x80000005
+#define STATUS_MORE_ENTRIES               0x0105
+#define ERROR_INVALID_PARAMETER		  0x0057
+#define ERROR_INSUFFICIENT_BUFFER	  0x007a
+#define STATUS_1804	                  0x070c
+#define STATUS_NOTIFY_ENUM_DIR            0x010c
+
+/* Win32 Error codes extracted using a loop in smbclient then printing a
+   netmon sniff to a file. */
+
+#define NT_STATUS_OK 0x0000
+#define STATUS_SOME_UNMAPPED       0x0107
+#define STATUS_BUFFER_OVERFLOW     0x80000005
+#define NT_STATUS_NO_MORE_ENTRIES  0x8000001a
+#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001
+#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002
+#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003
+#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004
+#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005
+#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006
+#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007
+#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008
+#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009
+#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a
+#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b
+#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c
+#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d
+#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e
+#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f
+#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010
+#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011
+#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012
+#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013
+#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014
+#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015
+#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016
+#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017
+#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018
+#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019
+#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a
+#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b
+#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c
+#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d
+#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e
+#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f
+#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020
+#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021
+#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022
+#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023
+#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024
+#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025
+#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026
+#define NT_STATUS_UNWIND 0xC0000000 | 0x0027
+#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028
+#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029
+#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a
+#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b
+#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c
+#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d
+#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e
+#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f
+#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030
+#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031
+#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032
+#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033
+#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034
+#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035
+#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036
+#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037
+#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038
+#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039
+#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a
+#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b
+#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c
+#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d
+#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e
+#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f
+#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040
+#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041
+#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042
+#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043
+#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044
+#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045
+#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046
+#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047
+#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048
+#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049
+#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a
+#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b
+#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c
+#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d
+#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e
+#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f
+#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050
+#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051
+#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052
+#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053
+#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054
+#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055
+#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056
+#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057
+#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058
+#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059
+#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a
+#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b
+#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c
+#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d
+#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e
+#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f
+#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060
+#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061
+#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062
+#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063
+#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064
+#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065
+#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066
+#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067
+#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068
+#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069
+#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a
+#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b
+#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c
+#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d
+#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e
+#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f
+#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070
+#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071
+#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072
+#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073
+#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074
+#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075
+#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076
+#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077
+#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078
+#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079
+#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a
+#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b
+#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c
+#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d
+#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e
+#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f
+#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080
+#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081
+#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082
+#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083
+#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084
+#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085
+#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086
+#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087
+#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088
+#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089
+#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a
+#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b
+#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c
+#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d
+#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e
+#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f
+#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090
+#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091
+#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092
+#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093
+#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094
+#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095
+#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096
+#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097
+#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098
+#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099
+#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a
+#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b
+#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c
+#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d
+#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e
+#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f
+#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0
+#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1
+#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2
+#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3
+#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4
+#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5
+#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6
+#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7
+#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8
+#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9
+#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa
+#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab
+#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac
+#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad
+#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae
+#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af
+#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0
+#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1
+#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2
+#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3
+#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4
+#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5
+#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6
+#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7
+#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8
+#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9
+#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba
+#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb
+#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc
+#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd
+#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be
+#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf
+#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0
+#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1
+#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2
+#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3
+#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4
+#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5
+#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6
+#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7
+#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8
+#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9
+#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca
+#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb
+#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc
+#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd
+#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce
+#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf
+#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0
+#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1
+#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2
+#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3
+#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4
+#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5
+#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6
+#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7
+#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8
+#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9
+#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da
+#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db
+#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc
+#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd
+#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de
+#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df
+#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0
+#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1
+#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2
+#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3
+#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4
+#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5
+#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6
+#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7
+#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8
+#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9
+#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea
+#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb
+#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec
+#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed
+#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee
+#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef
+#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0
+#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1
+#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2
+#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3
+#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4
+#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5
+#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6
+#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7
+#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8
+#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9
+#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa
+#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb
+#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc
+#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd
+#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe
+#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff
+#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101
+#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102
+#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103
+#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104
+#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105
+#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106
+#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107
+#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108
+#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109
+#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a
+#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b
+#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c
+#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d
+#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e
+#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f
+#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111
+#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112
+#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113
+#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115
+#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116
+#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117
+#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118
+#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119
+#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a
+#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b
+#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c
+#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d
+#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e
+#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f
+#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120
+#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121
+#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122
+#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123
+#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124
+#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125
+#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126
+#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127
+#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128
+#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129
+#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a
+#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b
+#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c
+#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d
+#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e
+#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f
+#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130
+#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131
+#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132
+#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133
+#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134
+#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135
+#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136
+#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137
+#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138
+#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139
+#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a
+#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b
+#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c
+#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d
+#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e
+#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f
+#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140
+#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141
+#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142
+#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143
+#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144
+#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145
+#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146
+#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147
+#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148
+#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149
+#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a
+#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b
+#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c
+#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d
+#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e
+#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f
+#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150
+#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151
+#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152
+#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153
+#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154
+#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155
+#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156
+#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157
+#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158
+#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159
+#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a
+#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b
+#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c
+#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d
+#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e
+#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f
+#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160
+#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161
+#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162
+#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163
+#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164
+#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165
+#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166
+#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167
+#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168
+#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169
+#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a
+#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b
+#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c
+#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d
+#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172
+#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173
+#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174
+#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175
+#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176
+#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177
+#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178
+#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a
+#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b
+#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c
+#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d
+#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e
+#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f
+#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180
+#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181
+#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182
+#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183
+#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184
+#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185
+#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186
+#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187
+#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188
+#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189
+#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a
+#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b
+#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c
+#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d
+#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e
+#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f
+#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190
+#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191
+#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192
+#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193
+#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194
+#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195
+#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196
+#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197
+#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198
+#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199
+#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a
+#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b
+#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c
+#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202
+#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203
+#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204
+#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205
+#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206
+#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207
+#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208
+#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209
+#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a
+#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b
+#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c
+#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d
+#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e
+#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f
+#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210
+#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211
+#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212
+#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213
+#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214
+#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215
+#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216
+#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217
+#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218
+#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219
+#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a
+#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b
+#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c
+#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d
+#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e
+#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f
+#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220
+#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221
+#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222
+#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223
+#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224
+#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225
+#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226
+#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227
+#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228
+#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229
+#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a
+#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b
+#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c
+#define NT_STATUS_RETRY 0xC0000000 | 0x022d
+#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e
+#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f
+#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230
+#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231
+#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232
+#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233
+#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234
+#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235
+#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236
+#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237
+#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238
+#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239
+#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a
+#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b
+#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c
+#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d
+#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e
+#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f
+#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240
+#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241
+#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242
+#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243
+#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244
+#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245
+#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246
+#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247
+#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248
+#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249
+#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250
+#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251
+#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252
+#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253
+#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254
+#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255
+#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256
+#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257
+#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258
+#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259
+#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a
+#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b
+#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c
+#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e
+#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f
+#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260
+#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261
+#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262
+#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263
+#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264
+#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265
+#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266
+#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267
+#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE	/* scheduler */
+
+#endif				/* _NTERR_H */
diff -Nru a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/ntlmssp.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,96 @@
+/*
+ *   fs/cifs/ntlmssp.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+#pragma pack(1)
+
+#define NTLMSSP_SIGNATURE "NTLMSSP"
+/* Message Types */
+#define NtLmNegotiate     1
+#define NtLmChallenge     2
+#define NtLmAuthenticate  3
+#define UnknownMessage    8
+/* Negotiate Flags */
+#define NTLMSSP_NEGOTIATE_UNICODE       0x01	// Text strings are in unicode
+#define NTLMSSP_NEGOTIATE_OEM           0x02	// Text strings are in OEM
+#define NTLMSSP_REQUEST_TARGET          0x04	// Server return its auth realm
+#define NTLMSSP_NEGOTIATE_SIGN        0x0010	// Request signature capability
+#define NTLMSSP_NEGOTIATE_SEAL        0x0020	// Request confidentiality
+#define NTLMSSP_NEGOTIATE_DGRAM       0x0040 
+#define NTLMSSP_NEGOTIATE_LM_KEY      0x0080	// Use LM session key for sign/seal
+#define NTLMSSP_NEGOTIATE_NTLM        0x0200	// NTLM authentication
+#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
+#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
+#define NTLMSSP_NEGOTIATE_LOCAL_CALL  0x4000	// client/server on same machine
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000	// Sign for all security levels
+#define NTLMSSP_NEGOTIATE_NTLMV2      0x80000
+#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000
+#define NTLMSSP_NEGOTIATE_128     0x20000000
+#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
+/* server only negotiate flags */
+#define NTLMSSP_TARGET_TYPE_DOMAIN  0x10000	/* NEGOTIATE_DOMAIN 0x1000 ? */
+#define NTLMSSP_TARGET_TYPE_SERVER  0x20000	/* NEGOTIATE_WORKSTATION 0x2000 ? */
+
+/* Although typedefs are not commonly used for structure definitions */
+/* in the Linux kernel, in this particular case they are useful      */
+/* to more closely match the standards document for NTLMSSP from     */
+/* OpenGroup and to make the code more closely match the standard in */
+/* appearance */
+
+typedef struct _SECURITY_BUFFER {
+	__u16 Length;
+	__u16 MaximumLength;
+	__u32 Buffer;		/* offset to buffer */
+} SECURITY_BUFFER;
+
+typedef struct _NEGOTIATE_MESSAGE {
+	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
+	__u32 MessageType;
+	__u32 NegotiateFlags;
+	SECURITY_BUFFER DomainName;	/* RFC 1001 style and ASCII */
+	SECURITY_BUFFER WorkstationName;	/* RFC 1001 and ASCII */
+	char DomainString[0];
+	/* followed by WorkstationString */
+} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
+
+typedef struct _CHALLENGE_MESSAGE {
+	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
+	__u32 MessageType;
+	SECURITY_BUFFER TargetName;
+	__u32 NegotiateFlags;
+	__u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
+	__u8 Reserved[8];
+	SECURITY_BUFFER TargetInfoArray;
+} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
+
+typedef struct _AUTHENTICATE_MESSAGE {
+	__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
+	__u32 MessageType;
+	SECURITY_BUFFER LmChallengeResponse;
+	SECURITY_BUFFER NtChallengeResponse;
+	SECURITY_BUFFER DomainName;
+	SECURITY_BUFFER UserName;
+	SECURITY_BUFFER WorkstationName;
+	SECURITY_BUFFER SessionKey;
+	__u32 NegotiateFlags;
+	char UserString[0];
+} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
+
+#pragma pack()			/* resume default structure packing */
diff -Nru a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/smbdes.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,416 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+
+   a partial implementation of DES designed for use in the 
+   SMB authentication protocol
+
+   Copyright (C) Andrew Tridgell 1998
+   Modified by Steve French (sfrench@us.ibm.com) 2002
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* NOTES: 
+
+   This code makes no attempt to be fast! In fact, it is a very
+   slow implementation 
+
+   This code is NOT a complete DES implementation. It implements only
+   the minimum necessary for SMB authentication, as used by all SMB
+   products (including every copy of Microsoft Windows95 ever sold)
+
+   In particular, it can only do a unchained forward DES pass. This
+   means it is not possible to use this code for encryption/decryption
+   of data, instead it is only useful as a "hash" algorithm.
+
+   There is no entry point into this code that allows normal DES operation.
+
+   I believe this means that this code does not come under ITAR
+   regulations but this is NOT a legal opinion. If you are concerned
+   about the applicability of ITAR regulations to this code then you
+   should confirm it for yourself (and maybe let me know if you come
+   up with a different answer to the one above)
+*/
+
+#define uchar unsigned char
+
+static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
+	1, 58, 50, 42, 34, 26, 18,
+	10, 2, 59, 51, 43, 35, 27,
+	19, 11, 3, 60, 52, 44, 36,
+	63, 55, 47, 39, 31, 23, 15,
+	7, 62, 54, 46, 38, 30, 22,
+	14, 6, 61, 53, 45, 37, 29,
+	21, 13, 5, 28, 20, 12, 4
+};
+
+static uchar perm2[48] = { 14, 17, 11, 24, 1, 5,
+	3, 28, 15, 6, 21, 10,
+	23, 19, 12, 4, 26, 8,
+	16, 7, 27, 20, 13, 2,
+	41, 52, 31, 37, 47, 55,
+	30, 40, 51, 45, 33, 48,
+	44, 49, 39, 56, 34, 53,
+	46, 42, 50, 36, 29, 32
+};
+
+static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
+	60, 52, 44, 36, 28, 20, 12, 4,
+	62, 54, 46, 38, 30, 22, 14, 6,
+	64, 56, 48, 40, 32, 24, 16, 8,
+	57, 49, 41, 33, 25, 17, 9, 1,
+	59, 51, 43, 35, 27, 19, 11, 3,
+	61, 53, 45, 37, 29, 21, 13, 5,
+	63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
+	4, 5, 6, 7, 8, 9,
+	8, 9, 10, 11, 12, 13,
+	12, 13, 14, 15, 16, 17,
+	16, 17, 18, 19, 20, 21,
+	20, 21, 22, 23, 24, 25,
+	24, 25, 26, 27, 28, 29,
+	28, 29, 30, 31, 32, 1
+};
+
+static uchar perm5[32] = { 16, 7, 20, 21,
+	29, 12, 28, 17,
+	1, 15, 23, 26,
+	5, 18, 31, 10,
+	2, 8, 24, 14,
+	32, 27, 3, 9,
+	19, 13, 30, 6,
+	22, 11, 4, 25
+};
+
+static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
+	39, 7, 47, 15, 55, 23, 63, 31,
+	38, 6, 46, 14, 54, 22, 62, 30,
+	37, 5, 45, 13, 53, 21, 61, 29,
+	36, 4, 44, 12, 52, 20, 60, 28,
+	35, 3, 43, 11, 51, 19, 59, 27,
+	34, 2, 42, 10, 50, 18, 58, 26,
+	33, 1, 41, 9, 49, 17, 57, 25
+};
+
+static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
+
+static uchar sbox[8][4][16] = {
+	{{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+	 {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+	 {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+	 {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+	{{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+	 {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+	 {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+	 {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+	{{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+	 {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+	 {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+	 {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+	{{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+	 {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+	 {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+	 {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+	{{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+	 {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+	 {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+	 {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+	{{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+	 {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+	 {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+	 {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+	{{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+	 {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+	 {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+	 {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+	{{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+	 {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+	 {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+	 {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
+};
+
+static void
+permute(char *out, char *in, uchar * p, int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		out[i] = in[p[i] - 1];
+}
+
+static void
+lshift(char *d, int count, int n)
+{
+	char out[64];
+	int i;
+	for (i = 0; i < n; i++)
+		out[i] = d[(i + count) % n];
+	for (i = 0; i < n; i++)
+		d[i] = out[i];
+}
+
+static void
+concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+	while (l1--)
+		*out++ = *in1++;
+	while (l2--)
+		*out++ = *in2++;
+}
+
+static void
+xor(char *out, char *in1, char *in2, int n)
+{
+	int i;
+	for (i = 0; i < n; i++)
+		out[i] = in1[i] ^ in2[i];
+}
+
+static void
+dohash(char *out, char *in, char *key, int forw)
+{
+	int i, j, k;
+	char pk1[56];
+	char c[28];
+	char d[28];
+	char cd[56];
+	char ki[16][48];
+	char pd1[64];
+	char l[32], r[32];
+	char rl[64];
+
+	permute(pk1, key, perm1, 56);
+
+	for (i = 0; i < 28; i++)
+		c[i] = pk1[i];
+	for (i = 0; i < 28; i++)
+		d[i] = pk1[i + 28];
+
+	for (i = 0; i < 16; i++) {
+		lshift(c, sc[i], 28);
+		lshift(d, sc[i], 28);
+
+		concat(cd, c, d, 28, 28);
+		permute(ki[i], cd, perm2, 48);
+	}
+
+	permute(pd1, in, perm3, 64);
+
+	for (j = 0; j < 32; j++) {
+		l[j] = pd1[j];
+		r[j] = pd1[j + 32];
+	}
+
+	for (i = 0; i < 16; i++) {
+		char er[48];
+		char erk[48];
+		char b[8][6];
+		char cb[32];
+		char pcb[32];
+		char r2[32];
+
+		permute(er, r, perm4, 48);
+
+		xor(erk, er, ki[forw ? i : 15 - i], 48);
+
+		for (j = 0; j < 8; j++)
+			for (k = 0; k < 6; k++)
+				b[j][k] = erk[j * 6 + k];
+
+		for (j = 0; j < 8; j++) {
+			int m, n;
+			m = (b[j][0] << 1) | b[j][5];
+
+			n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] <<
+							       1) | b[j][4];
+
+			for (k = 0; k < 4; k++)
+				b[j][k] =
+				    (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
+		}
+
+		for (j = 0; j < 8; j++)
+			for (k = 0; k < 4; k++)
+				cb[j * 4 + k] = b[j][k];
+		permute(pcb, cb, perm5, 32);
+
+		xor(r2, l, pcb, 32);
+
+		for (j = 0; j < 32; j++)
+			l[j] = r[j];
+
+		for (j = 0; j < 32; j++)
+			r[j] = r2[j];
+	}
+
+	concat(rl, r, l, 32, 32);
+
+	permute(out, rl, perm6, 64);
+}
+
+static void
+str_to_key(unsigned char *str, unsigned char *key)
+{
+	int i;
+
+	key[0] = str[0] >> 1;
+	key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
+	key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
+	key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
+	key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
+	key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
+	key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
+	key[7] = str[6] & 0x7F;
+	for (i = 0; i < 8; i++) {
+		key[i] = (key[i] << 1);
+	}
+}
+
+static void
+smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+{
+	int i;
+	char outb[64];
+	char inb[64];
+	char keyb[64];
+	unsigned char key2[8];
+
+	str_to_key(key, key2);
+
+	for (i = 0; i < 64; i++) {
+		inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+		keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
+		outb[i] = 0;
+	}
+
+	dohash(outb, inb, keyb, forw);
+
+	for (i = 0; i < 8; i++) {
+		out[i] = 0;
+	}
+
+	for (i = 0; i < 64; i++) {
+		if (outb[i])
+			out[i / 8] |= (1 << (7 - (i % 8)));
+	}
+}
+
+void
+E_P16(unsigned char *p14, unsigned char *p16)
+{
+	unsigned char sp8[8] =
+	    { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
+	smbhash(p16, sp8, p14, 1);
+	smbhash(p16 + 8, sp8, p14 + 7, 1);
+}
+
+void
+E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+{
+	smbhash(p24, c8, p21, 1);
+	smbhash(p24 + 8, c8, p21 + 7, 1);
+	smbhash(p24 + 16, c8, p21 + 14, 1);
+}
+
+void
+D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
+{
+	smbhash(out, in, p14, 0);
+	smbhash(out + 8, in + 8, p14 + 7, 0);
+}
+
+void
+E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
+{
+	smbhash(out, in, p14, 1);
+	smbhash(out + 8, in + 8, p14 + 7, 1);
+}
+
+void
+cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+	unsigned char buf[8];
+
+	smbhash(buf, in, key, 1);
+	smbhash(out, buf, key + 9, 1);
+}
+
+void
+cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+	unsigned char buf[8];
+	static unsigned char key2[8];
+
+	smbhash(buf, in, key, 1);
+	key2[0] = key[7];
+	smbhash(out, buf, key2, 1);
+}
+
+void
+cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+{
+	static unsigned char key2[8];
+
+	smbhash(out, in, key, forw);
+	key2[0] = key[7];
+	smbhash(out + 8, in + 8, key2, forw);
+}
+
+void
+SamOEMhash(unsigned char *data, unsigned char *key, int val)
+{
+	unsigned char s_box[256];
+	unsigned char index_i = 0;
+	unsigned char index_j = 0;
+	unsigned char j = 0;
+	int ind;
+
+	for (ind = 0; ind < 256; ind++) {
+		s_box[ind] = (unsigned char) ind;
+	}
+
+	for (ind = 0; ind < 256; ind++) {
+		unsigned char tc;
+
+		j += (s_box[ind] + key[ind % 16]);
+
+		tc = s_box[ind];
+		s_box[ind] = s_box[j];
+		s_box[j] = tc;
+	}
+	for (ind = 0; ind < (val ? 516 : 16); ind++) {
+		unsigned char tc;
+		unsigned char t;
+
+		index_i++;
+		index_j += s_box[index_i];
+
+		tc = s_box[index_i];
+		s_box[index_i] = s_box[index_j];
+		s_box[index_j] = tc;
+
+		t = s_box[index_i] + s_box[index_j];
+		data[ind] = data[ind] ^ s_box[t];
+	}
+}
diff -Nru a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/smbencrypt.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,454 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   SMB parameters and setup
+   Copyright (C) Andrew Tridgell 1992-2000
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+   Modified by Jeremy Allison 1995.
+   Modified by Steve French (sfrench@us.ibm.com) 2002
+   
+   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.
+*/
+
+extern int DEBUGLEVEL;
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include "cifs_unicode.h"
+#include "cifspdu.h"
+#include "md5.h"
+#include "cifs_debug.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* following came from the other byteorder.h to avoid include conflicts */
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((__u32)(val)))
+
+/*The following definitions come from  lib/md4.c  */
+
+void mdfour(unsigned char *out, unsigned char *in, int n);
+
+/*The following definitions come from  libsmb/smbdes.c  */
+
+void E_P16(unsigned char *p14, unsigned char *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
+void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
+void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out);
+void cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key);
+void cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key);
+void cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key,
+		int forw);
+void SamOEMhash(unsigned char *data, unsigned char *key, int val);
+
+/*The following definitions come from  libsmb/smbencrypt.c  */
+
+void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+void E_md4hash(const unsigned char *passwd, unsigned char *p16);
+void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
+void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+		   unsigned char p24[24]);
+void NTLMSSPOWFencrypt(unsigned char passwd[8],
+		       unsigned char *ntlmchalresp, unsigned char p24[24]);
+void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
+int make_oem_passwd_hash(char data[516], const char *passwd,
+			 unsigned char old_pw_hash[16], int unicode);
+int decode_pw_buffer(char in_buffer[516], char *new_pwrd,
+		     int new_pwrd_size, __u32 * new_pw_len);
+
+/*
+   This implements the X/Open SMB password encryption
+   It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
+   encrypted password into p24 */
+/* Note that password must be uppercased and null terminated */
+void
+SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+{
+	unsigned char p14[15], p21[21];
+
+	memset(p21, '\0', 21);
+	memset(p14, '\0', 14);
+	strncpy((char *) p14, (char *) passwd, 14);
+
+/*	strupper((char *)p14); *//* BB at least uppercase the easy range */
+	E_P16(p14, p21);
+
+	SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBencrypt: lm#, challenge, response\n"));
+	dump_data(100, (char *) p21, 16);
+	dump_data(100, (char *) c8, 8);
+	dump_data(100, (char *) p24, 24);
+#endif
+}
+
+/* Routines for Windows NT MD4 Hash functions. */
+static int
+_my_wcslen(__u16 * str)
+{
+	int len = 0;
+	while (*str++ != 0)
+		len++;
+	return len;
+}
+
+/*
+ * Convert a string into an NT UNICODE string.
+ * Note that regardless of processor type 
+ * this must be in intel (little-endian)
+ * format.
+ */
+
+static int
+_my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
+{				/* not a very good conversion routine - change/fix */
+	int i;
+	__u16 val;
+
+	for (i = 0; i < len; i++) {
+		val = *src;
+		SSVAL(dst, 0, val);
+		dst++;
+		src++;
+		if (val == 0)
+			break;
+	}
+	return i;
+}
+
+/* 
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
+
+void
+E_md4hash(const unsigned char *passwd, unsigned char *p16)
+{
+	int len;
+	__u16 wpwd[129];
+
+	/* Password cannot be longer than 128 characters */
+	len = strlen((char *) passwd);
+	if (len > 128)
+		len = 128;
+	/* Password must be converted to NT unicode */
+	_my_mbstowcs(wpwd, passwd, len);
+	wpwd[len] = 0;		/* Ensure string is null terminated */
+	/* Calculate length in bytes */
+	len = _my_wcslen(wpwd) * sizeof (__u16);
+
+	mdfour(p16, (unsigned char *) wpwd, len);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+void
+nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
+{
+	char passwd[514];
+
+	memset(passwd, '\0', 514);
+	if (strlen(pwd) < 513)
+		strcpy(passwd, pwd);
+	else
+		memcpy(passwd, pwd, 512);
+	/* Calculate the MD4 hash (NT compatible) of the password */
+	memset(nt_p16, '\0', 16);
+	E_md4hash(passwd, nt_p16);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("nt_lm_owf_gen: pwd, nt#\n"));
+	dump_data(120, passwd, strlen(passwd));
+	dump_data(100, (char *) nt_p16, 16);
+#endif
+
+	/* Mangle the passwords into Lanman format */
+	passwd[14] = '\0';
+/*	strupper(passwd); */
+
+	/* Calculate the SMB (lanman) hash functions of the password */
+
+	memset(p16, '\0', 16);
+	E_P16((unsigned char *) passwd, (unsigned char *) p16);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("nt_lm_owf_gen: pwd, lm#\n"));
+	dump_data(120, passwd, strlen(passwd));
+	dump_data(100, (char *) p16, 16);
+#endif
+	/* clear out local copy of user's password (just being paranoid). */
+	memset(passwd, '\0', sizeof (passwd));
+}
+
+/* Does the NTLMv2 owfs of a user's password */
+void
+ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
+	     const char *domain_n, unsigned char kr_buf[16],
+	     const struct nls_table *nls_codepage)
+{
+	wchar_t user_u[1024];
+	wchar_t dom_u[1024];
+	struct HMACMD5Context ctx;
+
+	/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
+	   push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
+
+    /* do not think it is supposed to be uppercased */
+	int user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
+	int domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage);
+
+	user_l++;		/* trailing null */
+	domain_l++;
+
+	hmac_md5_init_limK_to_64(owf, 16, &ctx);
+	hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx);
+	hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx);
+	hmac_md5_final(kr_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+	dump_data(100, user_u, user_l * 2);
+	dump_data(100, dom_u, domain_l * 2);
+	dump_data(100, owf, 16);
+	dump_data(100, kr_buf, 16);
+#endif
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+void
+SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
+	      unsigned char p24[24])
+{
+	unsigned char p21[21];
+
+	memset(p21, '\0', 21);
+
+	memcpy(p21, passwd, 16);
+	E_P24(p21, c8, p24);
+}
+
+/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
+void
+NTLMSSPOWFencrypt(unsigned char passwd[8],
+		  unsigned char *ntlmchalresp, unsigned char p24[24])
+{
+	unsigned char p21[21];
+
+	memset(p21, '\0', 21);
+	memcpy(p21, passwd, 8);
+	memset(p21 + 8, 0xbd, 8);
+
+	E_P24(p21, ntlmchalresp, p24);
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("NTLMSSPOWFencrypt: p21, c8, p24\n"));
+	dump_data(100, (char *) p21, 21);
+	dump_data(100, (char *) ntlmchalresp, 8);
+	dump_data(100, (char *) p24, 24);
+#endif
+}
+
+/* Does the NT MD4 hash then des encryption. */
+
+void
+SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
+{
+	unsigned char p21[21];
+
+	memset(p21, '\0', 21);
+
+	E_md4hash(passwd, p21);
+	SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBNTencrypt: nt#, challenge, response\n"));
+	dump_data(100, (char *) p21, 16);
+	dump_data(100, (char *) c8, 8);
+	dump_data(100, (char *) p24, 24);
+#endif
+}
+
+int
+make_oem_passwd_hash(char data[516], const char *passwd,
+		     unsigned char old_pw_hash[16], int unicode)
+{
+	int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
+
+	if (new_pw_len > 512) {
+		cERROR(1,
+		       ("CIFS make_oem_passwd_hash: new password is too long.\n"));
+		return FALSE;
+	}
+
+	/*
+	 * Now setup the data area.
+	 * We need to generate a random fill
+	 * for this area to make it harder to
+	 * decrypt. JRA.
+	 *
+	 */
+	get_random_bytes(data, sizeof (data));
+	if (unicode) {
+		/* Note that passwd should be in DOS oem character set. */
+		/*  dos_struni2( &data[512 - new_pw_len], passwd, 512); */
+		cifs_strtoUCS((wchar_t *) & data[512 - new_pw_len], passwd, 512,	/* struct nls_table */
+			      load_nls_default());
+		/* BB call unload_nls now or get nls differntly */
+	} else {
+		/* Note that passwd should be in DOS oem character set. */
+		strcpy(&data[512 - new_pw_len], passwd);
+	}
+	SIVAL(data, 512, new_pw_len);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("make_oem_passwd_hash\n"));
+	dump_data(100, data, 516);
+#endif
+	SamOEMhash((unsigned char *) data, (unsigned char *) old_pw_hash, TRUE);
+
+	return TRUE;
+}
+
+/* Does the md5 encryption from the NT hash for NTLMv2. */
+void
+SMBOWFencrypt_ntv2(const unsigned char kr[16],
+		   const struct data_blob srv_chal,
+		   const struct data_blob cli_chal, unsigned char resp_buf[16])
+{
+	struct HMACMD5Context ctx;
+
+	hmac_md5_init_limK_to_64(kr, 16, &ctx);
+	hmac_md5_update(srv_chal.data, srv_chal.length, &ctx);
+	hmac_md5_update(cli_chal.data, cli_chal.length, &ctx);
+	hmac_md5_final(resp_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
+	dump_data(100, srv_chal.data, srv_chal.length);
+	dump_data(100, cli_chal.data, cli_chal.length);
+	dump_data(100, resp_buf, 16);
+#endif
+}
+
+void
+SMBsesskeygen_ntv2(const unsigned char kr[16],
+		   const unsigned char *nt_resp, __u8 sess_key[16])
+{
+	struct HMACMD5Context ctx;
+
+	hmac_md5_init_limK_to_64(kr, 16, &ctx);
+	hmac_md5_update(nt_resp, 16, &ctx);
+	hmac_md5_final((unsigned char *) sess_key, &ctx);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
+	dump_data(100, sess_key, 16);
+#endif
+}
+
+void
+SMBsesskeygen_ntv1(const unsigned char kr[16],
+		   const unsigned char *nt_resp, __u8 sess_key[16])
+{
+	mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+	dump_data(100, sess_key, 16);
+#endif
+}
+
+/***********************************************************
+ encode a password buffer.  The caller gets to figure out 
+ what to put in it.
+************************************************************/
+int
+encode_pw_buffer(char buffer[516], char *new_pw, int new_pw_length)
+{
+	get_random_bytes(buffer, sizeof (buffer));
+
+	memcpy(&buffer[512 - new_pw_length], new_pw, new_pw_length);
+
+	/* 
+	 * The length of the new password is in the last 4 bytes of
+	 * the data buffer.
+	 */
+	SIVAL(buffer, 512, new_pw_length);
+
+	return TRUE;
+}
+
+/***********************************************************
+ SMB signing - setup the MAC key.
+************************************************************/
+
+void
+cli_calculate_mac_key(__u8 * mac_key, int *pmac_key_len,
+		      const char *ntpasswd, const unsigned char resp[24])
+{
+	/* Get first 16 bytes. */
+	E_md4hash(ntpasswd, mac_key);
+	memcpy(mac_key + 16, resp, 24);
+	*pmac_key_len = 40;
+
+	/* Reset the sequence number in case we had a previous (aborted) attempt */
+/*	cli->sign_info.send_seq_num = 0; */
+}
+
+/***********************************************************
+ SMB signing - calculate a MAC to send.
+************************************************************/
+
+void
+cli_caclulate_sign_mac(struct smb_hdr *outbuf, __u8 * mac_key,
+		       int mac_key_len, __u32 * send_seq_num,
+		       __u32 * reply_seq_num)
+{
+	unsigned char calc_md5_mac[16];
+	struct MD5Context md5_ctx;
+
+/*	if (!cli->sign_info.use_smb_signing) {
+		return;
+	} */
+
+	/*
+	 * Firstly put the sequence number into the first 4 bytes.
+	 * and zero out the next 4 bytes.
+	 */
+/*
+	SIVAL(outbuf, smb_ss_field, *send_seq_num);
+	SIVAL(outbuf, smb_ss_field + 4, 0); */
+
+	/* Calculate the 16 byte MAC and place first 8 bytes into the field. */
+	MD5Init(&md5_ctx);
+	MD5Update(&md5_ctx, mac_key, mac_key_len);
+	MD5Update(&md5_ctx, outbuf->Protocol,
+		  be32_to_cpu(outbuf->smb_buf_length));
+	MD5Final(calc_md5_mac, &md5_ctx);
+
+	memcpy(outbuf->SecuritySignature, calc_md5_mac, 8);
+	(*send_seq_num)++;
+	*reply_seq_num = *send_seq_num;
+	(*send_seq_num)++;
+}
diff -Nru a/fs/cifs/smberr.h b/fs/cifs/smberr.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/smberr.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,112 @@
+/*
+ *   fs/cifs/smberr.h
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   See Error Codes section of the SNIA CIFS Specification 
+ *   for more information 
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+#define SUCCESS 0		/* The request was successful. */
+#define ERRDOS 0x01		/* Error is from the core DOS operating system set */
+#define ERRSRV 0x02		/* Error is generated by the file server daemon */
+#define ERRHRD 0x03		/* Error is a hardware error. */
+#define ERRCMD 0xFF		/*  Command was not in the "SMB" format. */
+
+/* The following error codes may be generated with the SUCCESS error class.*/
+
+#define SUCCESS 0		/* The request was successful. */
+
+/* The following error codes may be generated with the ERRDOS error class.*/
+
+#define ERRbadfunc 1		/* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */
+#define ERRbadfile 2		/*File not found. The last component of a file's pathname could not be found. */
+#define ERRbadpath 3		/* Directory invalid. A directory component in a pathname could not be found. */
+#define ERRnofids 4		/* Too many open files. The server has no file handles available. */
+#define ERRnoaccess 5		/* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */
+#define ERRbadfid 6		/* Invalid file handle. The file handle specified was not recognized by the server. */
+#define ERRbadmcb 7		/* Memory control blocks destroyed. */
+#define ERRnomem 8		/* Insufficient server memory to perform the requested function. */
+#define ERRbadmem 9		/* Invalid memory block address. */
+#define ERRbadenv 10		/* Invalid environment. */
+#define ERRbadformat 11		/* Invalid format. */
+#define ERRbadaccess 12		/* Invalid open mode. */
+#define ERRbaddata 13		/* Invalid data (generated only by IOCTL calls within the server). */
+#define ERRbaddrive 15		/* Invalid drive specified. */
+#define ERRremcd 16		/* A Delete Directory request attempted to remove the server's current directory. */
+#define ERRdiffdevice 17	/* Not same device (e.g., a cross volume rename was attempted */
+#define ERRnofiles 18		/* A File Search command can find no more files matching the specified criteria. */
+#define ERRgeneral 31
+#define ERRbadshare 32		/* The sharing mode specified for an Open conflicts with existing FIDs on the file. */
+#define ERRlock 33		/* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */
+#define ERRunsup     50
+#define ERRnosuchshare 67
+#define ERRfilexists 80		/* The file named in the request already exists. */
+#define ERRinvparm   87
+#define ERRdiskfull  112
+#define ERRinvnum    123
+#define ERRdirnotempty 145
+#define ERRnotlocked   158
+#define ERRalreadyexists 183
+#define ERRbadpipe 230
+#define ERRpipebusy 231
+#define ERRpipeclosing 232
+#define ERRnotconnected 233
+#define ERRmoredata    234
+#define ErrQuota 0x200		/* The operation would cause a quota limit to be exceeded. */
+#define ErrNotALink 0x201	/* A link operation was performed on a pathname that
+				   was not a link. */
+
+/* Following error codes may be generated with the ERRSRV error
+class.*/
+
+#define ERRerror 1		/* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */
+#define ERRbadpw 2		/* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */
+#define ERRbadtype 3		/* used for indicating DFS referral needed */
+#define ERRaccess 4		/* The client does not have the necessary access rights within the specified context for requested function. */
+#define ERRinvtid 5		/* The Tid specified in a command was invalid. */
+#define ERRinvnetname 6		/* Invalid network name in tree connect. */
+#define ERRinvdevice 7		/* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */
+#define ERRqfull 49		/* Print queue full (files) -- returned by open print file. */
+#define ERRqtoobig 50		/* Print queue full -- no space. */
+#define ERRqeof         51	/* EOF on print queue dump */
+#define ERRinvpfid      52	/* Invalid print file FID. */
+#define ERRsmbcmd       64	/* The server did not recognize the command received. */
+#define ERRsrverror     65	/* The server encountered an internal error, e.g., system file unavailable. */
+#define ERRbadBID       66	/* (obsolete) */
+#define ERRfilespecs    67	/* The Fid and pathname parameters contained an invalid combination of values. */
+#define ERRbadLink      68	/* (obsolete) */
+#define ERRbadpermits   69	/* The access permissions specified for a file or directory are not a valid combination. */
+#define ERRbadPID       70
+#define ERRsetattrmode  71	/* attribute (mode) is invalid */
+#define ERRpaused       81	/* Server is paused */
+#define ERRmsgoff	82	/* reserved - messaging off */
+#define ERRnoroom       83	/* reserved - no room for message */
+#define ERRrmuns        87	/* reserved - too many remote names */
+#define ERRtimeout      88	/* operation timed out */
+#define ERRnoresource   89	/* No resources available for request */
+#define ERRtoomanyuids  90	/* Too many UIDs active on this session */
+#define ERRbaduid       91	/* The UID is not known as a valid user */
+#define ERRusempx      250	/* temporarily unable to use raw */
+#define ERRusestd      251	/* temporarily unable to use either raw or mpx */
+#define ERR_NOTIFY_ENUM_DIR 1024
+#define ERRaccountexpired 2239
+#define ERRbadclient      2240
+#define ERRbadLogonTime   2241
+#define ERRpasswordExpired 2242
+#define ERRnosupport       0xFFFF
diff -Nru a/fs/cifs/transport.c b/fs/cifs/transport.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/cifs/transport.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,245 @@
+/*
+ *   fs/cifs/transport.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2002
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library 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 Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/net.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+
+extern kmem_cache_t *cifs_mid_cachep;
+
+struct mid_q_entry *
+AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
+{
+	struct mid_q_entry *temp;
+
+/* BB add spinlock to protect midq for each session BB */
+	if (ses == NULL) {
+		cERROR(1, ("\nNull session passed in to AllocMidQEntry "));
+		return NULL;
+	}
+	temp = kmalloc(sizeof (struct mid_q_entry), GFP_KERNEL);
+	temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep,
+						       SLAB_KERNEL);
+	if (temp == NULL)
+		return temp;
+	else {
+		memset(temp, 0, sizeof (struct mid_q_entry));
+		temp->mid = smb_buffer->Mid;	/* always LE */
+		temp->pid = current->pid;
+		temp->command = smb_buffer->Command;
+		cFYI(1, ("\nFor smb_command %d", temp->command));
+		do_gettimeofday(&temp->when_sent);
+		temp->ses = ses;
+		temp->tsk = current;
+	}
+	if (ses->status == CifsGood) {
+		list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
+		atomic_inc(&midCount);
+		temp->midState = MID_REQUEST_ALLOCATED;
+	} else {		/* BB add reconnect code here BB */
+
+		cERROR(1,
+		       ("\nNeed to reconnect after session died to server\n"));
+		if (temp)
+			kmem_cache_free(cifs_mid_cachep, temp);
+		return NULL;
+	}
+	return temp;
+}
+
+void
+DeleteMidQEntry(struct mid_q_entry *midEntry)
+{
+	/* BB add spinlock to protect midq for each session BB */
+	midEntry->midState = MID_FREE;
+	buf_release(midEntry->resp_buf);
+	list_del(&midEntry->qhead);
+	kmem_cache_free(cifs_mid_cachep, midEntry);
+	atomic_dec(&midCount);
+}
+
+int
+smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
+	 unsigned int smb_buf_length, struct sockaddr *sin)
+{
+	int rc = 0;
+	struct msghdr smb_msg;
+	struct iovec iov;
+	mm_segment_t temp_fs;
+
+    if(ssocket == NULL)
+        return -ENOTSOCK; /* BB eventually add reconnect code here */
+/*  ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */
+	iov.iov_base = smb_buffer;
+	iov.iov_len = smb_buf_length + 4;
+
+	smb_msg.msg_name = sin;
+	smb_msg.msg_namelen = sizeof (struct sockaddr);
+	smb_msg.msg_iov = &iov;
+	smb_msg.msg_iovlen = 1;
+	smb_msg.msg_control = NULL;
+	smb_msg.msg_controllen = 0;
+	smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL;	/* BB add more flags? */
+
+	/* smb header is converted in header_assemble. bcc and rest of SMB word area, 
+	   and byte area if necessary, is converted to littleendian in cifssmb.c and RFC1001 
+	   len is converted to bigendian in smb_send */
+	if (smb_buf_length > 12)
+		smb_buffer->Flags2 = cpu_to_le16(smb_buffer->Flags2);
+
+    /* if(smb_buffer->Flags2 & SMBFLG2_SECURITY_SIGNATURE)
+        sign_smb(smb_buffer); */ /* BB enable when signing tested more */
+
+	smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
+	cFYI(1, ("\nSending smb of length %d ", smb_buf_length));
+	dump_smb(smb_buffer, smb_buf_length + 4);
+
+	temp_fs = get_fs();	/* we must turn off socket api parm checking */
+	set_fs(get_ds());
+	rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4);
+
+	set_fs(temp_fs);
+
+	if (rc < 0) {
+		cERROR(1,
+		       ("\nError %d sending data on socket to server.\n", rc));
+	} else
+		rc = 0;
+
+	return rc;
+}
+
+int
+SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
+	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,
+	    int *pbytes_returned, const int long_op)
+{
+	int rc = 0;
+	int receive_len;
+	long timeout;
+	struct mid_q_entry *midQ;
+
+	midQ = AllocMidQEntry(in_buf, ses);
+	if (midQ == NULL)
+		return -EIO;	/* reconnect should be done, if possible, in AllocMidQEntry */
+	if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
+		cERROR(1,
+		       ("\nIllegal length, greater than maximum frame, %d ",
+			in_buf->smb_buf_length));
+		DeleteMidQEntry(midQ);
+		return -EIO;
+	}
+	midQ->midState = MID_REQUEST_SUBMITTED;
+	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
+		      (struct sockaddr *) &(ses->server->sockAddr));
+
+	cFYI(1, ("\ncifs smb_send rc %d", rc));	/* BB remove */
+	/* BB add code to wait for response and copy to out_buf */
+	if (long_op > 1)	/* writes past end of file can take a looooooong time */
+		timeout = 300 * HZ;
+	else if (long_op == 1)
+		timeout = 60 * HZ;
+	else
+		timeout = 15 * HZ;
+	/* wait for 15 seconds or until woken up due to response arriving or due to 
+	   last connection to this server being unmounted */
+
+	/* timeout = interruptible_sleep_on_timeout(&ses->server->response_q,timeout); */
+	/* Replace above line with wait_event to get rid of sleep_on per lk guidelines */
+
+	timeout = wait_event_interruptible_timeout(ses->server->response_q,
+						   midQ->
+						   midState &
+						   MID_RESPONSE_RECEIVED,
+						   15 * HZ);
+	cFYI(1,
+	     (" with timeout %ld and Out_buf: %p  midQ->resp_buf: %p ", timeout,
+	      out_buf, midQ->resp_buf));
+	if (signal_pending(current)) {
+		cERROR(1, (KERN_ERR "\nCIFS: caught signal"));
+		DeleteMidQEntry(midQ);
+		return -EINTR;
+	} else {
+		if (midQ->resp_buf)
+			receive_len =
+			    be32_to_cpu(midQ->resp_buf->smb_buf_length);
+		else {
+			DeleteMidQEntry(midQ);
+			return -EIO;
+		}
+	}
+
+	if (timeout == 0) {
+		cFYI(1,
+		     ("\nTimeout on receive. Assume response SMB is invalid.\n"));
+		rc = -ETIMEDOUT;
+	} else if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
+		cERROR(1,
+		       ("\nFrame too large received.  Length: %d  Xid: %d\n",
+			receive_len, xid));
+		rc = -EIO;
+	} else {		/* rcvd frame is ok */
+
+		if (midQ->resp_buf && out_buf
+		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
+			memcpy(out_buf, midQ->resp_buf,
+			       receive_len +
+			       4 /* include 4 byte RFC1001 header */ );
+			/* convert the length back to a form that we can use */
+
+			dump_smb(out_buf, 92);
+
+			out_buf->smb_buf_length =
+			    be32_to_cpu(out_buf->smb_buf_length);
+			if (out_buf->smb_buf_length > 12)
+				out_buf->Flags2 = le16_to_cpu(out_buf->Flags2);
+			if (out_buf->smb_buf_length > 28)
+				out_buf->Pid = le16_to_cpu(out_buf->Pid);
+			if (out_buf->smb_buf_length > 28)
+				out_buf->PidHigh =
+				    le16_to_cpu(out_buf->PidHigh);
+
+			*pbytes_returned = out_buf->smb_buf_length;
+
+			/* BB special case reconnect tid and reconnect uid here? */
+			rc = map_smb_to_linux_error(out_buf);	/* BB watch endianness here BB */
+
+			/* convert ByteCount if necessary */
+			if (receive_len >=
+			    sizeof (struct smb_hdr) -
+			    4 /* do not count RFC1001 header */  +
+			    (2 * out_buf->WordCount) + 2 /* bcc */ )
+				BCC(out_buf) = le16_to_cpu(BCC(out_buf));
+		} else
+			rc = -EIO;
+	}
+
+	DeleteMidQEntry(midQ);	/* BB what if process is killed ? - BB add background daemon to clean up Mid entries from killed processes BB test killing process with active mid */
+	return rc;
+}
diff -Nru a/fs/coda/cnode.c b/fs/coda/cnode.c
--- a/fs/coda/cnode.c	Fri Oct 11 21:22:54 2002
+++ b/fs/coda/cnode.c	Fri Oct 11 21:22:54 2002
@@ -26,9 +26,9 @@
 }
 
 static struct inode_operations coda_symlink_inode_operations = {
-	readlink:	page_readlink,
-	follow_link:	page_follow_link,
-	setattr:	coda_setattr,
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.setattr	= coda_setattr,
 };
 
 /* cnode.c */
@@ -85,6 +85,7 @@
 		cii = ITOC(inode);
 		/* we still need to set i_ino for things like stat(2) */
 		inode->i_ino = hash;
+		cii->c_mapcount = 0;
 		list_add(&cii->c_cilist, &sbi->sbi_cihead);
 		unlock_new_inode(inode);
 	}
diff -Nru a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
--- a/fs/coda/coda_linux.c	Fri Oct 11 21:22:50 2002
+++ b/fs/coda/coda_linux.c	Fri Oct 11 21:22:50 2002
@@ -29,21 +29,7 @@
 char * coda_f2s(ViceFid *f)
 {
 	static char s[60];
-	if ( f ) {
-		sprintf(s, "(%-#lx,%-#lx,%-#lx)", 
-			 f->Volume, f->Vnode, f->Unique);
-	}
-	return s;
-}
-
-/* print another fid */
-char * coda_f2s2(ViceFid *f)
-{
-	static char s[60];
-	if ( f ) {
-		sprintf(s, "(%-#lx,%-#lx,%-#lx)", 
-			 f->Volume, f->Vnode, f->Unique);
-	}
+	sprintf(s, "(%-#lx.%-#lx.%-#lx)", f->Volume, f->Vnode, f->Unique);
 	return s;
 }
 
diff -Nru a/fs/coda/dir.c b/fs/coda/dir.c
--- a/fs/coda/dir.c	Fri Oct 11 21:22:53 2002
+++ b/fs/coda/dir.c	Fri Oct 11 21:22:53 2002
@@ -49,40 +49,42 @@
 static int coda_dentry_delete(struct dentry *);
 
 /* support routines */
-static int coda_venus_readdir(struct file *filp, filldir_t filldir, void *dirent);
+static int coda_venus_readdir(struct file *filp, filldir_t filldir,
+			      void *dirent, struct dentry *dir);
 int coda_fsync(struct file *, struct dentry *dentry, int datasync);
 
 int coda_hasmknod;
 
 struct dentry_operations coda_dentry_operations =
 {
-	d_revalidate:	coda_dentry_revalidate,
-	d_delete:	coda_dentry_delete,
+	.d_revalidate	= coda_dentry_revalidate,
+	.d_delete	= coda_dentry_delete,
 };
 
 struct inode_operations coda_dir_inode_operations =
 {
-	create:		coda_create,
-	lookup:		coda_lookup,
-	link:		coda_link,
-	unlink:		coda_unlink,
-	symlink:	coda_symlink,
-	mkdir:		coda_mkdir,
-	rmdir:		coda_rmdir,
-	mknod:		coda_mknod,
-	rename:		coda_rename,
-	permission:	coda_permission,
-        getattr:	coda_getattr,
-	setattr:	coda_setattr,
+	.create		= coda_create,
+	.lookup		= coda_lookup,
+	.link		= coda_link,
+	.unlink		= coda_unlink,
+	.symlink	= coda_symlink,
+	.mkdir		= coda_mkdir,
+	.rmdir		= coda_rmdir,
+	.mknod		= coda_mknod,
+	.rename		= coda_rename,
+	.permission	= coda_permission,
+	.getattr	= coda_getattr,
+	.setattr	= coda_setattr,
 };
 
 struct file_operations coda_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	coda_readdir,
-	open:		coda_open,
-	flush:  	coda_flush,
-	release:	coda_release,
-	fsync:		coda_fsync,
+	.llseek		= generic_file_llseek,
+	.read		= generic_read_dir,
+	.readdir	= coda_readdir,
+	.open		= coda_open,
+	.flush		= coda_flush,
+	.release	= coda_release,
+	.fsync		= coda_fsync,
 };
 
 
@@ -475,70 +477,99 @@
 
 
 /* file operations for directories */
-int coda_readdir(struct file *coda_file, void *dirent,  filldir_t filldir)
+int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
 {
-        int result = 0;
 	struct dentry *coda_dentry = coda_file->f_dentry;
-	struct inode *coda_inode = coda_dentry->d_inode;
-	struct coda_inode_info *cii = ITOC(coda_inode);
-	struct file *host_file = cii->c_container;
+	struct coda_file_info *cfi;
+	struct file *host_file;
+	struct inode *host_inode;
+	int ret;
 
-        BUG_ON(!host_file);
+	cfi = CODA_FTOC(coda_file);
+	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+	host_file = cfi->cfi_container;
 
 	coda_vfs_stat.readdir++;
 
-	/* Access to both host and coda f_pos fields is serialized on the
-	 * coda_file->f_dentry->d_inode->i_sem which has already been taken by
-	 * vfs_readdir. Userspace shouldn't 'play' with the container file as
-	 * long as the file is held open. */
+	host_inode = host_file->f_dentry->d_inode;
+	down(&host_inode->i_sem);
 	host_file->f_pos = coda_file->f_pos;
 
-	if ( !host_file->f_op->readdir )
+	if (!host_file->f_op->readdir) {
 		/* Venus: we must read Venus dirents from the file */
-		result = coda_venus_readdir(host_file, filldir, dirent);
-        else
-		/* potemkin case: we were handed a directory inode */
-		result = vfs_readdir(host_file, filldir, dirent);
-
+		ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
+	} else {
+		/* potemkin case: we were handed a directory inode. */
+		/* Yuk, we can't call vfs_readdir because we are already
+		 * holding the inode semaphore. */
+		ret = -ENOTDIR;
+		if (!host_file->f_op || !host_file->f_op->readdir)
+			goto out;
+
+		ret = -ENOENT;
+		if (!IS_DEADDIR(host_inode))
+			ret = host_file->f_op->readdir(host_file, filldir, dirent);
+	}
+out:
 	coda_file->f_pos = host_file->f_pos;
-	return result;
+	up(&host_inode->i_sem);
+
+	return ret;
 }
 
 static inline unsigned int CDT2DT(unsigned char cdt)
 {
-    unsigned int dt;
+	unsigned int dt;
 
-    switch(cdt) {
-    case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
-    case CDT_FIFO:    dt = DT_FIFO;    break;
-    case CDT_CHR:     dt = DT_CHR;     break;
-    case CDT_DIR:     dt = DT_DIR;     break;
-    case CDT_BLK:     dt = DT_BLK;     break;
-    case CDT_REG:     dt = DT_REG;     break;
-    case CDT_LNK:     dt = DT_LNK;     break;
-    case CDT_SOCK:    dt = DT_SOCK;    break;
-    case CDT_WHT:     dt = DT_WHT;     break;
-    default:	      dt = DT_UNKNOWN; break;
-    }
-    return dt;
+	switch(cdt) {
+	case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
+	case CDT_FIFO:	  dt = DT_FIFO;    break;
+	case CDT_CHR:	  dt = DT_CHR;     break;
+	case CDT_DIR:	  dt = DT_DIR;     break;
+	case CDT_BLK:	  dt = DT_BLK;     break;
+	case CDT_REG:	  dt = DT_REG;     break;
+	case CDT_LNK:	  dt = DT_LNK;     break;
+	case CDT_SOCK:	  dt = DT_SOCK;    break;
+	case CDT_WHT:	  dt = DT_WHT;     break;
+	default:	  dt = DT_UNKNOWN; break;
+	}
+	return dt;
 }
 
 /* support routines */
 static int coda_venus_readdir(struct file *filp, filldir_t filldir,
-			      void *getdent)
+			      void *dirent, struct dentry *dir)
 {
 	int result = 0; /* # of entries returned */
-        struct venus_dirent *vdir;
-        unsigned long vdir_size =
+	struct venus_dirent *vdir;
+	unsigned long vdir_size =
 	    (unsigned long)(&((struct venus_dirent *)0)->d_name);
-	int ret;
+	unsigned int type;
+	struct qstr name;
+	ino_t ino;
+	int ret, i;
 
 	vdir = (struct venus_dirent *)kmalloc(sizeof(*vdir), GFP_KERNEL);
 	if (!vdir) return -ENOMEM;
 
-	while(1) {
-		/* we use this routine to read the file into our buffer */
-		ret = kernel_read(filp, filp->f_pos, (char *)vdir,
+	i = filp->f_pos;
+	switch(i) {
+	case 0:
+		ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR);
+		if (ret < 0) break;
+		result++;
+		filp->f_pos++;
+		/* fallthrough */
+	case 1:
+		ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR);
+		if (ret < 0) break;
+		result++;
+		filp->f_pos++;
+		/* fallthrough */
+	default:
+	while (1) {
+		/* read entries from the directory file */
+		ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir,
 				  sizeof(*vdir));
 		if (ret < 0) {
 			printk("coda_venus_readdir: read dir failed %d\n", ret);
@@ -548,35 +579,51 @@
 
 		/* catch truncated reads */
 		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
-		    printk("coda_venus_readdir: short read: %ld\n", 
-			   filp->f_dentry->d_inode->i_ino);
-		    ret = -EBADF;
-		    break;
+			printk("coda_venus_readdir: short read: %ld\n",
+			       filp->f_dentry->d_inode->i_ino);
+			ret = -EBADF;
+			break;
 		}
 		/* validate whether the directory file actually makes sense */
 		if (vdir->d_reclen < vdir_size + vdir->d_namlen ||
 		    vdir->d_namlen > CODA_MAXNAMLEN) {
-		    printk("coda_venus_readdir: Invalid directory: %ld\n", 
-			   filp->f_dentry->d_inode->i_ino);
-		    ret = -EBADF;
-		    break;
+			printk("coda_venus_readdir: Invalid dir: %ld\n",
+			       filp->f_dentry->d_inode->i_ino);
+			ret = -EBADF;
+			break;
 		}
 
+		name.len = vdir->d_namlen;
+		name.name = vdir->d_name;
+
+		/* Make sure we skip '.' and '..', we already got those */
+		if (name.name[0] == '.' && (name.len == 1 ||
+		    (vdir->d_name[1] == '.' && name.len == 2)))
+			vdir->d_fileno = name.len = 0;
+
 		/* skip null entries */
-		if (vdir->d_fileno) {
-		    unsigned int d_type = CDT2DT(vdir->d_type);
-		    ret = filldir(getdent, vdir->d_name, vdir->d_namlen, 
-				  filp->f_pos, vdir->d_fileno, d_type); 
-		    /* failure means no space for filling in this round */
-		    if (ret < 0) break;
-		    result++;
+		if (vdir->d_fileno && name.len) {
+			/* try to look up this entry in the dcache, that way
+			 * userspace doesn't have to worry about breaking
+			 * getcwd by having mismatched inode numbers for
+			 * internal volume mountpoints. */
+			ino = find_inode_number(dir, &name);
+			if (!ino) ino = vdir->d_fileno;
+
+			type = CDT2DT(vdir->d_type);
+			ret = filldir(dirent, name.name, name.len, filp->f_pos,
+				      ino, type); 
+			/* failure means no space for filling in this round */
+			if (ret < 0) break;
+			result++;
 		}
 		/* we'll always have progress because d_reclen is unsigned and
 		 * we've already established it is non-zero. */
 		filp->f_pos += vdir->d_reclen;
 	}
+	} 
 	kfree(vdir);
-        return result ? result : ret;
+	return result ? result : ret;
 }
 
 /* called when a cache lookup succeeds */
@@ -660,7 +707,7 @@
 	if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
 		error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
 		if ( error )
-			goto return_bad_inode;
+			goto return_bad;
 
 		/* this inode may be lost if:
 		   - it's ino changed 
@@ -679,7 +726,7 @@
 		/* the following can happen when a local fid is replaced 
 		   with a global one, here we lose and declare the inode bad */
 		if (inode->i_ino != old_ino)
-			goto return_bad_inode;
+			goto return_bad;
 		
 		coda_flag_inode_children(inode, C_FLUSH);
 		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
@@ -689,13 +736,7 @@
 	unlock_kernel();
 	return 0;
 
-return_bad_inode:
-        inode->i_mapping = &inode->i_data;
-	if (cii->c_container) {
-		fput(cii->c_container);
-		cii->c_container = NULL;
-	}
-	make_bad_inode(inode);
+return_bad:
 	unlock_kernel();
 	return -EIO;
 }
diff -Nru a/fs/coda/file.c b/fs/coda/file.c
--- a/fs/coda/file.c	Fri Oct 11 21:22:55 2002
+++ b/fs/coda/file.c	Fri Oct 11 21:22:55 2002
@@ -29,143 +29,152 @@
 int use_coda_close;
 
 static ssize_t
-coda_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+coda_file_read(struct file *coda_file, char *buf, size_t count, loff_t *ppos)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	struct coda_inode_info *cii = ITOC(inode);
-	struct file *cfile;
+	struct coda_file_info *cfi;
+	struct file *host_file;
 
-	cfile = cii->c_container;
-	if (!cfile) BUG();
+	cfi = CODA_FTOC(coda_file);
+	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+	host_file = cfi->cfi_container;
 
-	if (!cfile->f_op || !cfile->f_op->read)
+	if (!host_file->f_op || !host_file->f_op->read)
 		return -EINVAL;
 
-	return cfile->f_op->read(cfile, buf, count, ppos);
+	return host_file->f_op->read(host_file, buf, count, ppos);
 }
 
 static ssize_t
-coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
+coda_file_write(struct file *coda_file, const char *buf, size_t count, loff_t *ppos)
 {
-	struct inode *cinode, *inode = file->f_dentry->d_inode;
-	struct coda_inode_info *cii = ITOC(inode);
-	struct file *cfile;
+	struct inode *host_inode, *coda_inode = coda_file->f_dentry->d_inode;
+	struct coda_file_info *cfi;
+	struct file *host_file;
 	ssize_t ret;
-	int flags;
 
-	cfile = cii->c_container;
-	if (!cfile) BUG();
+	cfi = CODA_FTOC(coda_file);
+	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+	host_file = cfi->cfi_container;
 
-	if (!cfile->f_op || !cfile->f_op->write)
+	if (!host_file->f_op || !host_file->f_op->write)
 		return -EINVAL;
 
-	cinode = cfile->f_dentry->d_inode;
-	down(&inode->i_sem);
-	flags = cfile->f_flags;
-        cfile->f_flags |= file->f_flags & (O_APPEND | O_SYNC);
-
-	ret = cfile->f_op->write(cfile, buf, count, ppos);
-
-	cfile->f_flags = flags;
-	inode->i_size = cinode->i_size;
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	up(&inode->i_sem);
+	host_inode = host_file->f_dentry->d_inode;
+	down(&coda_inode->i_sem);
+
+	ret = host_file->f_op->write(host_file, buf, count, ppos);
+
+	coda_inode->i_size = host_inode->i_size;
+	coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
+	coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME;
+	up(&coda_inode->i_sem);
 
 	return ret;
 }
 
 static int
-coda_file_mmap(struct file *file, struct vm_area_struct *vma)
+coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	struct coda_inode_info *cii = ITOC(inode);
-	struct file *cfile;
-
-	cfile = cii->c_container;
+	struct coda_file_info *cfi;
+	struct coda_inode_info *cii;
+	struct file *host_file;
+	struct inode *coda_inode, *host_inode;
 
-	if (!cfile) BUG();
+	cfi = CODA_FTOC(coda_file);
+	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+	host_file = cfi->cfi_container;
 
-	if (!cfile->f_op || !cfile->f_op->mmap)
+	if (!host_file->f_op || !host_file->f_op->mmap)
 		return -ENODEV;
 
-	return cfile->f_op->mmap(cfile, vma);
+	coda_inode = coda_file->f_dentry->d_inode;
+	host_inode = host_file->f_dentry->d_inode;
+	if (coda_inode->i_mapping == &coda_inode->i_data)
+		coda_inode->i_mapping = host_inode->i_mapping;
+
+	/* only allow additional mmaps as long as userspace isn't changing
+	 * the container file on us! */
+	else if (coda_inode->i_mapping != host_inode->i_mapping)
+		return -EBUSY;
+
+	/* keep track of how often the coda_inode/host_file has been mmapped */
+	cii = ITOC(coda_inode);
+	cii->c_mapcount++;
+	cfi->cfi_mapcount++;
+
+	return host_file->f_op->mmap(host_file, vma);
 }
 
-int coda_open(struct inode *i, struct file *f)
+int coda_open(struct inode *coda_inode, struct file *coda_file)
 {
-	struct file *fh = NULL;
-	int error = 0;
-	unsigned short flags = f->f_flags & (~O_EXCL);
+	struct file *host_file = NULL;
+	int error;
+	unsigned short flags = coda_file->f_flags & (~O_EXCL);
 	unsigned short coda_flags = coda_flags_to_cflags(flags);
-	struct coda_cred *cred;
-	struct coda_inode_info *cii;
+	struct coda_file_info *cfi;
 
-	lock_kernel();
 	coda_vfs_stat.open++;
 
-	error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &fh); 
-	if (error || !fh) {
+	cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
+	if (!cfi) {
 		unlock_kernel();
-		return error;
+		return -ENOMEM;
 	}
 
-	/* coda_upcall returns filehandle of container file object */
-	cii = ITOC(i);
-	if (cii->c_container)
-		fput(cii->c_container);
-
-	cii->c_contcount++;
-	cii->c_container = fh;
-	i->i_mapping = &cii->c_container->f_dentry->d_inode->i_data;
-
-	cred = kmalloc(sizeof(struct coda_cred), GFP_KERNEL);
-
-	/* If the allocation failed, we'll just muddle on. This actually works
-	 * fine for normal cases. (i.e. when open credentials are the same as
-	 * close credentials) */
-	if (cred) {
-		coda_load_creds(cred);
-		f->private_data = cred;
+	lock_kernel();
+
+	error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
+			   &host_file); 
+	if (error || !host_file) {
+		kfree(cfi);
+		unlock_kernel();
+		return error;
 	}
 
+	host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC);
+
+	cfi->cfi_magic = CODA_MAGIC;
+	cfi->cfi_mapcount = 0;
+	cfi->cfi_container = host_file;
+	coda_load_creds(&cfi->cfi_cred);
+
+	BUG_ON(coda_file->private_data != NULL);
+	coda_file->private_data = cfi;
+
 	unlock_kernel();
 	return 0;
 }
 
-
-int coda_flush(struct file *file)
+int coda_flush(struct file *coda_file)
 {
-	unsigned short flags = (file->f_flags) & (~O_EXCL);
-	unsigned short cflags;
-	struct coda_inode_info *cii;
-	struct file *cfile;
-	struct inode *cinode, *inode;
+	unsigned short flags = coda_file->f_flags & ~O_EXCL;
+	unsigned short coda_flags = coda_flags_to_cflags(flags);
+	struct coda_file_info *cfi;
+	struct inode *coda_inode;
 	int err = 0, fcnt;
 
 	coda_vfs_stat.flush++;
 
+	/* last close semantics */
+	fcnt = file_count(coda_file);
+	if (fcnt > 1) return 0;
+
 	/* No need to make an upcall when we have not made any modifications
 	 * to the file */
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+	if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
 		return 0;
 
 	if (use_coda_close)
 		return 0;
 
-	fcnt = file_count(file);
-	if (fcnt > 1) return 0;
-
-	cflags = coda_flags_to_cflags(flags);
+	cfi = CODA_FTOC(coda_file);
+	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
 
-	inode = file->f_dentry->d_inode;
-	cii = ITOC(inode);
-	cfile = cii->c_container;
-	if (!cfile) BUG();
+	coda_inode = coda_file->f_dentry->d_inode;
 
-	cinode = cfile->f_dentry->d_inode;
+	err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
+			  &cfi->cfi_cred);
 
-	err = venus_store(inode->i_sb, coda_i2f(inode), cflags,
-                          (struct coda_cred *)file->private_data);
 	if (err == -EOPNOTSUPP) {
 		use_coda_close = 1;
 		err = 0;
@@ -174,79 +183,81 @@
 	return err;
 }
 
-int coda_release(struct inode *i, struct file *f)
+int coda_release(struct inode *coda_inode, struct file *coda_file)
 {
-	unsigned short flags = (f->f_flags) & (~O_EXCL);
-	unsigned short cflags = coda_flags_to_cflags(flags);
+	unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
+	unsigned short coda_flags = coda_flags_to_cflags(flags);
+	struct coda_file_info *cfi;
 	struct coda_inode_info *cii;
-	struct file *cfile;
+	struct inode *host_inode;
 	int err = 0;
 
 	lock_kernel();
 	coda_vfs_stat.release++;
  
 	if (!use_coda_close) {
-		err = venus_release(i->i_sb, coda_i2f(i), cflags);
+		err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
+				    coda_flags);
 		if (err == -EOPNOTSUPP) {
 			use_coda_close = 1;
 			err = 0;
 		}
 	}
 
-	if (use_coda_close)
-		err = venus_close(i->i_sb, coda_i2f(i), cflags,
-                                  (struct coda_cred *)f->private_data);
-
-	cii = ITOC(i);
-	cfile = cii->c_container;
-	if (!cfile) BUG();
+	cfi = CODA_FTOC(coda_file);
+	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
 
-	if (--cii->c_contcount) {
-		unlock_kernel();
-		return err;
-	}
+	if (use_coda_close)
+		err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
+				  coda_flags, &cfi->cfi_cred);
 
-	i->i_mapping = &i->i_data;
-	fput(cfile);
-	cii->c_container = NULL;
+	host_inode = cfi->cfi_container->f_dentry->d_inode;
+	cii = ITOC(coda_inode);
 
-	if (f->private_data) {
-		kfree(f->private_data);
-		f->private_data = NULL;
-	}
+	/* did we mmap this file? */
+	if (coda_inode->i_mapping == &host_inode->i_data) {
+		cii->c_mapcount -= cfi->cfi_mapcount;
+		if (!cii->c_mapcount)
+			coda_inode->i_mapping = &coda_inode->i_data;
+	}
+
+	fput(cfi->cfi_container);
+	kfree(coda_file->private_data);
+	coda_file->private_data = NULL;
 
 	unlock_kernel();
 	return err;
 }
 
-int coda_fsync(struct file *file, struct dentry *dentry, int datasync)
+int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
 {
-	struct file *cfile;
-	struct dentry *cdentry;
-	struct inode *cinode, *inode = dentry->d_inode;
-	struct coda_inode_info *cii = ITOC(inode);
+	struct file *host_file;
+	struct dentry *host_dentry;
+	struct inode *host_inode, *coda_inode = coda_dentry->d_inode;
+	struct coda_file_info *cfi;
 	int err = 0;
 
-	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-	      S_ISLNK(inode->i_mode)))
+	if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
+	      S_ISLNK(coda_inode->i_mode)))
 		return -EINVAL;
 
-	cfile = cii->c_container;
-	if (!cfile) BUG();
+	cfi = CODA_FTOC(coda_file);
+	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+	host_file = cfi->cfi_container;
 
 	coda_vfs_stat.fsync++;
 
-	if (cfile->f_op && cfile->f_op->fsync) {
-		cdentry = cfile->f_dentry;
-		cinode = cdentry->d_inode;
-		down(&cinode->i_sem);
-		err = cfile->f_op->fsync(cfile, cdentry, datasync);
-		up(&cinode->i_sem);
+	if (host_file->f_op && host_file->f_op->fsync) {
+		host_dentry = host_file->f_dentry;
+		host_inode = host_dentry->d_inode;
+		down(&host_inode->i_sem);
+		err = host_file->f_op->fsync(host_file, host_dentry, datasync);
+		up(&host_inode->i_sem);
 	}
 
 	if ( !err && !datasync ) {
 		lock_kernel();
-		err = venus_fsync(inode->i_sb, coda_i2f(inode));
+		err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
 		unlock_kernel();
 	}
 
@@ -254,13 +265,13 @@
 }
 
 struct file_operations coda_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		coda_file_read,
-	write:		coda_file_write,
-	mmap:		coda_file_mmap,
-	open:		coda_open,
-	flush:  	coda_flush,
-	release:	coda_release,
-	fsync:		coda_fsync,
+	.llseek		= generic_file_llseek,
+	.read		= coda_file_read,
+	.write		= coda_file_write,
+	.mmap		= coda_file_mmap,
+	.open		= coda_open,
+	.flush		= coda_flush,
+	.release	= coda_release,
+	.fsync		= coda_fsync,
 };
 
diff -Nru a/fs/coda/inode.c b/fs/coda/inode.c
--- a/fs/coda/inode.c	Fri Oct 11 21:22:58 2002
+++ b/fs/coda/inode.c	Fri Oct 11 21:22:58 2002
@@ -8,7 +8,6 @@
  * Copyright (C) Carnegie Mellon University
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -47,8 +46,6 @@
 	memset(&ei->c_fid, 0, sizeof(struct ViceFid));
 	ei->c_flags = 0;
 	INIT_LIST_HEAD(&ei->c_cilist);
-	ei->c_container = NULL;
-	ei->c_contcount = 0;
 	memset(&ei->c_cached_cred, 0, sizeof(struct coda_cred));
 	ei->c_cached_perm = 0;
 	return &ei->vfs_inode;
@@ -88,11 +85,11 @@
 /* exported operations */
 struct super_operations coda_super_operations =
 {
-	alloc_inode:	coda_alloc_inode,
-	destroy_inode:	coda_destroy_inode,
-	clear_inode:	coda_clear_inode,
-	put_super:	coda_put_super,
-	statfs:		coda_statfs,
+	.alloc_inode	= coda_alloc_inode,
+	.destroy_inode	= coda_destroy_inode,
+	.clear_inode	= coda_clear_inode,
+	.put_super	= coda_put_super,
+	.statfs		= coda_statfs,
 };
 
 static int get_device_index(struct coda_mount_data *data)
@@ -175,7 +172,7 @@
 	sbi->sbi_vcomm = vc;
 	INIT_LIST_HEAD(&sbi->sbi_cihead);
 
-        sb->u.generic_sbp = sbi;
+        sb->s_fs_info = sbi;
         sb->s_blocksize = 1024;	/* XXXXX  what do we put here?? */
         sb->s_blocksize_bits = 10;
         sb->s_magic = CODA_SUPER_MAGIC;
@@ -230,10 +227,7 @@
 {
 	struct coda_inode_info *cii = ITOC(inode);
 
-	if (cii->c_container) BUG();
-	
-        list_del_init(&cii->c_cilist);
-	inode->i_mapping = &inode->i_data;
+	list_del_init(&cii->c_cilist);
 	coda_cache_clear_inode(inode);
 }
 
@@ -248,16 +242,16 @@
 int coda_setattr(struct dentry *de, struct iattr *iattr)
 {
 	struct inode *inode = de->d_inode;
-        struct coda_vattr vattr;
-        int error;
-	
+	struct coda_vattr vattr;
+	int error;
+
 	lock_kernel();
 	
-        memset(&vattr, 0, sizeof(vattr)); 
+	memset(&vattr, 0, sizeof(vattr)); 
 
 	inode->i_ctime = CURRENT_TIME;
-        coda_iattr_to_vattr(iattr, &vattr);
-        vattr.va_type = C_VNON; /* cannot set type */
+	coda_iattr_to_vattr(iattr, &vattr);
+	vattr.va_type = C_VNON; /* cannot set type */
 
 	/* Venus is responsible for truncating the container-file!!! */
 	error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
@@ -273,9 +267,9 @@
 }
 
 struct inode_operations coda_file_inode_operations = {
-	permission:	coda_permission,
-	getattr:	coda_getattr,
-	setattr:	coda_setattr,
+	.permission	= coda_permission,
+	.getattr	= coda_getattr,
+	.setattr	= coda_setattr,
 };
 
 static int coda_statfs(struct super_block *sb, struct statfs *buf)
@@ -314,8 +308,9 @@
 }
 
 struct file_system_type coda_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"coda",
-	get_sb:		coda_get_sb,
-	kill_sb:	kill_anon_super,
+	.owner		= THIS_MODULE,
+	.name		= "coda",
+	.get_sb		= coda_get_sb,
+	.kill_sb	= kill_anon_super,
 };
+
diff -Nru a/fs/coda/pioctl.c b/fs/coda/pioctl.c
--- a/fs/coda/pioctl.c	Fri Oct 11 21:23:01 2002
+++ b/fs/coda/pioctl.c	Fri Oct 11 21:23:01 2002
@@ -14,7 +14,6 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/string.h>
-#define __NO_VERSION__
 #include <linux/namei.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
@@ -32,13 +31,13 @@
 /* exported from this file */
 struct inode_operations coda_ioctl_inode_operations =
 {
-	permission:	coda_ioctl_permission,
-	setattr:	coda_setattr,
+	.permission	= coda_ioctl_permission,
+	.setattr	= coda_setattr,
 };
 
 struct file_operations coda_ioctl_operations = {
-	owner:		THIS_MODULE,
-	ioctl:		coda_pioctl,
+	.owner		= THIS_MODULE,
+	.ioctl		= coda_pioctl,
 };
 
 /* the coda pioctl inode ops */
diff -Nru a/fs/coda/psdev.c b/fs/coda/psdev.c
--- a/fs/coda/psdev.c	Fri Oct 11 21:23:00 2002
+++ b/fs/coda/psdev.c	Fri Oct 11 21:23:00 2002
@@ -353,13 +353,13 @@
 
 
 static struct file_operations coda_psdev_fops = {
-	owner:		THIS_MODULE,
-	read:		coda_psdev_read,
-	write:		coda_psdev_write,
-	poll:		coda_psdev_poll,
-	ioctl:		coda_psdev_ioctl,
-	open:		coda_psdev_open,
-	release:	coda_psdev_release,
+	.owner		= THIS_MODULE,
+	.read		= coda_psdev_read,
+	.write		= coda_psdev_write,
+	.poll		= coda_psdev_poll,
+	.ioctl		= coda_psdev_ioctl,
+	.open		= coda_psdev_open,
+	.release	= coda_psdev_release,
 };
 
 static devfs_handle_t devfs_handle;
diff -Nru a/fs/coda/symlink.c b/fs/coda/symlink.c
--- a/fs/coda/symlink.c	Fri Oct 11 21:22:54 2002
+++ b/fs/coda/symlink.c	Fri Oct 11 21:22:54 2002
@@ -51,5 +51,5 @@
 }
 
 struct address_space_operations coda_symlink_aops = {
-	readpage:	coda_symlink_filler
+	.readpage	= coda_symlink_filler,
 };
diff -Nru a/fs/coda/sysctl.c b/fs/coda/sysctl.c
--- a/fs/coda/sysctl.c	Fri Oct 11 21:22:55 2002
+++ b/fs/coda/sysctl.c	Fri Oct 11 21:22:55 2002
@@ -22,7 +22,6 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <linux/utsname.h>
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/coda.h>
@@ -39,7 +38,6 @@
 #define CODA_TIMEOUT    3       /* timeout on upcalls to become intrble */
 #define CODA_HARD       5       /* mount type "hard" or "soft" */
 #define CODA_VFS 	 6       /* vfs statistics */
-#define CODA_UPCALL 	 7       /* upcall statistics */
 #define CODA_CACHE_INV 	 9       /* cache invalidation statistics */
 #define CODA_FAKE_STATFS 10	 /* don't query venus for actual cache usage */
 
@@ -47,7 +45,6 @@
  	{CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
  	{CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec},
  	{CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
- 	{CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
  	{CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
  	{CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec},
 	{ 0 }
@@ -60,152 +57,17 @@
 
 struct coda_vfs_stats		coda_vfs_stat;
 struct coda_cache_inv_stats	coda_cache_inv_stat;
-struct coda_upcall_stats_entry  coda_upcall_stat[CODA_NCALLS];
-struct coda_upcallstats         coda_callstats;
-int                             coda_upcall_timestamping = 0;
-
-/* keep this in sync with coda.h! */
-char *coda_upcall_names[] = {
-	"totals      ",   /*  0 */
-	"-           ",   /*  1 */
-	"root        ",   /*  2 */
-	"open_by_fd  ",   /*  3 */
-	"open        ",   /*  4 */
-	"close       ",   /*  5 */
-	"ioctl       ",   /*  6 */
-	"getattr     ",   /*  7 */
-	"setattr     ",   /*  8 */
-	"access      ",   /*  9 */
-	"lookup      ",   /* 10 */
-	"create      ",   /* 11 */
-	"remove      ",   /* 12 */
-	"link        ",   /* 13 */
-	"rename      ",   /* 14 */
-	"mkdir       ",   /* 15 */
-	"rmdir       ",   /* 16 */
-	"readdir     ",   /* 17 */
-	"symlink     ",   /* 18 */
-	"readlink    ",   /* 19 */
-	"fsync       ",   /* 20 */
-	"-           ",   /* 21 */
-	"vget        ",   /* 22 */
-	"signal      ",   /* 23 */
-	"replace     ",   /* 24 */
-	"flush       ",   /* 25 */
-	"purgeuser   ",   /* 26 */
-	"zapfile     ",   /* 27 */
-	"zapdir      ",   /* 28 */
-	"-           ",   /* 29 */
-	"purgefid    ",   /* 30 */
-	"open_by_path",   /* 31 */
-	"resolve     ",   /* 32 */
-	"reintegrate ",   /* 33 */
-	"statfs      ",   /* 34 */
-	"store       ",   /* 35 */
-	"release     "    /* 36 */
-};
-
 
 void reset_coda_vfs_stats( void )
 {
 	memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
 }
 
-void reset_coda_upcall_stats( void )
-{
-	memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) );
-}
-
 void reset_coda_cache_inv_stats( void )
 {
 	memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
 }
 
-
-void do_time_stats( struct coda_upcall_stats_entry * pentry, 
-		    unsigned long runtime )
-{
-	unsigned long time = runtime;	/* time in us */
-
-	if ( pentry->count == 0 ) {
-		pentry->time_sum = pentry->time_squared_sum = 0;
-	}
-	
-	pentry->count++;
-	pentry->time_sum += time;
-	pentry->time_squared_sum += time*time;
-}
-
-
-
-void coda_upcall_stats(int opcode, long unsigned runtime) 
-{
-	struct coda_upcall_stats_entry * pentry;
-	
-	if ( opcode < 0 || opcode > CODA_NCALLS - 1) {
-		printk("Nasty opcode %d passed to coda_upcall_stats\n",
-		       opcode);
-		return;
-	}
-		
-	pentry = &coda_upcall_stat[opcode];
-	do_time_stats(pentry, runtime);
-
-        /* fill in the totals */
-	pentry = &coda_upcall_stat[0];
-	do_time_stats(pentry, runtime);
-
-}
-
-unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry )
-{
-	return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count;
-}
-
-static inline unsigned long absolute( unsigned long x )
-{
-	return x >= 0 ? x : -x;
-}
-
-static unsigned long sqr_root( unsigned long x )
-{
-	unsigned long y = x, r;
-	int n_bit = 0;
-  
-	if ( x == 0 )
-		return 0;
-	if ( x < 0)
-		x = -x;
-
-	while ( y ) {
-		y >>= 1;
-		n_bit++;
-	}
-  
-	r = 1 << (n_bit/2);
-  
-	while ( 1 ) {
-		r = (r + x/r)/2;
-		if ( r*r <= x && x < (r+1)*(r+1) )
-			break;
-	}
-  
-	return r;
-}
-
-unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry )
-{
-	unsigned long time_avg;
-  
-	if ( pentry->count <= 1 )
-		return 0;
-  
-	time_avg = get_time_average( pentry );
-
-	return sqr_root( (pentry->time_squared_sum / pentry->count) - 
-			    time_avg * time_avg );
-}
-
 int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
 			     void * buffer, size_t * lenp )
 {
@@ -220,27 +82,6 @@
 	return 0;
 }
 
-int do_reset_coda_upcall_stats( ctl_table * table, int write, 
-				struct file * filp, void * buffer, 
-				size_t * lenp )
-{
-	if ( write ) {
-        	if (*lenp > 0) {
-			char c;
-                	if (get_user(c, (char *)buffer))
-			       	return -EFAULT;
-                        coda_upcall_timestamping = (c == '1');
-                }
-		reset_coda_upcall_stats();
-
-		filp->f_pos += *lenp;
-	} else {
-		*lenp = 0;
-	}
-
-	return 0;
-}
-
 int do_reset_coda_cache_inv_stats( ctl_table * table, int write, 
 				   struct file * filp, void * buffer, 
 				   size_t * lenp )
@@ -317,52 +158,6 @@
 	return len;
 }
 
-int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
-				int length)
-{
-	int len=0;
-	int i;
-	off_t begin;
-	off_t pos = 0;
-	char tmpbuf[80];
-	int tmplen = 0;
-
-	/* this works as long as we are below 1024 characters! */
-	if ( offset < 80 ) 
-		len += sprintf( buffer,"%-79s\n",	"Coda upcall statistics");
-	if ( offset < 160) 
-		len += sprintf( buffer + len,"%-79s\n",	"======================");
-	if ( offset < 240) 
-		len += sprintf( buffer + len,"%-79s\n",	"upcall              count       avg time(us)    std deviation(us)");
-	if ( offset < 320) 
-		len += sprintf( buffer + len,"%-79s\n",	"------              -----       ------------    -----------------");
-	pos = 320; 
-	for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
-		tmplen += sprintf(tmpbuf,"%s    %9d       %10ld      %10ld", 
-				  coda_upcall_names[i],
-				  coda_upcall_stat[i].count, 
-				  get_time_average(&coda_upcall_stat[i]),
-				  coda_upcall_stat[i].time_squared_sum);
-		pos += 80;
-		if ( pos < offset ) 
-			continue; 
-		len += sprintf(buffer + len, "%-79s\n", tmpbuf);
-		if ( len >= length ) 
-			break; 
-	}
-  
-	begin = len- (pos - offset);
-	*start = buffer + begin;
-	len -= begin;
-
-	if ( len > length )
-		len = length;
-	if ( len < 0 )
-		len = 0;
-
-	return len;
-}
-
 int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
 				   int length)
 {
@@ -421,9 +216,7 @@
 
 void coda_sysctl_init()
 {
-	memset(&coda_callstats, 0, sizeof(coda_callstats));
 	reset_coda_vfs_stats();
-	reset_coda_upcall_stats();
 	reset_coda_cache_inv_stats();
 
 #ifdef CONFIG_PROC_FS
@@ -431,7 +224,6 @@
 	if (proc_fs_coda) {
 		proc_fs_coda->owner = THIS_MODULE;
 		coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
-		coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
 		coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
 	}
 #endif
@@ -454,7 +246,6 @@
 
 #if CONFIG_PROC_FS
         remove_proc_entry("cache_inv_stats", proc_fs_coda);
-        remove_proc_entry("upcall_stats", proc_fs_coda);
         remove_proc_entry("vfs_stats", proc_fs_coda);
 	remove_proc_entry("coda", proc_root_fs);
 #endif 
diff -Nru a/fs/coda/upcall.c b/fs/coda/upcall.c
--- a/fs/coda/upcall.c	Fri Oct 11 21:23:03 2002
+++ b/fs/coda/upcall.c	Fri Oct 11 21:23:03 2002
@@ -171,10 +171,7 @@
 	insize = SIZE(store);
 	UPARG(CODA_STORE);
 	
-	if ( cred ) {
-		memcpy(&(inp->ih.cred), cred, sizeof(*cred));
-	} else 
-		printk("CODA: store without valid file creds.\n");
+	memcpy(&(inp->ih.cred), cred, sizeof(*cred));
 	
         inp->coda_store.VFid = *fid;
         inp->coda_store.flags = flags;
@@ -213,10 +210,7 @@
 	insize = SIZE(release);
 	UPARG(CODA_CLOSE);
 	
-	if ( cred ) {
-		memcpy(&(inp->ih.cred), cred, sizeof(*cred));
-	} else 
-		printk("CODA: close without valid file creds.\n");
+	memcpy(&(inp->ih.cred), cred, sizeof(*cred));
 	
         inp->coda_close.VFid = *fid;
         inp->coda_close.flags = flags;
@@ -620,17 +614,13 @@
  * 
  */
 
-static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
-						struct venus_comm *vcommp)
+static inline void coda_waitfor_upcall(struct upc_req *vmp,
+				       struct venus_comm *vcommp)
 {
 	DECLARE_WAITQUEUE(wait, current);
- 	struct timeval begin = { 0, 0 }, end = { 0, 0 };
 
 	vmp->uc_posttime = jiffies;
 
-	if (coda_upcall_timestamping)
-		do_gettimeofday(&begin);
-
 	add_wait_queue(&vmp->uc_sleep, &wait);
 	for (;;) {
 		if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 
@@ -661,17 +651,7 @@
 	remove_wait_queue(&vmp->uc_sleep, &wait);
 	set_current_state(TASK_RUNNING);
 
-	if (coda_upcall_timestamping && begin.tv_sec != 0) {
-		do_gettimeofday(&end);
-
-		if (end.tv_usec < begin.tv_usec) {
-			end.tv_usec += 1000000; end.tv_sec--;
-		}
-		end.tv_sec  -= begin.tv_sec;
-		end.tv_usec -= begin.tv_usec;
-	}
-
-	return 	((end.tv_sec * 1000000) + end.tv_usec);
+	return;
 }
 
 
@@ -689,7 +669,6 @@
 		int inSize, int *outSize, 
 		union inputArgs *buffer) 
 {
-	unsigned long runtime; 
 	struct venus_comm *vcommp;
 	union outputArgs *out;
 	struct upc_req *req;
@@ -732,8 +711,7 @@
 	 * ENODEV.  */
 
 	/* Go to sleep.  Wake up on signals only after the timeout. */
-	runtime = coda_waitfor_upcall(req, vcommp);
-	coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
+	coda_waitfor_upcall(req, vcommp);
 
 	if (vcommp->vc_inuse) {      /* i.e. Venus is still alive */
 	    /* Op went through, interrupt or not... */
@@ -794,8 +772,6 @@
 
  exit:
 	upc_free(req);
-	if (error) 
-	        badclstats();
 	return error;
 }
 
@@ -842,7 +818,6 @@
 	  switch (opcode) {
 
 	  case CODA_FLUSH : {
-	           clstats(CODA_FLUSH);
 		   coda_cache_clear_all(sb, NULL);
 		   shrink_dcache_sb(sb);
 		   coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
@@ -855,7 +830,6 @@
 		           printk("PURGEUSER: null cred!\n");
 			   return 0;
 		   }
-		   clstats(CODA_PURGEUSER);
 		   coda_cache_clear_all(sb, cred);
 		   return(0);
 	  }
@@ -863,7 +837,6 @@
 	  case CODA_ZAPDIR : {
 	          struct inode *inode;
 		  ViceFid *fid = &out->coda_zapdir.CodaFid;
-		  clstats(CODA_ZAPDIR);
 
 		  inode = coda_fid_to_inode(fid, sb);
 		  if (inode) {
@@ -878,7 +851,6 @@
 	  case CODA_ZAPFILE : {
 	          struct inode *inode;
 		  struct ViceFid *fid = &out->coda_zapfile.CodaFid;
-		  clstats(CODA_ZAPFILE);
 		  inode = coda_fid_to_inode(fid, sb);
 		  if ( inode ) {
 	                  coda_flag_inode(inode, C_VATTR);
@@ -890,7 +862,6 @@
 	  case CODA_PURGEFID : {
 	          struct inode *inode;
 		  ViceFid *fid = &out->coda_purgefid.CodaFid;
-		  clstats(CODA_PURGEFID);
 		  inode = coda_fid_to_inode(fid, sb);
 		  if ( inode ) { 
 			coda_flag_inode_children(inode, C_PURGE);
@@ -908,7 +879,6 @@
 	          struct inode *inode;
 		  ViceFid *oldfid = &out->coda_replace.OldFid;
 		  ViceFid *newfid = &out->coda_replace.NewFid;
-		  clstats(CODA_REPLACE);
 		  inode = coda_fid_to_inode(oldfid, sb);
 		  if ( inode ) { 
 			  coda_replace_fid(inode, oldfid, newfid);
diff -Nru a/fs/cramfs/inode.c b/fs/cramfs/inode.c
--- a/fs/cramfs/inode.c	Fri Oct 11 21:22:51 2002
+++ b/fs/cramfs/inode.c	Fri Oct 11 21:22:51 2002
@@ -181,8 +181,8 @@
 
 static void cramfs_put_super(struct super_block *sb)
 {
-	kfree(sb->u.generic_sbp);
-	sb->u.generic_sbp = NULL;
+	kfree(sb->s_fs_info);
+	sb->s_fs_info = NULL;
 }
 
 static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
@@ -195,7 +195,7 @@
 	sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct cramfs_sb_info));
 
 	sb_set_blocksize(sb, PAGE_CACHE_SIZE);
@@ -258,7 +258,7 @@
 	return 0;
 out:
 	kfree(sbi);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	return -EINVAL;
 }
 
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Fri Oct 11 21:22:54 2002
+++ b/fs/dcache.c	Fri Oct 11 21:22:54 2002
@@ -51,7 +51,9 @@
 static LIST_HEAD(dentry_unused);
 
 /* Statistics gathering. */
-struct dentry_stat_t dentry_stat = {0, 0, 45, 0,};
+struct dentry_stat_t dentry_stat = {
+	.age_limit = 45,
+};
 
 /* no dcache_lock, please */
 static inline void d_free(struct dentry *dentry)
@@ -1352,7 +1354,7 @@
 			__get_free_pages(GFP_ATOMIC, order);
 	} while (dentry_hashtable == NULL && --order >= 0);
 
-	printk("Dentry-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+	printk(KERN_INFO "Dentry cache hash table entries: %d (order: %ld, %ld bytes)\n",
 			nr_hash, order, (PAGE_SIZE << order));
 
 	if (!dentry_hashtable)
diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c
--- a/fs/devfs/base.c	Fri Oct 11 21:22:54 2002
+++ b/fs/devfs/base.c	Fri Oct 11 21:22:54 2002
@@ -2483,7 +2483,7 @@
     int retval;
     struct devfs_entry *de;
     struct inode *inode = dentry->d_inode;
-    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = inode->i_sb->s_fs_info;
 
     de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENODEV;
@@ -2630,7 +2630,7 @@
     struct devfs_entry *parent, *de, *next = NULL;
     struct inode *inode = file->f_dentry->d_inode;
 
-    fs_info = inode->i_sb->u.generic_sbp;
+    fs_info = inode->i_sb->s_fs_info;
     parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode);
     if ( (long) file->f_pos < 0 ) return -EINVAL;
     DPRINTK (DEBUG_F_READDIR, "(%s): fs_info: %p  pos: %ld\n",
@@ -2694,7 +2694,7 @@
     int err;
     struct fcb_type *df;
     struct devfs_entry *de;
-    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = inode->i_sb->s_fs_info;
     void *ops;
 
     de = get_devfs_entry_from_vfs_inode (inode);
@@ -2825,7 +2825,7 @@
 	DPRINTK (DEBUG_D_DELETE, "(%p): dropping negative dentry\n", dentry);
 	return 1;
     }
-    fs_info = inode->i_sb->u.generic_sbp;
+    fs_info = inode->i_sb->s_fs_info;
     de = get_devfs_entry_from_vfs_inode (inode);
     DPRINTK (DEBUG_D_DELETE, "(%p): inode: %p  devfs_entry: %p\n",
 	     dentry, inode, de);
@@ -2854,7 +2854,7 @@
 static int devfs_d_revalidate_wait (struct dentry *dentry, int flags)
 {
     struct inode *dir = dentry->d_parent->d_inode;
-    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = dir->i_sb->s_fs_info;
     devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir);
     struct devfs_lookup_struct *lookup_info = dentry->d_fsdata;
     DECLARE_WAITQUEUE (wait, current);
@@ -2907,7 +2907,7 @@
 {
     struct devfs_entry tmp;  /*  Must stay in scope until devfsd idle again  */
     struct devfs_lookup_struct lookup_info;
-    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = dir->i_sb->s_fs_info;
     struct devfs_entry *parent, *de;
     struct inode *inode;
     struct dentry *retval = NULL;
@@ -2996,7 +2996,7 @@
     int unhooked;
     struct devfs_entry *de;
     struct inode *inode = dentry->d_inode;
-    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = dir->i_sb->s_fs_info;
 
     de = get_devfs_entry_from_vfs_inode (inode);
     DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de);
@@ -3018,7 +3018,7 @@
 			  const char *symname)
 {
     int err;
-    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = dir->i_sb->s_fs_info;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
@@ -3050,7 +3050,7 @@
 static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
 {
     int err;
-    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = dir->i_sb->s_fs_info;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
@@ -3082,10 +3082,10 @@
 {
     int err = 0;
     struct devfs_entry *de;
-    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = dir->i_sb->s_fs_info;
     struct inode *inode = dentry->d_inode;
 
-    if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL;
+    if (dir->i_sb->s_fs_info != inode->i_sb->s_fs_info) return -EINVAL;
     de = get_devfs_entry_from_vfs_inode (inode);
     if (de == NULL) return -ENOENT;
     if ( !S_ISDIR (de->mode) ) return -ENOTDIR;
@@ -3113,7 +3113,7 @@
 			int rdev)
 {
     int err;
-    struct fs_info *fs_info = dir->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = dir->i_sb->s_fs_info;
     struct devfs_entry *parent, *de;
     struct inode *inode;
 
@@ -3201,7 +3201,7 @@
     init_waitqueue_head (&fs_info.devfsd_wait_queue);
     init_waitqueue_head (&fs_info.revalidate_wait_queue);
     fs_info.sb = sb;
-    sb->u.generic_sbp = &fs_info;
+    sb->s_fs_info = &fs_info;
     sb->s_blocksize = 1024;
     sb->s_blocksize_bits = 10;
     sb->s_magic = DEVFS_SUPER_MAGIC;
@@ -3210,7 +3210,7 @@
 	goto out_no_root;
     sb->s_root = d_alloc_root (root_inode);
     if (!sb->s_root) goto out_no_root;
-    DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->u.generic_sbp);
+    DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->s_fs_info);
     return 0;
 
 out_no_root:
@@ -3242,7 +3242,7 @@
     loff_t pos, devname_offset, tlen, rpos;
     devfs_handle_t de;
     struct devfsd_buf_entry *entry;
-    struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->s_fs_info;
     struct devfsd_notify_struct *info = fs_info->devfsd_info;
     DECLARE_WAITQUEUE (wait, current);
 
@@ -3343,7 +3343,7 @@
 			 unsigned int cmd, unsigned long arg)
 {
     int ival;
-    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = inode->i_sb->s_fs_info;
 
     switch (cmd)
     {
@@ -3400,7 +3400,7 @@
 static int devfsd_close (struct inode *inode, struct file *file)
 {
     struct devfsd_buf_entry *entry, *next;
-    struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
+    struct fs_info *fs_info = inode->i_sb->s_fs_info;
 
     if (fs_info->devfsd_file != file) return 0;
     fs_info->devfsd_event_mask = 0;
diff -Nru a/fs/dnotify.c b/fs/dnotify.c
--- a/fs/dnotify.c	Fri Oct 11 21:22:55 2002
+++ b/fs/dnotify.c	Fri Oct 11 21:22:55 2002
@@ -144,7 +144,7 @@
 
 static int __init dnotify_init(void)
 {
-	dn_cache = kmem_cache_create("dnotify cache",
+	dn_cache = kmem_cache_create("dnotify_cache",
 		sizeof(struct dnotify_struct), 0, 0, NULL, NULL);
 	if (!dn_cache)
 		panic("cannot create dnotify slab cache");
diff -Nru a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c	Fri Oct 11 21:23:01 2002
+++ b/fs/dquot.c	Fri Oct 11 21:23:01 2002
@@ -190,8 +190,7 @@
 
 static inline void remove_dquot_hash(struct dquot *dquot)
 {
-	list_del(&dquot->dq_hash);
-	INIT_LIST_HEAD(&dquot->dq_hash);
+	list_del_init(&dquot->dq_hash);
 }
 
 static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type)
@@ -232,8 +231,7 @@
 {
 	if (list_empty(&dquot->dq_free))
 		return;
-	list_del(&dquot->dq_free);
-	INIT_LIST_HEAD(&dquot->dq_free);
+	list_del_init(&dquot->dq_free);
 	dqstats.free_dquots--;
 }
 
@@ -729,8 +727,7 @@
 	while (act_head != tofree_head) {
 		dquot = list_entry(act_head, struct dquot, dq_free);
 		act_head = act_head->next;
-		list_del(&dquot->dq_free);	/* Remove dquot from the list so we won't have problems... */
-		INIT_LIST_HEAD(&dquot->dq_free);
+		list_del_init(&dquot->dq_free);	/* Remove dquot from the list so we won't have problems... */
 		dqput(dquot);
 	}
 	unlock_kernel();
diff -Nru a/fs/efs/inode.c b/fs/efs/inode.c
--- a/fs/efs/inode.c	Fri Oct 11 21:22:55 2002
+++ b/fs/efs/inode.c	Fri Oct 11 21:22:55 2002
@@ -19,7 +19,7 @@
 {
 	return block_read_full_page(page,efs_get_block);
 }
-static int _efs_bmap(struct address_space *mapping, long block)
+static sector_t _efs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,efs_get_block);
 }
diff -Nru a/fs/efs/super.c b/fs/efs/super.c
--- a/fs/efs/super.c	Fri Oct 11 21:22:55 2002
+++ b/fs/efs/super.c	Fri Oct 11 21:22:55 2002
@@ -72,8 +72,8 @@
 
 void efs_put_super(struct super_block *s)
 {
-	kfree(s->u.generic_sbp);
-	s->u.generic_sbp = NULL;
+	kfree(s->s_fs_info);
+	s->s_fs_info = NULL;
 }
 
 static struct super_operations efs_superblock_operations = {
@@ -213,7 +213,7 @@
  	sb = kmalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
 	if (!sb)
 		return -ENOMEM;
-	s->u.generic_sbp = sb;
+	s->s_fs_info = sb;
 	memset(sb, 0, sizeof(struct efs_sb_info));
  
 	s->s_magic		= EFS_SUPER_MAGIC;
@@ -272,7 +272,7 @@
 
 out_no_fs_ul:
 out_no_fs:
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	kfree(sb);
 	return -EINVAL;
 }
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Fri Oct 11 21:22:55 2002
+++ b/fs/exec.c	Fri Oct 11 21:22:55 2002
@@ -131,7 +131,7 @@
 		goto out;
 
 	error = -ENOEXEC;
-	if(file->f_op && file->f_op->read) {
+	if(file->f_op) {
 		struct linux_binfmt * fmt;
 
 		read_lock(&binfmt_lock);
@@ -453,19 +453,16 @@
 }
 
 int kernel_read(struct file *file, unsigned long offset,
-	char * addr, unsigned long count)
+	char *addr, unsigned long count)
 {
 	mm_segment_t old_fs;
 	loff_t pos = offset;
-	int result = -ENOSYS;
+	int result;
 
-	if (!file->f_op->read)
-		goto fail;
 	old_fs = get_fs();
 	set_fs(get_ds());
-	result = file->f_op->read(file, addr, count, &pos);
+	result = vfs_read(file, addr, count, &pos);
 	set_fs(old_fs);
-fail:
 	return result;
 }
 
diff -Nru a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
--- a/fs/exportfs/expfs.c	Fri Oct 11 21:22:55 2002
+++ b/fs/exportfs/expfs.c	Fri Oct 11 21:22:55 2002
@@ -183,12 +183,12 @@
 			err = CALL(nops,get_name)(ppd, nbuf, pd);
 			if (err) {
 				dput(ppd);
+				dput(pd);
 				if (err == -ENOENT)
 					/* some race between get_parent and
 					 * get_name?  just try again
 					 */
 					continue;
-				dput(pd);
 				break;
 			}
 			dprintk("find_exported_dentry: found name: %s\n", nbuf);
@@ -254,6 +254,7 @@
 		return result;
 	/* one last try of the aliases.. */
 	spin_lock(&dcache_lock);
+	toput = NULL;
 	head = &result->d_inode->i_dentry;
 	list_for_each(le, head) {
 		struct dentry *dentry = list_entry(le, struct dentry, d_alias);
diff -Nru a/fs/ext2/file.c b/fs/ext2/file.c
--- a/fs/ext2/file.c	Fri Oct 11 21:22:55 2002
+++ b/fs/ext2/file.c	Fri Oct 11 21:22:55 2002
@@ -41,6 +41,8 @@
 	.llseek		= generic_file_llseek,
 	.read		= generic_file_read,
 	.write		= generic_file_write,
+	.aio_read	= generic_file_aio_read,
+	.aio_write	= generic_file_aio_write,
 	.ioctl		= ext2_ioctl,
 	.mmap		= generic_file_mmap,
 	.open		= generic_file_open,
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Fri Oct 11 21:22:52 2002
+++ b/fs/ext2/inode.c	Fri Oct 11 21:22:52 2002
@@ -601,7 +601,7 @@
 	return block_prepare_write(page,from,to,ext2_get_block);
 }
 
-static int ext2_bmap(struct address_space *mapping, long block)
+static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,ext2_get_block);
 }
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
--- a/fs/ext2/super.c	Fri Oct 11 21:23:00 2002
+++ b/fs/ext2/super.c	Fri Oct 11 21:23:00 2002
@@ -143,7 +143,7 @@
 			brelse (sbi->s_group_desc[i]);
 	kfree(sbi->s_group_desc);
 	brelse (sbi->s_sbh);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(sbi);
 
 	return;
@@ -475,7 +475,7 @@
 	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(*sbi));
 
 	/*
@@ -710,7 +710,7 @@
 failed_mount:
 	brelse(bh);
 failed_sbi:
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(sbi);
 	return -EINVAL;
 }
diff -Nru a/fs/ext3/Makefile b/fs/ext3/Makefile
--- a/fs/ext3/Makefile	Fri Oct 11 21:22:53 2002
+++ b/fs/ext3/Makefile	Fri Oct 11 21:22:53 2002
@@ -5,6 +5,6 @@
 obj-$(CONFIG_EXT3_FS) += ext3.o
 
 ext3-objs    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
-		ioctl.o namei.o super.o symlink.o
+		ioctl.o namei.o super.o symlink.o hash.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c
--- a/fs/ext3/dir.c	Fri Oct 11 21:22:59 2002
+++ b/fs/ext3/dir.c	Fri Oct 11 21:22:59 2002
@@ -23,12 +23,16 @@
 #include <linux/ext3_fs.h>
 #include <linux/buffer_head.h>
 #include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
 
 static unsigned char ext3_filetype_table[] = {
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
 
 static int ext3_readdir(struct file *, void *, filldir_t);
+static int ext3_dx_readdir(struct file * filp,
+			   void * dirent, filldir_t filldir);
 
 struct file_operations ext3_dir_operations = {
 	.read		= generic_read_dir,
@@ -37,6 +41,17 @@
 	.fsync		= ext3_sync_file,		/* BKL held */
 };
 
+
+static unsigned char get_dtype(struct super_block *sb, int filetype)
+{
+	if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE) ||
+	    (filetype >= EXT3_FT_MAX))
+		return DT_UNKNOWN;
+
+	return (ext3_filetype_table[filetype]);
+}
+			       
+
 int ext3_check_dir_entry (const char * function, struct inode * dir,
 			  struct ext3_dir_entry_2 * de,
 			  struct buffer_head * bh,
@@ -83,6 +98,16 @@
 
 	sb = inode->i_sb;
 
+	if (is_dx(inode)) {
+		err = ext3_dx_readdir(filp, dirent, filldir);
+		if (err != ERR_BAD_DX_DIR)
+			return err;
+		/*
+		 * We don't set the inode dirty flag since it's not
+		 * critical that it get flushed back to the disk.
+		 */
+		EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL;
+	}
 	stored = 0;
 	bh = NULL;
 	offset = filp->f_pos & (sb->s_blocksize - 1);
@@ -167,18 +192,12 @@
 				 * during the copy operation.
 				 */
 				unsigned long version = filp->f_version;
-				unsigned char d_type = DT_UNKNOWN;
 
-				if (EXT3_HAS_INCOMPAT_FEATURE(sb,
-						EXT3_FEATURE_INCOMPAT_FILETYPE)
-						&& de->file_type < EXT3_FT_MAX)
-					d_type =
-					  ext3_filetype_table[de->file_type];
 				error = filldir(dirent, de->name,
 						de->name_len,
 						filp->f_pos,
 						le32_to_cpu(de->inode),
-						d_type);
+						get_dtype(sb, de->file_type));
 				if (error)
 					break;
 				if (version != filp->f_version)
@@ -194,3 +213,269 @@
 	unlock_kernel();
 	return 0;
 }
+
+#ifdef CONFIG_EXT3_INDEX
+/*
+ * These functions convert from the major/minor hash to an f_pos
+ * value.
+ * 
+ * Currently we only use major hash numer.  This is unfortunate, but
+ * on 32-bit machines, the same VFS interface is used for lseek and
+ * llseek, so if we use the 64 bit offset, then the 32-bit versions of
+ * lseek/telldir/seekdir will blow out spectacularly, and from within
+ * the ext2 low-level routine, we don't know if we're being called by
+ * a 64-bit version of the system call or the 32-bit version of the
+ * system call.  Worse yet, NFSv2 only allows for a 32-bit readdir
+ * cookie.  Sigh.
+ */
+#define hash2pos(major, minor)	(major >> 1)
+#define pos2maj_hash(pos)	((pos << 1) & 0xffffffff)
+#define pos2min_hash(pos)	(0)
+
+/*
+ * This structure holds the nodes of the red-black tree used to store
+ * the directory entry in hash order.
+ */
+struct fname {
+	__u32		hash;
+	__u32		minor_hash;
+	struct rb_node	rb_hash; 
+	struct fname	*next;
+	__u32		inode;
+	__u8		name_len;
+	__u8		file_type;
+	char		name[0];
+};
+
+/*
+ * This functoin implements a non-recursive way of freeing all of the
+ * nodes in the red-black tree.
+ */
+static void free_rb_tree_fname(struct rb_root *root)
+{
+	struct rb_node	*n = root->rb_node;
+	struct rb_node	*parent;
+	struct fname	*fname;
+
+	while (n) {
+		/* Do the node's children first */
+		if ((n)->rb_left) {
+			n = n->rb_left;
+			continue;
+		}
+		if (n->rb_right) {
+			n = n->rb_right;
+			continue;
+		}
+		/*
+		 * The node has no children; free it, and then zero
+		 * out parent's link to it.  Finally go to the
+		 * beginning of the loop and try to free the parent
+		 * node.
+		 */
+		parent = n->rb_parent;
+		fname = rb_entry(n, struct fname, rb_hash);
+		kfree(fname);
+		if (!parent)
+			root->rb_node = 0;
+		else if (parent->rb_left == n)
+			parent->rb_left = 0;
+		else if (parent->rb_right == n)
+			parent->rb_right = 0;
+		n = parent;
+	}
+	root->rb_node = 0;
+}
+
+
+struct dir_private_info *create_dir_info(loff_t pos)
+{
+	struct dir_private_info *p;
+
+	p = kmalloc(sizeof(struct dir_private_info), GFP_KERNEL);
+	if (!p)
+		return NULL;
+	p->root.rb_node = 0;
+	p->curr_node = 0;
+	p->extra_fname = 0;
+	p->last_pos = 0;
+	p->curr_hash = pos2maj_hash(pos);
+	p->curr_minor_hash = pos2min_hash(pos);
+	p->next_hash = 0;
+	return p;
+}
+
+void ext3_htree_free_dir_info(struct dir_private_info *p)
+{
+	free_rb_tree_fname(&p->root);
+	kfree(p);
+}
+		
+/*
+ * Given a directory entry, enter it into the fname rb tree.
+ */
+void ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
+			     __u32 minor_hash,
+			     struct ext3_dir_entry_2 *dirent)
+{
+	struct rb_node **p, *parent = NULL;
+	struct fname * fname, *new_fn;
+	struct dir_private_info *info;
+	int len;
+
+	info = (struct dir_private_info *) dir_file->private_data;
+	p = &info->root.rb_node;
+
+	/* Create and allocate the fname structure */
+	len = sizeof(struct fname) + dirent->name_len + 1;
+	new_fn = kmalloc(len, GFP_KERNEL);
+	memset(new_fn, 0, len);
+	new_fn->hash = hash;
+	new_fn->minor_hash = minor_hash;
+	new_fn->inode = le32_to_cpu(dirent->inode);
+	new_fn->name_len = dirent->name_len;
+	new_fn->file_type = dirent->file_type;
+	memcpy(new_fn->name, dirent->name, dirent->name_len);
+	new_fn->name[dirent->name_len] = 0;
+	
+	while (*p) {
+		parent = *p;
+		fname = rb_entry(parent, struct fname, rb_hash);
+
+		/*
+		 * If the hash and minor hash match up, then we put
+		 * them on a linked list.  This rarely happens...
+		 */
+		if ((new_fn->hash == fname->hash) &&
+		    (new_fn->minor_hash == fname->minor_hash)) {
+			new_fn->next = fname->next;
+			fname->next = new_fn;
+			return;
+		}
+			
+		if (new_fn->hash < fname->hash)
+			p = &(*p)->rb_left;
+		else if (new_fn->hash > fname->hash)
+			p = &(*p)->rb_right;
+		else if (new_fn->minor_hash < fname->minor_hash)
+			p = &(*p)->rb_left;
+		else /* if (new_fn->minor_hash > fname->minor_hash) */
+			p = &(*p)->rb_right;
+	}
+
+	rb_link_node(&new_fn->rb_hash, parent, p);
+	rb_insert_color(&new_fn->rb_hash, &info->root);
+}
+
+
+
+/*
+ * This is a helper function for ext3_dx_readdir.  It calls filldir
+ * for all entres on the fname linked list.  (Normally there is only
+ * one entry on the linked list, unless there are 62 bit hash collisions.)
+ */
+static int call_filldir(struct file * filp, void * dirent,
+			filldir_t filldir, struct fname *fname)
+{
+	struct dir_private_info *info = filp->private_data;
+	loff_t	curr_pos;
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct super_block * sb;
+	int error;
+
+	sb = inode->i_sb;
+	
+	if (!fname) {
+		printk("call_filldir: called with null fname?!?\n");
+		return 0;
+	}
+	curr_pos = hash2pos(fname->hash, fname->minor_hash);
+	while (fname) {
+		error = filldir(dirent, fname->name,
+				fname->name_len, curr_pos, 
+				fname->inode,
+				get_dtype(sb, fname->file_type));
+		if (error) {
+			filp->f_pos = curr_pos;
+			info->extra_fname = fname->next;
+			return error;
+		}
+		fname = fname->next;
+	}
+	return 0;
+}
+
+static int ext3_dx_readdir(struct file * filp,
+			 void * dirent, filldir_t filldir)
+{
+	struct dir_private_info *info = filp->private_data;
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct fname *fname;
+	int	ret;
+
+	if (!info) {
+		info = create_dir_info(filp->f_pos);
+		if (!info)
+			return -ENOMEM;
+		filp->private_data = info;
+	}
+
+	/* Some one has messed with f_pos; reset the world */
+	if (info->last_pos != filp->f_pos) {
+		free_rb_tree_fname(&info->root);
+		info->curr_node = 0;
+		info->extra_fname = 0;
+		info->curr_hash = pos2maj_hash(filp->f_pos);
+		info->curr_minor_hash = pos2min_hash(filp->f_pos);
+	}
+
+	/*
+	 * If there are any leftover names on the hash collision
+	 * chain, return them first.
+	 */
+	if (info->extra_fname &&
+	    call_filldir(filp, dirent, filldir, info->extra_fname))
+		goto finished;
+
+	if (!info->curr_node)
+		info->curr_node = rb_first(&info->root);
+
+	while (1) {
+		/*
+		 * Fill the rbtree if we have no more entries,
+		 * or the inode has changed since we last read in the
+		 * cached entries. 
+		 */
+		if ((!info->curr_node) ||
+		    (filp->f_version != inode->i_version)) {
+			info->curr_node = 0;
+			free_rb_tree_fname(&info->root);
+			filp->f_version = inode->i_version;
+			ret = ext3_htree_fill_tree(filp, info->curr_hash,
+						   info->curr_minor_hash,
+						   &info->next_hash);
+			if (ret < 0)
+				return ret;
+			if (ret == 0)
+				break;
+			info->curr_node = rb_first(&info->root);
+		}
+
+		fname = rb_entry(info->curr_node, struct fname, rb_hash);
+		info->curr_hash = fname->hash;
+		info->curr_minor_hash = fname->minor_hash;
+		if (call_filldir(filp, dirent, filldir, fname))
+			break;
+
+		info->curr_node = rb_next(info->curr_node);
+		if (!info->curr_node) {
+			info->curr_hash = info->next_hash;
+			info->curr_minor_hash = 0;
+		}
+	}
+finished:
+	info->last_pos = filp->f_pos;
+	UPDATE_ATIME(inode);
+	return 0;
+}
+#endif
diff -Nru a/fs/ext3/file.c b/fs/ext3/file.c
--- a/fs/ext3/file.c	Fri Oct 11 21:23:04 2002
+++ b/fs/ext3/file.c	Fri Oct 11 21:23:04 2002
@@ -34,6 +34,9 @@
 {
 	if (filp->f_mode & FMODE_WRITE)
 		ext3_discard_prealloc (inode);
+	if (is_dx(inode) && filp->private_data)
+		ext3_htree_free_dir_info(filp->private_data);
+
 	return 0;
 }
 
@@ -58,8 +61,9 @@
  */
 
 static ssize_t
-ext3_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+ext3_file_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos)
 {
+	struct file *file = iocb->ki_filp;
 	struct inode *inode = file->f_dentry->d_inode;
 
 	/*
@@ -72,13 +76,15 @@
 	if (IS_SYNC(inode) || (file->f_flags & O_SYNC))
 		mark_inode_dirty(inode);
 
-	return generic_file_write(file, buf, count, ppos);
+	return generic_file_aio_write(iocb, buf, count, pos);
 }
 
 struct file_operations ext3_file_operations = {
 	.llseek		= generic_file_llseek,
-	.read		= generic_file_read,
-	.write		= ext3_file_write,
+	.read		= do_sync_read,
+	.write		= do_sync_write,
+	.aio_read		= generic_file_aio_read,
+	.aio_write		= ext3_file_write,
 	.readv		= generic_file_readv,
 	.writev		= generic_file_writev,
 	.ioctl		= ext3_ioctl,
diff -Nru a/fs/ext3/hash.c b/fs/ext3/hash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/ext3/hash.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,215 @@
+/*
+ *  linux/fs/ext3/hash.c
+ *
+ * Copyright (C) 2002 by Theodore Ts'o
+ *
+ * This file is released under the GPL v2.
+ * 
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ */
+
+#include <linux/fs.h>
+#include <linux/jbd.h>
+#include <linux/sched.h>
+#include <linux/ext3_fs.h>
+
+#define DELTA 0x9E3779B9
+
+static void TEA_transform(__u32 buf[4], __u32 const in[])
+{
+	__u32	sum = 0;
+	__u32	b0 = buf[0], b1 = buf[1];
+	__u32	a = in[0], b = in[1], c = in[2], d = in[3];
+	int	n = 16;
+
+	do {							
+		sum += DELTA;					
+		b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);	
+		b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);	
+	} while(--n);
+
+	buf[0] += b0;
+	buf[1] += b1;
+}
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function.  The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s)	\
+	(a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform.  Returns only 32 bits of result.
+ */
+static void halfMD4Transform (__u32 buf[4], __u32 const in[])
+{
+	__u32	a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+	/* Round 1 */
+	ROUND(F, a, b, c, d, in[0] + K1,  3);
+	ROUND(F, d, a, b, c, in[1] + K1,  7);
+	ROUND(F, c, d, a, b, in[2] + K1, 11);
+	ROUND(F, b, c, d, a, in[3] + K1, 19);
+	ROUND(F, a, b, c, d, in[4] + K1,  3);
+	ROUND(F, d, a, b, c, in[5] + K1,  7);
+	ROUND(F, c, d, a, b, in[6] + K1, 11);
+	ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+	/* Round 2 */
+	ROUND(G, a, b, c, d, in[1] + K2,  3);
+	ROUND(G, d, a, b, c, in[3] + K2,  5);
+	ROUND(G, c, d, a, b, in[5] + K2,  9);
+	ROUND(G, b, c, d, a, in[7] + K2, 13);
+	ROUND(G, a, b, c, d, in[0] + K2,  3);
+	ROUND(G, d, a, b, c, in[2] + K2,  5);
+	ROUND(G, c, d, a, b, in[4] + K2,  9);
+	ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+	/* Round 3 */
+	ROUND(H, a, b, c, d, in[3] + K3,  3);
+	ROUND(H, d, a, b, c, in[7] + K3,  9);
+	ROUND(H, c, d, a, b, in[2] + K3, 11);
+	ROUND(H, b, c, d, a, in[6] + K3, 15);
+	ROUND(H, a, b, c, d, in[1] + K3,  3);
+	ROUND(H, d, a, b, c, in[5] + K3,  9);
+	ROUND(H, c, d, a, b, in[0] + K3, 11);
+	ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#undef ROUND
+#undef F
+#undef G
+#undef H
+#undef K1
+#undef K2
+#undef K3
+
+/* The old legacy hash */
+static __u32 dx_hack_hash (const char *name, int len)
+{
+	__u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+	while (len--) {
+		__u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
+		
+		if (hash & 0x80000000) hash -= 0x7fffffff;
+		hash1 = hash0;
+		hash0 = hash;
+	}
+	return (hash0 << 1);
+}
+
+static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
+{
+	__u32	pad, val;
+	int	i;
+
+	pad = (__u32)len | ((__u32)len << 8);
+	pad |= pad << 16;
+
+	val = pad;
+	if (len > num*4)
+		len = num * 4;
+	for (i=0; i < len; i++) {
+		if ((i % 4) == 0)
+			val = pad;
+		val = msg[i] + (val << 8);
+		if ((i % 4) == 3) {
+			*buf++ = val;
+			val = pad;
+			num--;
+		}
+	}
+	if (--num >= 0)
+		*buf++ = val;
+	while (--num >= 0)
+		*buf++ = pad;
+}
+
+/*
+ * Returns the hash of a filename.  If len is 0 and name is NULL, then
+ * this function can be used to test whether or not a hash version is
+ * supported.
+ * 
+ * The seed is an 4 longword (32 bits) "secret" which can be used to
+ * uniquify a hash.  If the seed is all zero's, then some default seed
+ * may be used.
+ * 
+ * A particular hash version specifies whether or not the seed is
+ * represented, and whether or not the returned hash is 32 bits or 64
+ * bits.  32 bit hashes will return 0 for the minor hash.
+ */
+int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
+{
+	__u32	hash;
+	__u32	minor_hash = 0;
+	const char	*p;
+	int		i;
+	__u32 		in[8], buf[4];
+
+	/* Initialize the default seed for the hash checksum functions */
+	buf[0] = 0x67452301;
+	buf[1] = 0xefcdab89;
+	buf[2] = 0x98badcfe;
+	buf[3] = 0x10325476;
+
+	/* Check to see if the seed is all zero's */
+	if (hinfo->seed) {
+		for (i=0; i < 4; i++) {
+			if (hinfo->seed[i])
+				break;
+		}
+		if (i < 4)
+			memcpy(buf, hinfo->seed, sizeof(buf));
+	}
+		
+	switch (hinfo->hash_version) {
+	case DX_HASH_LEGACY:
+		hash = dx_hack_hash(name, len);
+		break;
+	case DX_HASH_HALF_MD4:
+		p = name;
+		while (len > 0) {
+			str2hashbuf(p, len, in, 8);
+			halfMD4Transform(buf, in);
+			len -= 32;
+			p += 32;
+		}
+		minor_hash = buf[2];
+		hash = buf[1];
+		break;
+	case DX_HASH_TEA:
+		p = name;
+		while (len > 0) {
+			str2hashbuf(p, len, in, 4);
+			TEA_transform(buf, in);
+			len -= 16;
+			p += 16;
+		}
+		hash = buf[0];
+		minor_hash = buf[1];
+		break;
+	default:
+		hinfo->hash = 0;
+		return -1;
+	}
+	hinfo->hash = hash & ~1;
+	hinfo->minor_hash = minor_hash;
+	return 0;
+}
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
--- a/fs/ext3/ialloc.c	Fri Oct 11 21:22:58 2002
+++ b/fs/ext3/ialloc.c	Fri Oct 11 21:22:58 2002
@@ -479,9 +479,10 @@
 			!(inode = iget(sb, ino)) || is_bad_inode(inode) ||
 			NEXT_ORPHAN(inode) > max_ino) {
 		ext3_warning(sb, __FUNCTION__,
-			     "bad orphan inode %ld!  e2fsck was run?\n", ino);
-		printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%ld) = %d\n",
-			bit, bitmap_bh->b_blocknr,
+			     "bad orphan inode %lu!  e2fsck was run?\n", (unsigned long)ino);
+		printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
+		       bit, 
+			(unsigned long long)bitmap_bh->b_blocknr, 
 			ext3_test_bit(bit, bitmap_bh->b_data));
 		printk(KERN_NOTICE "inode=%p\n", inode);
 		if (inode) {
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c	Fri Oct 11 21:23:00 2002
+++ b/fs/ext3/inode.c	Fri Oct 11 21:23:00 2002
@@ -1181,7 +1181,7 @@
  * So, if we see any bmap calls here on a modified, data-journaled file,
  * take extra steps to flush any blocks which might be in the cache. 
  */
-static int ext3_bmap(struct address_space *mapping, long block)
+static sector_t ext3_bmap(struct address_space *mapping, sector_t block)
 {
 	struct inode *inode = mapping->host;
 	journal_t *journal;
diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c
--- a/fs/ext3/namei.c	Fri Oct 11 21:23:00 2002
+++ b/fs/ext3/namei.c	Fri Oct 11 21:23:00 2002
@@ -16,9 +16,16 @@
  *        David S. Miller (davem@caip.rutgers.edu), 1995
  *  Directory entry file type support and forward compatibility hooks
  *  	for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
+ *  Hash Tree Directory indexing (c)
+ *  	Daniel Phillips, 2001
+ *  Hash Tree Directory indexing porting
+ *  	Christopher Li, 2002
+ *  Hash Tree Directory indexing cleanup
+ * 	Theodore Ts'o, 2002
  */
 
 #include <linux/fs.h>
+#include <linux/pagemap.h>
 #include <linux/jbd.h>
 #include <linux/time.h>
 #include <linux/ext3_fs.h>
@@ -39,6 +46,630 @@
 #define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
 #define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
 
+static struct buffer_head *ext3_append(handle_t *handle,
+					struct inode *inode,
+					u32 *block, int *err)
+{
+	struct buffer_head *bh;
+
+	*block = inode->i_size >> inode->i_sb->s_blocksize_bits;
+
+	if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
+		inode->i_size += inode->i_sb->s_blocksize;
+		EXT3_I(inode)->i_disksize = inode->i_size;
+		ext3_journal_get_write_access(handle,bh);
+	}
+	return bh;
+}
+
+#ifndef assert
+#define assert(test) J_ASSERT(test)
+#endif
+
+#ifndef swap
+#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0)
+#endif
+
+typedef struct { u32 v; } le_u32;
+typedef struct { u16 v; } le_u16;
+
+#ifdef DX_DEBUG
+#define dxtrace(command) command
+#else
+#define dxtrace(command) 
+#endif
+
+struct fake_dirent
+{
+	/*le*/u32 inode;
+	/*le*/u16 rec_len;
+	u8 name_len;
+	u8 file_type;
+};
+
+struct dx_countlimit
+{
+	le_u16 limit;
+	le_u16 count;
+};
+
+struct dx_entry
+{
+	le_u32 hash;
+	le_u32 block;
+};
+
+/*
+ * dx_root_info is laid out so that if it should somehow get overlaid by a
+ * dirent the two low bits of the hash version will be zero.  Therefore, the
+ * hash version mod 4 should never be 0.  Sincerely, the paranoia department.
+ */
+
+struct dx_root
+{
+	struct fake_dirent dot;
+	char dot_name[4];
+	struct fake_dirent dotdot;
+	char dotdot_name[4];
+	struct dx_root_info
+	{
+		le_u32 reserved_zero;
+		u8 hash_version;
+		u8 info_length; /* 8 */
+		u8 indirect_levels;
+		u8 unused_flags;
+	}
+	info;
+	struct dx_entry	entries[0];
+};
+
+struct dx_node
+{
+	struct fake_dirent fake;
+	struct dx_entry	entries[0];
+};
+
+
+struct dx_frame
+{
+	struct buffer_head *bh;
+	struct dx_entry *entries;
+	struct dx_entry *at;
+};
+
+struct dx_map_entry
+{
+	u32 hash;
+	u32 offs;
+};
+
+#ifdef CONFIG_EXT3_INDEX
+static inline unsigned dx_get_block (struct dx_entry *entry);
+static void dx_set_block (struct dx_entry *entry, unsigned value);
+static inline unsigned dx_get_hash (struct dx_entry *entry);
+static void dx_set_hash (struct dx_entry *entry, unsigned value);
+static unsigned dx_get_count (struct dx_entry *entries);
+static unsigned dx_get_limit (struct dx_entry *entries);
+static void dx_set_count (struct dx_entry *entries, unsigned value);
+static void dx_set_limit (struct dx_entry *entries, unsigned value);
+static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
+static unsigned dx_node_limit (struct inode *dir);
+static struct dx_frame *dx_probe(struct dentry *dentry,
+				 struct inode *dir,
+				 struct dx_hash_info *hinfo,
+				 struct dx_frame *frame,
+				 int *err);
+static void dx_release (struct dx_frame *frames);
+static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
+			struct dx_hash_info *hinfo, struct dx_map_entry map[]);
+static void dx_sort_map(struct dx_map_entry *map, unsigned count);
+static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
+		struct dx_map_entry *offsets, int count);
+static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
+static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
+static int ext3_htree_next_block(struct inode *dir, __u32 hash,
+				 struct dx_frame *frame,
+				 struct dx_frame *frames, int *err,
+				 __u32 *start_hash);
+static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
+		       struct ext3_dir_entry_2 **res_dir, int *err);
+static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
+			     struct inode *inode);
+
+/*
+ * Future: use high four bits of block for coalesce-on-delete flags
+ * Mask them off for now.
+ */
+
+static inline unsigned dx_get_block (struct dx_entry *entry)
+{
+	return le32_to_cpu(entry->block.v) & 0x00ffffff;
+}
+
+static inline void dx_set_block (struct dx_entry *entry, unsigned value)
+{
+	entry->block.v = cpu_to_le32(value);
+}
+
+static inline unsigned dx_get_hash (struct dx_entry *entry)
+{
+	return le32_to_cpu(entry->hash.v);
+}
+
+static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
+{
+	entry->hash.v = cpu_to_le32(value);
+}
+
+static inline unsigned dx_get_count (struct dx_entry *entries)
+{
+	return le16_to_cpu(((struct dx_countlimit *) entries)->count.v);
+}
+
+static inline unsigned dx_get_limit (struct dx_entry *entries)
+{
+	return le16_to_cpu(((struct dx_countlimit *) entries)->limit.v);
+}
+
+static inline void dx_set_count (struct dx_entry *entries, unsigned value)
+{
+	((struct dx_countlimit *) entries)->count.v = cpu_to_le16(value);
+}
+
+static inline void dx_set_limit (struct dx_entry *entries, unsigned value)
+{
+	((struct dx_countlimit *) entries)->limit.v = cpu_to_le16(value);
+}
+
+static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
+{
+	unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) -
+		EXT3_DIR_REC_LEN(2) - infosize;
+	return 0? 20: entry_space / sizeof(struct dx_entry);
+}
+
+static inline unsigned dx_node_limit (struct inode *dir)
+{
+	unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0);
+	return 0? 22: entry_space / sizeof(struct dx_entry);
+}
+
+/*
+ * Debug
+ */
+#ifdef DX_DEBUG
+struct stats
+{ 
+	unsigned names;
+	unsigned space;
+	unsigned bcount;
+};
+
+static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_entry_2 *de,
+				 int size, int show_names)
+{
+	unsigned names = 0, space = 0;
+	char *base = (char *) de;
+	struct dx_hash_info h = *hinfo;
+	
+	printk("names: ");
+	while ((char *) de < base + size)
+	{
+		if (de->inode)
+		{
+			if (show_names)
+			{
+				int len = de->name_len;
+				char *name = de->name;
+				while (len--) printk("%c", *name++);
+				ext3fs_dirhash(de->name, de->name_len, &h);
+				printk(":%x.%u ", h.hash,
+				       ((char *) de - base));
+			}
+			space += EXT3_DIR_REC_LEN(de->name_len);
+	 		names++;
+		}
+		de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+	}
+	printk("(%i)\n", names);
+	return (struct stats) { names, space, 1 };
+}
+
+struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
+			     struct dx_entry *entries, int levels)
+{
+	unsigned blocksize = dir->i_sb->s_blocksize;
+	unsigned count = dx_get_count (entries), names = 0, space = 0, i;
+	unsigned bcount = 0;
+	struct buffer_head *bh;
+	int err;
+	printk("%i indexed blocks...\n", count);
+	for (i = 0; i < count; i++, entries++)
+	{
+		u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0;
+		u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash;
+		struct stats stats;
+		printk("%s%3u:%03u hash %8x/%8x ",levels?"":"   ", i, block, hash, range);
+		if (!(bh = ext3_bread (NULL,dir, block, 0,&err))) continue;
+		stats = levels?
+		   dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1):
+		   dx_show_leaf(hinfo, (struct ext3_dir_entry_2 *) bh->b_data, blocksize, 0);
+		names += stats.names;
+		space += stats.space;
+		bcount += stats.bcount;
+		brelse (bh);
+	}
+	if (bcount)
+		printk("%snames %u, fullness %u (%u%%)\n", levels?"":"   ",
+			names, space/bcount,(space/bcount)*100/blocksize);
+	return (struct stats) { names, space, bcount};
+}
+#endif /* DX_DEBUG */
+
+/*
+ * Probe for a directory leaf block to search.
+ *
+ * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
+ * error in the directory index, and the caller should fall back to
+ * searching the directory normally.  The callers of dx_probe **MUST**
+ * check for this error code, and make sure it never gets reflected
+ * back to userspace.
+ */
+static struct dx_frame *
+dx_probe(struct dentry *dentry, struct inode *dir,
+	 struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
+{
+	unsigned count, indirect;
+	struct dx_entry *at, *entries, *p, *q, *m;
+	struct dx_root *root;
+	struct buffer_head *bh;
+	struct dx_frame *frame = frame_in;
+	u32 hash;
+
+	frame->bh = NULL;
+	if (dentry)
+		dir = dentry->d_parent->d_inode;
+	if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
+		goto fail;
+	root = (struct dx_root *) bh->b_data;
+	if (root->info.hash_version != DX_HASH_TEA &&
+	    root->info.hash_version != DX_HASH_HALF_MD4 &&
+	    root->info.hash_version != DX_HASH_LEGACY) {
+		ext3_warning(dir->i_sb, __FUNCTION__,
+			     "Unrecognised inode hash code %d",
+			     root->info.hash_version);
+		brelse(bh);
+		*err = ERR_BAD_DX_DIR;
+		goto fail;
+	}
+	hinfo->hash_version = root->info.hash_version;
+	hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
+	if (dentry)
+		ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
+	hash = hinfo->hash;
+
+	if (root->info.unused_flags & 1) {
+		ext3_warning(dir->i_sb, __FUNCTION__,
+			     "Unimplemented inode hash flags: %#06x",
+			     root->info.unused_flags);
+		brelse(bh);
+		*err = ERR_BAD_DX_DIR;
+		goto fail;
+	}
+
+	if ((indirect = root->info.indirect_levels) > 1) {
+		ext3_warning(dir->i_sb, __FUNCTION__,
+			     "Unimplemented inode hash depth: %#06x",
+			     root->info.indirect_levels);
+		brelse(bh);
+		*err = ERR_BAD_DX_DIR;
+		goto fail;
+	}
+
+	entries = (struct dx_entry *) (((char *)&root->info) +
+				       root->info.info_length);
+	assert(dx_get_limit(entries) == dx_root_limit(dir,
+						      root->info.info_length));
+	dxtrace (printk("Look up %x", hash));
+	while (1)
+	{
+		count = dx_get_count(entries);
+		assert (count && count <= dx_get_limit(entries));
+		p = entries + 1;
+		q = entries + count - 1;
+		while (p <= q)
+		{
+			m = p + (q - p)/2;
+			dxtrace(printk("."));
+			if (dx_get_hash(m) > hash)
+				q = m - 1;
+			else
+				p = m + 1;
+		}
+
+		if (0) // linear search cross check
+		{
+			unsigned n = count - 1;
+			at = entries;
+			while (n--)
+			{
+				dxtrace(printk(","));
+				if (dx_get_hash(++at) > hash)
+				{
+					at--;
+					break;
+				}
+			}
+			assert (at == p - 1);
+		}
+
+		at = p - 1;
+		dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
+		frame->bh = bh;
+		frame->entries = entries;
+		frame->at = at;
+		if (!indirect--) return frame;
+		if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
+			goto fail2;
+		at = entries = ((struct dx_node *) bh->b_data)->entries;
+		assert (dx_get_limit(entries) == dx_node_limit (dir));
+		frame++;
+	}
+fail2:
+	while (frame >= frame_in) {
+		brelse(frame->bh);
+		frame--;
+	}
+fail:
+	return NULL;
+}
+
+static void dx_release (struct dx_frame *frames)
+{
+	if (frames[0].bh == NULL)
+		return;
+
+	if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
+		brelse(frames[1].bh);
+	brelse(frames[0].bh);
+}
+
+/*
+ * This function increments the frame pointer to search the next leaf
+ * block, and reads in the necessary intervening nodes if the search
+ * should be necessary.  Whether or not the search is necessary is
+ * controlled by the hash parameter.  If the hash value is even, then
+ * the search is only continued if the next block starts with that
+ * hash value.  This is used if we are searching for a specific file.
+ *
+ * If the hash value is HASH_NB_ALWAYS, then always go to the next block.
+ *
+ * This function returns 1 if the caller should continue to search,
+ * or 0 if it should not.  If there is an error reading one of the
+ * index blocks, it will return -1.
+ *
+ * If start_hash is non-null, it will be filled in with the starting
+ * hash of the next page.
+ */
+static int ext3_htree_next_block(struct inode *dir, __u32 hash,
+				 struct dx_frame *frame,
+				 struct dx_frame *frames, int *err,
+				 __u32 *start_hash)
+{
+	struct dx_frame *p;
+	struct buffer_head *bh;
+	int num_frames = 0;
+	__u32 bhash;
+
+	*err = ENOENT;
+	p = frame;
+	/*
+	 * Find the next leaf page by incrementing the frame pointer.
+	 * If we run out of entries in the interior node, loop around and
+	 * increment pointer in the parent node.  When we break out of
+	 * this loop, num_frames indicates the number of interior
+	 * nodes need to be read.
+	 */
+	while (1) {
+		if (++(p->at) < p->entries + dx_get_count(p->entries))
+			break;
+		if (p == frames)
+			return 0;
+		num_frames++;
+		p--;
+	}
+
+	/*
+	 * If the hash is 1, then continue only if the next page has a
+	 * continuation hash of any value.  This is used for readdir
+	 * handling.  Otherwise, check to see if the hash matches the
+	 * desired contiuation hash.  If it doesn't, return since
+	 * there's no point to read in the successive index pages.
+	 */
+	bhash = dx_get_hash(p->at);
+	if (start_hash)
+		*start_hash = bhash;
+	if ((hash & 1) == 0) {
+		if ((bhash & ~1) != hash)
+			return 0;
+	}
+	/*
+	 * If the hash is HASH_NB_ALWAYS, we always go to the next
+	 * block so no check is necessary
+	 */
+	while (num_frames--) {
+		if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at),
+				      0, err)))
+			return -1; /* Failure */
+		p++;
+		brelse (p->bh);
+		p->bh = bh;
+		p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
+	}
+	return 1;
+}
+
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+static inline struct ext3_dir_entry_2 *ext3_next_entry(struct ext3_dir_entry_2 *p)
+{
+	return (struct ext3_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len));
+}
+
+/*
+ * This function fills a red-black tree with information from a
+ * directory.  We start scanning the directory in hash order, starting
+ * at start_hash and start_minor_hash.
+ *
+ * This function returns the number of entries inserted into the tree,
+ * or a negative error code.
+ */
+int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+			 __u32 start_minor_hash, __u32 *next_hash)
+{
+	struct dx_hash_info hinfo;
+	struct buffer_head *bh;
+	struct ext3_dir_entry_2 *de, *top;
+	static struct dx_frame frames[2], *frame;
+	struct inode *dir;
+	int block, err;
+	int count = 0;
+	int ret;
+	__u32 hashval;
+	
+	dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
+		       start_minor_hash));
+	dir = dir_file->f_dentry->d_inode;
+	hinfo.hash = start_hash;
+	hinfo.minor_hash = 0;
+	frame = dx_probe(0, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+	if (!frame)
+		return err;
+
+	while (1) {
+		block = dx_get_block(frame->at);
+		dxtrace(printk("Reading block %d\n", block));
+		if (!(bh = ext3_bread (NULL, dir, block, 0, &err)))
+			goto errout;
+	
+		de = (struct ext3_dir_entry_2 *) bh->b_data;
+		top = (struct ext3_dir_entry_2 *) ((char *) de + dir->i_sb->s_blocksize -
+				       EXT3_DIR_REC_LEN(0));
+		for (; de < top; de = ext3_next_entry(de)) {
+			ext3fs_dirhash(de->name, de->name_len, &hinfo);
+			if ((hinfo.hash < start_hash) ||
+			    ((hinfo.hash == start_hash) &&
+			     (hinfo.minor_hash < start_minor_hash)))
+				continue;
+			ext3_htree_store_dirent(dir_file, hinfo.hash,
+						hinfo.minor_hash, de);
+			count++;
+		}
+		brelse (bh);
+		hashval = ~1;
+		ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, 
+					    frame, frames, &err, &hashval);
+		if (next_hash)
+			*next_hash = hashval;
+		if (ret == -1)
+			goto errout;
+		/*
+		 * Stop if:  (a) there are no more entries, or
+		 * (b) we have inserted at least one entry and the
+		 * next hash value is not a continuation
+		 */
+		if ((ret == 0) ||
+		    (count && ((hashval & 1) == 0)))
+			break;
+	}
+	dx_release(frames);
+	dxtrace(printk("Fill tree: returned %d entries\n", count));
+	return count;
+errout:
+	dx_release(frames);
+	return (err);
+}
+
+
+/*
+ * Directory block splitting, compacting
+ */
+
+static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
+			struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
+{
+	int count = 0;
+	char *base = (char *) de;
+	struct dx_hash_info h = *hinfo;
+	
+	while ((char *) de < base + size)
+	{
+		if (de->name_len && de->inode) {
+			ext3fs_dirhash(de->name, de->name_len, &h);
+			map_tail--;
+			map_tail->hash = h.hash;
+			map_tail->offs = (u32) ((char *) de - base);
+			count++;
+		}
+		/* XXX: do we need to check rec_len == 0 case? -Chris */
+		de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+	}
+	return count;
+}
+
+static void dx_sort_map (struct dx_map_entry *map, unsigned count)
+{
+        struct dx_map_entry *p, *q, *top = map + count - 1;
+        int more;
+        /* Combsort until bubble sort doesn't suck */
+        while (count > 2)
+	{
+                count = count*10/13;
+                if (count - 9 < 2) /* 9, 10 -> 11 */
+                        count = 11;
+                for (p = top, q = p - count; q >= map; p--, q--)
+                        if (p->hash < q->hash)
+                                swap(*p, *q);
+        }
+        /* Garden variety bubble sort */
+        do {
+                more = 0;
+                q = top;
+                while (q-- > map)
+		{
+                        if (q[1].hash >= q[0].hash)
+				continue;
+                        swap(*(q+1), *q);
+                        more = 1;
+		}
+	} while(more);
+}
+
+static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
+{
+	struct dx_entry *entries = frame->entries;
+	struct dx_entry *old = frame->at, *new = old + 1;
+	int count = dx_get_count(entries);
+
+	assert(count < dx_get_limit(entries));
+	assert(old < entries + count);
+	memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
+	dx_set_hash(new, hash);
+	dx_set_block(new, block);
+	dx_set_count(entries, count + 1);
+}
+#endif
+
+
+static void ext3_update_dx_flag(struct inode *inode)
+{
+	if (!EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
+				     EXT3_FEATURE_COMPAT_DIR_INDEX))
+		EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL;
+}
+
 /*
  * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure.
  *
@@ -95,6 +726,7 @@
 	return 0;
 }
 
+
 /*
  *	ext3_find_entry()
  *
@@ -106,6 +738,8 @@
  * The returned buffer_head has ->b_count elevated.  The caller is expected
  * to brelse() it when appropriate.
  */
+
+	
 static struct buffer_head * ext3_find_entry (struct dentry *dentry,
 					struct ext3_dir_entry_2 ** res_dir)
 {
@@ -120,10 +754,30 @@
 	int num = 0;
 	int nblocks, i, err;
 	struct inode *dir = dentry->d_parent->d_inode;
+	int namelen;
+	const u8 *name;
+	unsigned blocksize;
 
 	*res_dir = NULL;
 	sb = dir->i_sb;
-
+	blocksize = sb->s_blocksize;
+	namelen = dentry->d_name.len;
+	name = dentry->d_name.name;
+	if (namelen > EXT3_NAME_LEN)
+		return NULL;
+#ifdef CONFIG_EXT3_INDEX
+	if (is_dx(dir)) {
+		bh = ext3_dx_find_entry(dentry, res_dir, &err);
+		/*
+		 * On success, or if the error was file not found,
+		 * return.  Otherwise, fall back to doing a search the
+		 * old fashioned way.
+		 */
+		if (bh || (err != ERR_BAD_DX_DIR))
+			return bh;
+		dxtrace(printk("ext3_find_entry: dx failed, falling back\n"));
+	}
+#endif
 	nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
 	start = EXT3_I(dir)->i_dir_start_lookup;
 	if (start >= nblocks)
@@ -197,6 +851,66 @@
 	return ret;
 }
 
+#ifdef CONFIG_EXT3_INDEX
+static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
+		       struct ext3_dir_entry_2 **res_dir, int *err)
+{
+	struct super_block * sb;
+	struct dx_hash_info	hinfo;
+	u32 hash;
+	struct dx_frame frames[2], *frame;
+	struct ext3_dir_entry_2 *de, *top;
+	struct buffer_head *bh;
+	unsigned long block;
+	int retval;
+	int namelen = dentry->d_name.len;
+	const u8 *name = dentry->d_name.name;
+	struct inode *dir = dentry->d_parent->d_inode;
+	
+	sb = dir->i_sb;
+	if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err)))
+		return NULL;
+	hash = hinfo.hash;
+	do {
+		block = dx_get_block(frame->at);
+		if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
+			goto errout;
+		de = (struct ext3_dir_entry_2 *) bh->b_data;
+		top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize -
+				       EXT3_DIR_REC_LEN(0));
+		for (; de < top; de = ext3_next_entry(de))
+		if (ext3_match (namelen, name, de)) {
+			if (!ext3_check_dir_entry("ext3_find_entry",
+						  dir, de, bh,
+				  (block<<EXT3_BLOCK_SIZE_BITS(sb))
+					  +((char *)de - bh->b_data))) {
+				brelse (bh);
+				goto errout;
+			}
+			*res_dir = de;
+			dx_release (frames);
+			return bh;
+		}
+		brelse (bh);
+		/* Check to see if we should continue to search */
+		retval = ext3_htree_next_block(dir, hash, frame,
+					       frames, err, 0);
+		if (retval == -1) {
+			ext3_warning(sb, __FUNCTION__,
+			     "error reading index page in directory #%lu",
+			     dir->i_ino);
+			goto errout;
+		}
+	} while (retval == 1);
+	
+	*err = -ENOENT;
+errout:
+	dxtrace(printk("%s not found\n", name));
+	dx_release (frames);
+	return NULL;
+}
+#endif
+
 static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct inode * inode;
@@ -281,6 +995,300 @@
 		de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
 }
 
+#ifdef CONFIG_EXT3_INDEX
+static struct ext3_dir_entry_2 *
+dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
+{
+	unsigned rec_len = 0;
+
+	while (count--) {
+		struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs);
+		rec_len = EXT3_DIR_REC_LEN(de->name_len);
+		memcpy (to, de, rec_len);
+		((struct ext3_dir_entry_2 *) to)->rec_len = rec_len;
+		de->inode = 0;
+		map++;
+		to += rec_len;
+	}
+	return (struct ext3_dir_entry_2 *) (to - rec_len);
+}
+
+static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
+{
+	struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
+	unsigned rec_len = 0;
+
+	prev = to = de;
+	while ((char*)de < base + size) {
+		next = (struct ext3_dir_entry_2 *) ((char *) de +
+						    le16_to_cpu(de->rec_len));
+		if (de->inode && de->name_len) {
+			rec_len = EXT3_DIR_REC_LEN(de->name_len);
+			if (de > to)
+				memmove(to, de, rec_len);
+			to->rec_len = rec_len;
+			prev = to;
+			to = (struct ext3_dir_entry_2 *) (((char *) to) + rec_len);
+		}
+		de = next;
+	}
+	return prev;
+}
+
+static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
+			struct buffer_head **bh,struct dx_frame *frame,
+			struct dx_hash_info *hinfo, int *error)
+{
+	unsigned blocksize = dir->i_sb->s_blocksize;
+	unsigned count, continued;
+	struct buffer_head *bh2;
+	u32 newblock;
+	u32 hash2;
+	struct dx_map_entry *map;
+	char *data1 = (*bh)->b_data, *data2;
+	unsigned split;
+	struct ext3_dir_entry_2 *de = NULL, *de2;
+	int	err;
+
+	bh2 = ext3_append (handle, dir, &newblock, error);
+	if (!(bh2)) {
+		brelse(*bh);
+		*bh = NULL;
+		goto errout;
+	}
+
+	BUFFER_TRACE(*bh, "get_write_access");
+	err = ext3_journal_get_write_access(handle, *bh);
+	if (err) {
+	journal_error:
+		brelse(*bh);
+		brelse(bh2);
+		*bh = NULL;
+		ext3_std_error(dir->i_sb, err);
+		goto errout;
+	}
+	BUFFER_TRACE(frame->bh, "get_write_access");
+	err = ext3_journal_get_write_access(handle, frame->bh);
+	if (err)
+		goto journal_error;
+
+	data2 = bh2->b_data;
+
+	/* create map in the end of data2 block */
+	map = (struct dx_map_entry *) (data2 + blocksize);
+	count = dx_make_map ((struct ext3_dir_entry_2 *) data1,
+			     blocksize, hinfo, map);
+	map -= count;
+	split = count/2; // need to adjust to actual middle
+	dx_sort_map (map, count);
+	hash2 = map[split].hash;
+	continued = hash2 == map[split - 1].hash;
+	dxtrace(printk("Split block %i at %x, %i/%i\n",
+		dx_get_block(frame->at), hash2, split, count-split));
+
+	/* Fancy dance to stay within two buffers */
+	de2 = dx_move_dirents(data1, data2, map + split, count - split);
+	de = dx_pack_dirents(data1,blocksize);
+	de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
+	de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
+	dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1));
+	dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1));
+
+	/* Which block gets the new entry? */
+	if (hinfo->hash >= hash2)
+	{
+		swap(*bh, bh2);
+		de = de2;
+	}
+	dx_insert_block (frame, hash2 + continued, newblock);
+	err = ext3_journal_dirty_metadata (handle, bh2);
+	if (err)
+		goto journal_error;
+	err = ext3_journal_dirty_metadata (handle, frame->bh);
+	if (err)
+		goto journal_error;
+	brelse (bh2);
+	dxtrace(dx_show_index ("frame", frame->entries));
+errout:
+	return de;
+}
+#endif
+
+
+/*
+ * Add a new entry into a directory (leaf) block.  If de is non-NULL,
+ * it points to a directory entry which is guaranteed to be large
+ * enough for new directory entry.  If de is NULL, then
+ * add_dirent_to_buf will attempt search the directory block for
+ * space.  It will return -ENOSPC if no space is available, and -EIO
+ * and -EEXIST if directory entry already exists.
+ * 
+ * NOTE!  bh is NOT released in the case where ENOSPC is returned.  In
+ * all other cases bh is released.
+ */
+static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
+			     struct inode *inode, struct ext3_dir_entry_2 *de,
+			     struct buffer_head * bh)
+{
+	struct inode	*dir = dentry->d_parent->d_inode;
+	const char	*name = dentry->d_name.name;
+	int		namelen = dentry->d_name.len;
+	unsigned long	offset = 0;
+	unsigned short	reclen;
+	int		nlen, rlen, err;
+	char		*top;
+	
+	reclen = EXT3_DIR_REC_LEN(namelen);
+	if (!de) {
+		de = (struct ext3_dir_entry_2 *)bh->b_data;
+		top = bh->b_data + dir->i_sb->s_blocksize - reclen;
+		while ((char *) de <= top) {
+			if (!ext3_check_dir_entry("ext3_add_entry", dir, de,
+						  bh, offset)) {
+				brelse (bh);
+				return -EIO;
+			}
+			if (ext3_match (namelen, name, de)) {
+				brelse (bh);
+				return -EEXIST;
+			}
+			nlen = EXT3_DIR_REC_LEN(de->name_len);
+			rlen = le16_to_cpu(de->rec_len);
+			if ((de->inode? rlen - nlen: rlen) >= reclen)
+				break;
+			de = (struct ext3_dir_entry_2 *)((char *)de + rlen);
+			offset += rlen;
+		}
+		if ((char *) de > top)
+			return -ENOSPC;
+	}
+	BUFFER_TRACE(bh, "get_write_access");
+	err = ext3_journal_get_write_access(handle, bh);
+	if (err) {
+		ext3_std_error(dir->i_sb, err);
+		brelse(bh);
+		return err;
+	}
+	
+	/* By now the buffer is marked for journaling */
+	nlen = EXT3_DIR_REC_LEN(de->name_len);
+	rlen = le16_to_cpu(de->rec_len);
+	if (de->inode) {
+		struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen);
+		de1->rec_len = cpu_to_le16(rlen - nlen);
+		de->rec_len = cpu_to_le16(nlen);
+		de = de1;
+	}
+	de->file_type = EXT3_FT_UNKNOWN;
+	if (inode) {
+		de->inode = cpu_to_le32(inode->i_ino);
+		ext3_set_de_type(dir->i_sb, de, inode->i_mode);
+	} else
+		de->inode = 0;
+	de->name_len = namelen;
+	memcpy (de->name, name, namelen);
+	/*
+	 * XXX shouldn't update any times until successful
+	 * completion of syscall, but too many callers depend
+	 * on this.
+	 *
+	 * XXX similarly, too many callers depend on
+	 * ext3_new_inode() setting the times, but error
+	 * recovery deletes the inode, so the worst that can
+	 * happen is that the times are slightly out of date
+	 * and/or different from the directory change time.
+	 */
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+	ext3_update_dx_flag(dir);
+	dir->i_version = ++event;
+	ext3_mark_inode_dirty(handle, dir);
+	BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
+	err = ext3_journal_dirty_metadata(handle, bh);
+	if (err)
+		ext3_std_error(dir->i_sb, err);
+	brelse(bh);
+	return 0;
+}
+
+#ifdef CONFIG_EXT3_INDEX
+/*
+ * This converts a one block unindexed directory to a 3 block indexed
+ * directory, and adds the dentry to the indexed directory.
+ */
+static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
+			    struct inode *inode, struct buffer_head *bh)
+{
+	struct inode	*dir = dentry->d_parent->d_inode;
+	const char	*name = dentry->d_name.name;
+	int		namelen = dentry->d_name.len;
+	struct buffer_head *bh2;
+	struct dx_root	*root;
+	struct dx_frame	frames[2], *frame;
+	struct dx_entry *entries;
+	struct ext3_dir_entry_2	*de, *de2;
+	char		*data1, *top;
+	unsigned	len;
+	int		retval;
+	unsigned	blocksize;
+	struct dx_hash_info hinfo;
+	u32		block;
+		
+	blocksize =  dir->i_sb->s_blocksize;
+	dxtrace(printk("Creating index\n"));
+	retval = ext3_journal_get_write_access(handle, bh);
+	if (retval) {
+		ext3_std_error(dir->i_sb, retval);
+		brelse(bh);
+		return retval;
+	}
+	root = (struct dx_root *) bh->b_data;
+		
+	EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
+	bh2 = ext3_append (handle, dir, &block, &retval);
+	if (!(bh2)) {
+		brelse(bh);
+		return retval;
+	}
+	data1 = bh2->b_data;
+
+	/* The 0th block becomes the root, move the dirents out */
+	de = (struct ext3_dir_entry_2 *) &root->info;
+	len = ((char *) root) + blocksize - (char *) de;
+	memcpy (data1, de, len);
+	de = (struct ext3_dir_entry_2 *) data1;
+	top = data1 + len;
+	while (((char *) de2=(char*)de+le16_to_cpu(de->rec_len)) < top)
+		de = de2;
+	de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
+	/* Initialize the root; the dot dirents already exist */
+	de = (struct ext3_dir_entry_2 *) (&root->dotdot);
+	de->rec_len = cpu_to_le16(blocksize - EXT3_DIR_REC_LEN(2));
+	memset (&root->info, 0, sizeof(root->info));
+	root->info.info_length = sizeof(root->info);
+	root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
+	entries = root->entries;
+	dx_set_block (entries, 1);
+	dx_set_count (entries, 1);
+	dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
+
+	/* Initialize as for dx_probe */
+	hinfo.hash_version = root->info.hash_version;
+	hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
+	ext3fs_dirhash(name, namelen, &hinfo);
+	frame = frames;
+	frame->entries = entries;
+	frame->at = entries;
+	frame->bh = bh;
+	bh = bh2;
+	de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
+	dx_release (frames);
+	if (!(de))
+		return retval;
+
+	return add_dirent_to_buf(handle, dentry, inode, de, bh);
+}
+#endif
+
 /*
  *	ext3_add_entry()
  *
@@ -291,127 +1299,198 @@
  * may not sleep between calling this and putting something into
  * the entry, as someone else might have used it while you slept.
  */
-
-/*
- * AKPM: the journalling code here looks wrong on the error paths
- */
 static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
 	struct inode *inode)
 {
 	struct inode *dir = dentry->d_parent->d_inode;
-	const char *name = dentry->d_name.name;
-	int namelen = dentry->d_name.len;
 	unsigned long offset;
-	unsigned short rec_len;
 	struct buffer_head * bh;
-	struct ext3_dir_entry_2 * de, * de1;
+	struct ext3_dir_entry_2 *de;
 	struct super_block * sb;
 	int	retval;
+#ifdef CONFIG_EXT3_INDEX
+	int	dx_fallback=0;
+#endif
+	unsigned blocksize;
+	unsigned nlen, rlen;
+	u32 block, blocks;
 
 	sb = dir->i_sb;
-
-	if (!namelen)
+	blocksize = sb->s_blocksize;
+	if (!dentry->d_name.len)
 		return -EINVAL;
-	bh = ext3_bread (handle, dir, 0, 0, &retval);
+#ifdef CONFIG_EXT3_INDEX
+	if (is_dx(dir)) {
+		retval = ext3_dx_add_entry(handle, dentry, inode);
+		if (!retval || (retval != ERR_BAD_DX_DIR))
+			return retval;
+		EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
+		dx_fallback++;
+		ext3_mark_inode_dirty(handle, dir);
+	}
+#endif
+	blocks = dir->i_size >> sb->s_blocksize_bits;
+	for (block = 0, offset = 0; block < blocks; block++) {
+		bh = ext3_bread(handle, dir, block, 0, &retval);
+		if(!bh)
+			return retval;
+		retval = add_dirent_to_buf(handle, dentry, inode, 0, bh);
+		if (retval != -ENOSPC)
+			return retval;
+
+#ifdef CONFIG_EXT3_INDEX
+		if (blocks == 1 && !dx_fallback &&
+		    EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
+			return make_indexed_dir(handle, dentry, inode, bh);
+#endif
+		brelse(bh);
+	}
+	bh = ext3_append(handle, dir, &block, &retval);
 	if (!bh)
 		return retval;
-	rec_len = EXT3_DIR_REC_LEN(namelen);
-	offset = 0;
 	de = (struct ext3_dir_entry_2 *) bh->b_data;
-	while (1) {
-		if ((char *)de >= sb->s_blocksize + bh->b_data) {
-			brelse (bh);
-			bh = NULL;
-			bh = ext3_bread (handle, dir,
-				offset >> EXT3_BLOCK_SIZE_BITS(sb), 1, &retval);
-			if (!bh)
-				return retval;
-			if (dir->i_size <= offset) {
-				if (dir->i_size == 0) {
-					brelse(bh);
-					return -ENOENT;
-				}
+	de->inode = 0;
+	de->rec_len = cpu_to_le16(rlen = blocksize);
+	nlen = 0;
+	return add_dirent_to_buf(handle, dentry, inode, de, bh);
+}
 
-				ext3_debug ("creating next block\n");
+#ifdef CONFIG_EXT3_INDEX
+/*
+ * Returns 0 for success, or a negative error value
+ */
+static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
+			     struct inode *inode)
+{
+	struct dx_frame frames[2], *frame;
+	struct dx_entry *entries, *at;
+	struct dx_hash_info hinfo;
+	struct buffer_head * bh;
+	struct inode *dir = dentry->d_parent->d_inode;
+	struct super_block * sb = dir->i_sb;
+	struct ext3_dir_entry_2 *de;
+	int err;
 
-				BUFFER_TRACE(bh, "get_write_access");
-				ext3_journal_get_write_access(handle, bh);
-				de = (struct ext3_dir_entry_2 *) bh->b_data;
-				de->inode = 0;
-				de->rec_len = le16_to_cpu(sb->s_blocksize);
-				EXT3_I(dir)->i_disksize =
-					dir->i_size = offset + sb->s_blocksize;
-				EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
-				ext3_mark_inode_dirty(handle, dir);
-			} else {
+	frame = dx_probe(dentry, 0, &hinfo, frames, &err);
+	if (!frame)
+		return err;
+	entries = frame->entries;
+	at = frame->at;
 
-				ext3_debug ("skipping to next block\n");
+	if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
+		goto cleanup;
 
-				de = (struct ext3_dir_entry_2 *) bh->b_data;
-			}
-		}
-		if (!ext3_check_dir_entry ("ext3_add_entry", dir, de, bh,
-					   offset)) {
-			brelse (bh);
-			return -ENOENT;
-		}
-		if (ext3_match (namelen, name, de)) {
-				brelse (bh);
-				return -EEXIST;
+	BUFFER_TRACE(bh, "get_write_access");
+	err = ext3_journal_get_write_access(handle, bh);
+	if (err)
+		goto journal_error;
+
+	err = add_dirent_to_buf(handle, dentry, inode, 0, bh);
+	if (err != -ENOSPC) {
+		bh = 0;
+		goto cleanup;
+	}
+
+	/* Block full, should compress but for now just split */
+	dxtrace(printk("using %u of %u node entries\n",
+		       dx_get_count(entries), dx_get_limit(entries)));
+	/* Need to split index? */
+	if (dx_get_count(entries) == dx_get_limit(entries)) {
+		u32 newblock;
+		unsigned icount = dx_get_count(entries);
+		int levels = frame - frames;
+		struct dx_entry *entries2;
+		struct dx_node *node2;
+		struct buffer_head *bh2;
+
+		if (levels && (dx_get_count(frames->entries) ==
+			       dx_get_limit(frames->entries))) {
+			ext3_warning(sb, __FUNCTION__,
+				     "Directory index full!\n");
+			err = -ENOSPC;
+			goto cleanup;
 		}
-		if ((le32_to_cpu(de->inode) == 0 &&
-				le16_to_cpu(de->rec_len) >= rec_len) ||
-		    (le16_to_cpu(de->rec_len) >=
-				EXT3_DIR_REC_LEN(de->name_len) + rec_len)) {
-			BUFFER_TRACE(bh, "get_write_access");
-			ext3_journal_get_write_access(handle, bh);
-			/* By now the buffer is marked for journaling */
-			offset += le16_to_cpu(de->rec_len);
-			if (le32_to_cpu(de->inode)) {
-				de1 = (struct ext3_dir_entry_2 *) ((char *) de +
-					EXT3_DIR_REC_LEN(de->name_len));
-				de1->rec_len =
-					cpu_to_le16(le16_to_cpu(de->rec_len) -
-					EXT3_DIR_REC_LEN(de->name_len));
-				de->rec_len = cpu_to_le16(
-						EXT3_DIR_REC_LEN(de->name_len));
-				de = de1;
+		bh2 = ext3_append (handle, dir, &newblock, &err);
+		if (!(bh2))
+			goto cleanup;
+		node2 = (struct dx_node *)(bh2->b_data);
+		entries2 = node2->entries;
+		node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
+		node2->fake.inode = 0;
+		BUFFER_TRACE(frame->bh, "get_write_access");
+		err = ext3_journal_get_write_access(handle, frame->bh);
+		if (err)
+			goto journal_error;
+		if (levels) {
+			unsigned icount1 = icount/2, icount2 = icount - icount1;
+			unsigned hash2 = dx_get_hash(entries + icount1);
+			dxtrace(printk("Split index %i/%i\n", icount1, icount2));
+				
+			BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
+			err = ext3_journal_get_write_access(handle,
+							     frames[0].bh);
+			if (err)
+				goto journal_error;
+				
+			memcpy ((char *) entries2, (char *) (entries + icount1),
+				icount2 * sizeof(struct dx_entry));
+			dx_set_count (entries, icount1);
+			dx_set_count (entries2, icount2);
+			dx_set_limit (entries2, dx_node_limit(dir));
+
+			/* Which index block gets the new entry? */
+			if (at - entries >= icount1) {
+				frame->at = at = at - entries - icount1 + entries2;
+				frame->entries = entries = entries2;
+				swap(frame->bh, bh2);
 			}
-			de->file_type = EXT3_FT_UNKNOWN;
-			if (inode) {
-				de->inode = cpu_to_le32(inode->i_ino);
-				ext3_set_de_type(dir->i_sb, de, inode->i_mode);
-			} else
-				de->inode = 0;
-			de->name_len = namelen;
-			memcpy (de->name, name, namelen);
-			/*
-			 * XXX shouldn't update any times until successful
-			 * completion of syscall, but too many callers depend
-			 * on this.
-			 *
-			 * XXX similarly, too many callers depend on
-			 * ext3_new_inode() setting the times, but error
-			 * recovery deletes the inode, so the worst that can
-			 * happen is that the times are slightly out of date
-			 * and/or different from the directory change time.
-			 */
-			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
-			ext3_mark_inode_dirty(handle, dir);
-			dir->i_version = ++event;
-			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
-			ext3_journal_dirty_metadata(handle, bh);
-			brelse(bh);
-			return 0;
+			dx_insert_block (frames + 0, hash2, newblock);
+			dxtrace(dx_show_index ("node", frames[1].entries));
+			dxtrace(dx_show_index ("node",
+			       ((struct dx_node *) bh2->b_data)->entries));
+			err = ext3_journal_dirty_metadata(handle, bh2);
+			if (err)
+				goto journal_error;
+			brelse (bh2);
+		} else {
+			dxtrace(printk("Creating second level index...\n"));
+			memcpy((char *) entries2, (char *) entries,
+			       icount * sizeof(struct dx_entry));
+			dx_set_limit(entries2, dx_node_limit(dir));
+
+			/* Set up root */
+			dx_set_count(entries, 1);
+			dx_set_block(entries + 0, newblock);
+			((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
+
+			/* Add new access path frame */
+			frame = frames + 1;
+			frame->at = at = at - entries + entries2;
+			frame->entries = entries = entries2;
+			frame->bh = bh2;
+			err = ext3_journal_get_write_access(handle,
+							     frame->bh);
+			if (err)
+				goto journal_error;
 		}
-		offset += le16_to_cpu(de->rec_len);
-		de = (struct ext3_dir_entry_2 *)
-			((char *) de + le16_to_cpu(de->rec_len));
+		ext3_journal_dirty_metadata(handle, frames[0].bh);
 	}
-	brelse (bh);
-	return -ENOSPC;
+	de = do_split(handle, dir, &bh, frame, &hinfo, &err);
+	if (!de)
+		goto cleanup;
+	err = add_dirent_to_buf(handle, dentry, inode, de, bh);
+	bh = 0;
+	goto cleanup;
+	
+journal_error:
+	ext3_std_error(dir->i_sb, err);
+cleanup:
+	if (bh)
+		brelse(bh);
+	dx_release(frames);
+	return err;
 }
+#endif
 
 /*
  * ext3_delete_entry deletes a directory entry by merging it with the
@@ -496,7 +1575,8 @@
 	int err;
 
 	lock_kernel();
-	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);
+	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
 	if (IS_ERR(handle)) {
 		unlock_kernel();
 		return PTR_ERR(handle);
@@ -530,7 +1610,8 @@
 	int err;
 
 	lock_kernel();
-	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);
+	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
 	if (IS_ERR(handle)) {
 		unlock_kernel();
 		return PTR_ERR(handle);
@@ -563,7 +1644,8 @@
 		return -EMLINK;
 
 	lock_kernel();
-	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 3);
+	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3);
 	if (IS_ERR(handle)) {
 		unlock_kernel();
 		return PTR_ERR(handle);
@@ -612,22 +1694,20 @@
 		inode->i_mode |= S_ISGID;
 	ext3_mark_inode_dirty(handle, inode);
 	err = ext3_add_entry (handle, dentry, inode);
-	if (err)
-		goto out_no_entry;
+	if (err) {
+		inode->i_nlink = 0;
+		ext3_mark_inode_dirty(handle, inode);
+		iput (inode);
+		goto out_stop;
+	}
 	dir->i_nlink++;
-	EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
+	ext3_update_dx_flag(dir);
 	ext3_mark_inode_dirty(handle, dir);
 	d_instantiate(dentry, inode);
 out_stop:
 	ext3_journal_stop(handle, dir);
 	unlock_kernel();
 	return err;
-
-out_no_entry:
-	inode->i_nlink = 0;
-	ext3_mark_inode_dirty(handle, inode);
-	iput (inode);
-	goto out_stop;
 }
 
 /*
@@ -894,7 +1974,7 @@
 	ext3_mark_inode_dirty(handle, inode);
 	dir->i_nlink--;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
+	ext3_update_dx_flag(dir);
 	ext3_mark_inode_dirty(handle, dir);
 
 end_rmdir:
@@ -944,7 +2024,7 @@
 	if (retval)
 		goto end_unlink;
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
+	ext3_update_dx_flag(dir);
 	ext3_mark_inode_dirty(handle, dir);
 	inode->i_nlink--;
 	if (!inode->i_nlink)
@@ -972,7 +2052,8 @@
 		return -ENAMETOOLONG;
 
 	lock_kernel();
-	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + 5);
+	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5);
 	if (IS_ERR(handle)) {
 		unlock_kernel();
 		return PTR_ERR(handle);
@@ -998,8 +2079,12 @@
 		 * i_size in generic_commit_write().
 		 */
 		err = page_symlink(inode, symname, l);
-		if (err)
-			goto out_no_entry;
+		if (err) {
+			ext3_dec_count(handle, inode);
+			ext3_mark_inode_dirty(handle, inode);
+			iput (inode);
+			goto out_stop;
+		}
 	} else {
 		inode->i_op = &ext3_fast_symlink_inode_operations;
 		memcpy((char*)&EXT3_I(inode)->i_data,symname,l);
@@ -1012,12 +2097,6 @@
 	ext3_journal_stop(handle, dir);
 	unlock_kernel();
 	return err;
-
-out_no_entry:
-	ext3_dec_count(handle, inode);
-	ext3_mark_inode_dirty(handle, inode);
-	iput (inode);
-	goto out_stop;
 }
 
 static int ext3_link (struct dentry * old_dentry,
@@ -1033,7 +2112,8 @@
 		return -EMLINK;
 	}
 
-	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS);
+	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+					EXT3_INDEX_EXTRA_TRANS_BLOCKS);
 	if (IS_ERR(handle)) {
 		unlock_kernel();
 		return PTR_ERR(handle);
@@ -1073,7 +2153,8 @@
 	old_bh = new_bh = dir_bh = NULL;
 
 	lock_kernel();
-	handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + 2);
+	handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS +
+			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
 	if (IS_ERR(handle)) {
 		unlock_kernel();
 		return PTR_ERR(handle);
@@ -1157,7 +2238,7 @@
 		new_inode->i_ctime = CURRENT_TIME;
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-	EXT3_I(old_dir)->i_flags &= ~EXT3_INDEX_FL;
+	ext3_update_dx_flag(old_dir);
 	if (dir_bh) {
 		BUFFER_TRACE(dir_bh, "get_write_access");
 		ext3_journal_get_write_access(handle, dir_bh);
@@ -1169,7 +2250,7 @@
 			new_inode->i_nlink--;
 		} else {
 			new_dir->i_nlink++;
-			EXT3_I(new_dir)->i_flags &= ~EXT3_INDEX_FL;
+			ext3_update_dx_flag(new_dir);
 			ext3_mark_inode_dirty(handle, new_dir);
 		}
 	}
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Fri Oct 11 21:23:03 2002
+++ b/fs/ext3/super.c	Fri Oct 11 21:23:03 2002
@@ -439,7 +439,7 @@
 		ext3_blkdev_remove(sbi);
 	}
 	clear_ro_after(sb);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(sbi);
 	return;
 }
@@ -762,6 +762,7 @@
 	es->s_mtime = cpu_to_le32(CURRENT_TIME);
 	ext3_update_dynamic_rev(sb);
 	EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
+
 	ext3_commit_super (sb, es, 1);
 	if (test_opt (sb, DEBUG))
 		printk (KERN_INFO
@@ -772,6 +773,7 @@
 			EXT3_BLOCKS_PER_GROUP(sb),
 			EXT3_INODES_PER_GROUP(sb),
 			sbi->s_mount_opt);
+
 	printk(KERN_INFO "EXT3 FS " EXT3FS_VERSION ", " EXT3FS_DATE " on %s, ",
 				sb->s_id);
 	if (EXT3_SB(sb)->s_journal->j_inode == NULL) {
@@ -946,6 +948,7 @@
 	return res;
 }
 
+
 static int ext3_fill_super (struct super_block *sb, void *data, int silent)
 {
 	struct buffer_head * bh;
@@ -974,7 +977,7 @@
 	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(*sbi));
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = EXT3_DEF_RESUID;
@@ -1115,6 +1118,9 @@
 	sbi->s_mount_state = le16_to_cpu(es->s_state);
 	sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
 	sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
+	for (i=0; i < 4; i++)
+		sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
+	sbi->s_def_hash_version = es->s_def_hash_version;
 
 	if (sbi->s_blocks_per_group > blocksize * 8) {
 		printk (KERN_ERR
@@ -1271,7 +1277,7 @@
 	ext3_blkdev_remove(sbi);
 	brelse(bh);
 out_fail:
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(sbi);
 	return -EINVAL;
 }
diff -Nru a/fs/fat/file.c b/fs/fat/file.c
--- a/fs/fat/file.c	Fri Oct 11 21:22:55 2002
+++ b/fs/fat/file.c	Fri Oct 11 21:22:55 2002
@@ -59,7 +59,7 @@
 		BUG();
 		return -EIO;
 	}
-	if (!(iblock % MSDOS_SB(sb)->cluster_size)) {
+	if (!((unsigned long)iblock % MSDOS_SB(sb)->cluster_size)) {
 		int error;
 
 		error = fat_add_cluster(inode);
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Fri Oct 11 21:22:57 2002
+++ b/fs/fat/inode.c	Fri Oct 11 21:22:57 2002
@@ -197,7 +197,7 @@
 		kfree(sbi->options.iocharset);
 		sbi->options.iocharset = NULL;
 	}
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(sbi);
 }
 
@@ -648,7 +648,7 @@
 	sbi = kmalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct msdos_sb_info));
 
 	cvf_format[0] = '\0';
@@ -925,7 +925,7 @@
 	if (sbi->private_data)
 		kfree(sbi->private_data);
 	sbi->private_data = NULL;
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(sbi);
 
 	return error;
@@ -998,7 +998,7 @@
 	return generic_commit_write(file, page, from, to);
 }
 
-static int _fat_bmap(struct address_space *mapping, long block)
+static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,fat_get_block);
 }
diff -Nru a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
--- a/fs/freevxfs/vxfs.h	Fri Oct 11 21:22:58 2002
+++ b/fs/freevxfs/vxfs.h	Fri Oct 11 21:22:59 2002
@@ -261,6 +261,6 @@
  * Get filesystem private data from VFS superblock.
  */
 #define VXFS_SBI(sbp) \
-	((struct vxfs_sb_info *)(sbp)->u.generic_sbp)
+	((struct vxfs_sb_info *)(sbp)->s_fs_info)
 
 #endif /* _VXFS_SUPER_H_ */
diff -Nru a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c
--- a/fs/freevxfs/vxfs_subr.c	Fri Oct 11 21:22:55 2002
+++ b/fs/freevxfs/vxfs_subr.c	Fri Oct 11 21:22:55 2002
@@ -43,7 +43,7 @@
 
 
 static int		vxfs_readpage(struct file *, struct page *);
-static int		vxfs_bmap(struct address_space *, long);
+static sector_t		vxfs_bmap(struct address_space *, sector_t);
 
 struct address_space_operations vxfs_aops = {
 	.readpage =		vxfs_readpage,
@@ -186,8 +186,8 @@
  * Locking status:
  *   We are under the bkl.
  */
-static int
-vxfs_bmap(struct address_space *mapping, long block)
+static sector_t
+vxfs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping, block, vxfs_getblk);
 }
diff -Nru a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
--- a/fs/freevxfs/vxfs_super.c	Fri Oct 11 21:23:03 2002
+++ b/fs/freevxfs/vxfs_super.c	Fri Oct 11 21:23:03 2002
@@ -184,7 +184,7 @@
 #endif
 
 	sbp->s_magic = rsbp->vs_magic;
-	sbp->u.generic_sbp = (void *)infp;
+	sbp->s_fs_info = (void *)infp;
 
 	infp->vsi_raw = rsbp;
 	infp->vsi_bp = bp;
diff -Nru a/fs/hfs/catalog.c b/fs/hfs/catalog.c
--- a/fs/hfs/catalog.c	Fri Oct 11 21:23:02 2002
+++ b/fs/hfs/catalog.c	Fri Oct 11 21:23:02 2002
@@ -158,8 +158,7 @@
 
 static inline void remove_hash(struct hfs_cat_entry *entry)
 {
-	list_del(&entry->hash);
-	INIT_LIST_HEAD(&entry->hash);
+	list_del_init(&entry->hash);
 }
 
 /*
@@ -223,8 +222,7 @@
 {
         if (!(entry->state & HFS_DELETED)) {
 	        entry->state |= HFS_DELETED;
-		list_del(&entry->hash);
-		INIT_LIST_HEAD(&entry->hash);
+		list_del_init(&entry->hash);
 
 	        if (entry->type == HFS_CDR_FIL) {
 		  /* free all extents */
@@ -836,8 +834,7 @@
 		}
 
 		if (!entry->count) {
-		        list_del(&entry->hash);
-			INIT_LIST_HEAD(&entry->hash);
+		        list_del_init(&entry->hash);
 			list_del(&entry->list);
 			list_add(&entry->list, dispose);
 			continue;
diff -Nru a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
--- a/fs/hfs/dir_cap.c	Fri Oct 11 21:22:55 2002
+++ b/fs/hfs/dir_cap.c	Fri Oct 11 21:22:55 2002
@@ -59,30 +59,30 @@
 #define DOT_ROOTINFO	(&hfs_cap_reserved2[0])
 
 struct file_operations hfs_cap_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	cap_readdir,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= cap_readdir,
+	.fsync		= file_fsync,
 };
 
 struct inode_operations hfs_cap_ndir_inode_operations = {
-	create:		hfs_create,
-	lookup:		cap_lookup,
-	unlink:		hfs_unlink,
-	mkdir:		hfs_mkdir,
-	rmdir:		hfs_rmdir,
-	rename:		hfs_rename,
-	setattr:	hfs_notify_change,
+	.create		= hfs_create,
+	.lookup		= cap_lookup,
+	.unlink		= hfs_unlink,
+	.mkdir		= hfs_mkdir,
+	.rmdir		= hfs_rmdir,
+	.rename		= hfs_rename,
+	.setattr	= hfs_notify_change,
 };
 
 struct inode_operations hfs_cap_fdir_inode_operations = {
-	lookup:		cap_lookup,
-	setattr:	hfs_notify_change,
+	.lookup		= cap_lookup,
+	.setattr	= hfs_notify_change,
 };
 
 struct inode_operations hfs_cap_rdir_inode_operations = {
-	create:		hfs_create,
-	lookup:		cap_lookup,
-	setattr:	hfs_notify_change,
+	.create		= hfs_create,
+	.lookup		= cap_lookup,
+	.setattr	= hfs_notify_change,
 };
 
 /*================ File-local functions ================*/
diff -Nru a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
--- a/fs/hfs/dir_dbl.c	Fri Oct 11 21:23:03 2002
+++ b/fs/hfs/dir_dbl.c	Fri Oct 11 21:23:03 2002
@@ -58,19 +58,19 @@
 #define PCNT_ROOTINFO	(&hfs_dbl_reserved2[1])
 
 struct file_operations hfs_dbl_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	dbl_readdir,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= dbl_readdir,
+	.fsync		= file_fsync,
 };
 
 struct inode_operations hfs_dbl_dir_inode_operations = {
-	create:		dbl_create,
-	lookup:		dbl_lookup,
-	unlink:		dbl_unlink,
-	mkdir:		dbl_mkdir,
-	rmdir:		dbl_rmdir,
-	rename:		dbl_rename,
-	setattr:	hfs_notify_change,
+	.create		= dbl_create,
+	.lookup		= dbl_lookup,
+	.unlink		= dbl_unlink,
+	.mkdir		= dbl_mkdir,
+	.rmdir		= dbl_rmdir,
+	.rename		= dbl_rename,
+	.setattr	= hfs_notify_change,
 };
 
 
diff -Nru a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
--- a/fs/hfs/dir_nat.c	Fri Oct 11 21:23:04 2002
+++ b/fs/hfs/dir_nat.c	Fri Oct 11 21:23:04 2002
@@ -64,27 +64,27 @@
 #define ROOTINFO        (&hfs_nat_reserved2[0])
 
 struct file_operations hfs_nat_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	nat_readdir,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= nat_readdir,
+	.fsync		= file_fsync,
 };
 
 struct inode_operations hfs_nat_ndir_inode_operations = {
-	create:		hfs_create,
-	lookup:		nat_lookup,
-	unlink:		hfs_unlink,
-	mkdir:		hfs_mkdir,
-	rmdir:		nat_rmdir,
-	rename:		hfs_rename,
-	setattr:	hfs_notify_change,
+	.create		= hfs_create,
+	.lookup		= nat_lookup,
+	.unlink		= hfs_unlink,
+	.mkdir		= hfs_mkdir,
+	.rmdir		= nat_rmdir,
+	.rename		= hfs_rename,
+	.setattr	= hfs_notify_change,
 };
 
 struct inode_operations hfs_nat_hdir_inode_operations = {
-	create:		hfs_create,
-	lookup:		nat_lookup,
-	unlink:		nat_hdr_unlink,
-	rename:		nat_hdr_rename,
-	setattr:	hfs_notify_change,
+	.create		= hfs_create,
+	.lookup		= nat_lookup,
+	.unlink		= nat_hdr_unlink,
+	.rename		= nat_hdr_rename,
+	.setattr	= hfs_notify_change,
 };
 
 /*================ File-local functions ================*/
diff -Nru a/fs/hfs/file.c b/fs/hfs/file.c
--- a/fs/hfs/file.c	Fri Oct 11 21:22:55 2002
+++ b/fs/hfs/file.c	Fri Oct 11 21:22:55 2002
@@ -34,16 +34,16 @@
 /*================ Global variables ================*/
 
 struct file_operations hfs_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		hfs_file_read,
-	write:		hfs_file_write,
-	mmap:		generic_file_mmap,
-	fsync:		file_fsync,
+	.llseek		= generic_file_llseek,
+	.read		= hfs_file_read,
+	.write		= hfs_file_write,
+	.mmap		= generic_file_mmap,
+	.fsync		= file_fsync,
 };
 
 struct inode_operations hfs_file_inode_operations = {
-	truncate:	hfs_file_truncate,
-	setattr:	hfs_notify_change,
+	.truncate	= hfs_file_truncate,
+	.setattr	= hfs_notify_change,
 };
 
 /*================ Variable-like macros ================*/
diff -Nru a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c
--- a/fs/hfs/file_cap.c	Fri Oct 11 21:22:50 2002
+++ b/fs/hfs/file_cap.c	Fri Oct 11 21:22:50 2002
@@ -47,14 +47,14 @@
 /*================ Global variables ================*/
 
 struct file_operations hfs_cap_info_operations = {
-	llseek:		cap_info_llseek,
-	read:		cap_info_read,
-	write:		cap_info_write,
-	fsync:		file_fsync,
+	.llseek		= cap_info_llseek,
+	.read		= cap_info_read,
+	.write		= cap_info_write,
+	.fsync		= file_fsync,
 };
 
 struct inode_operations hfs_cap_info_inode_operations = {
-	setattr:	hfs_notify_change_cap,
+	.setattr	= hfs_notify_change_cap,
 };
 
 /*================ File-local functions ================*/
diff -Nru a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
--- a/fs/hfs/file_hdr.c	Fri Oct 11 21:23:00 2002
+++ b/fs/hfs/file_hdr.c	Fri Oct 11 21:23:00 2002
@@ -47,20 +47,20 @@
 /*================ Global variables ================*/
 
 struct file_operations hfs_hdr_operations = {
-	llseek:		hdr_llseek,
-	read:		hdr_read,
-	write:		hdr_write,
-	fsync:		file_fsync,
+	.llseek		= hdr_llseek,
+	.read		= hdr_read,
+	.write		= hdr_write,
+	.fsync		= file_fsync,
 };
 
 struct inode_operations hfs_hdr_inode_operations = {
-	setattr:	hfs_notify_change_hdr,
+	.setattr	= hfs_notify_change_hdr,
 };
 
 const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
-	magic:		__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
-	version:	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
-	entries:	6,					/* entries */
+	.magic		= __constant_htonl(HFS_DBL_MAGIC),	/* magic   */
+	.version	= __constant_htonl(HFS_HDR_VERSION_2),	/* version */
+	.entries	= 6,					/* entries */
 	{					/* descr[] */
 		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
 		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
@@ -80,9 +80,9 @@
 };
 
 const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout = {
-	magic:		__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
-	version:	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
-	entries:	5,					/* entries */
+	.magic		= __constant_htonl(HFS_DBL_MAGIC),	/* magic   */
+	.version	= __constant_htonl(HFS_HDR_VERSION_2),	/* version */
+	.entries	= 5,					/* entries */
 	{					/* descr[] */
 		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
 		{HFS_HDR_DATES, offsetof(struct hfs_dbl_hdr, create_time), 16},
@@ -100,9 +100,9 @@
 };
 
 const struct hfs_hdr_layout hfs_nat2_hdr_layout = {
-	magic:		__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
-	version:	__constant_htonl(HFS_HDR_VERSION_2),	/* version */
-	entries:	9,					/* entries */
+	.magic		= __constant_htonl(HFS_DBL_MAGIC),	/* magic   */
+	.version	= __constant_htonl(HFS_HDR_VERSION_2),	/* version */
+	.entries	= 9,					/* entries */
 	{					/* descr[] */
 		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
 		{HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
@@ -128,9 +128,9 @@
 };
 
 const struct hfs_hdr_layout hfs_nat_hdr_layout = {
-	magic:		__constant_htonl(HFS_DBL_MAGIC),	/* magic   */
-	version:	__constant_htonl(HFS_HDR_VERSION_1),	/* version */
-	entries:	5,					/* entries */
+	.magic		= __constant_htonl(HFS_DBL_MAGIC),	/* magic   */
+	.version	= __constant_htonl(HFS_HDR_VERSION_1),	/* version */
+	.entries	= 5,					/* entries */
 	{					/* descr[] */
 		{HFS_HDR_FNAME, offsetof(struct hfs_dbl_hdr, real_name),   ~0},
 		{HFS_HDR_COMNT, offsetof(struct hfs_dbl_hdr, comment),      0},
diff -Nru a/fs/hfs/inode.c b/fs/hfs/inode.c
--- a/fs/hfs/inode.c	Fri Oct 11 21:23:05 2002
+++ b/fs/hfs/inode.c	Fri Oct 11 21:23:05 2002
@@ -242,17 +242,17 @@
 	return cont_prepare_write(page,from,to,hfs_get_block,
 		&HFS_I(page->mapping->host)->mmu_private);
 }
-static int hfs_bmap(struct address_space *mapping, long block)
+static sector_t hfs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,hfs_get_block);
 }
 struct address_space_operations hfs_aops = {
-	readpage: hfs_readpage,
-	writepage: hfs_writepage,
-	sync_page: block_sync_page,
-	prepare_write: hfs_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: hfs_bmap
+	.readpage = hfs_readpage,
+	.writepage = hfs_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = hfs_prepare_write,
+	.commit_write = generic_commit_write,
+	.bmap = hfs_bmap
 };
 
 /*
diff -Nru a/fs/hfs/super.c b/fs/hfs/super.c
--- a/fs/hfs/super.c	Fri Oct 11 21:22:55 2002
+++ b/fs/hfs/super.c	Fri Oct 11 21:22:55 2002
@@ -87,13 +87,13 @@
 /*================ Global variables ================*/
 
 static struct super_operations hfs_super_operations = { 
-	alloc_inode:	hfs_alloc_inode,
-	destroy_inode:	hfs_destroy_inode,
-	read_inode:	hfs_read_inode,
-	put_inode:	hfs_put_inode,
-	put_super:	hfs_put_super,
-	write_super:	hfs_write_super,
-	statfs:		hfs_statfs,
+	.alloc_inode	= hfs_alloc_inode,
+	.destroy_inode	= hfs_destroy_inode,
+	.read_inode	= hfs_read_inode,
+	.put_inode	= hfs_put_inode,
+	.put_super	= hfs_put_super,
+	.write_super	= hfs_write_super,
+	.statfs		= hfs_statfs,
 };
 
 /*================ File-local variables ================*/
@@ -105,11 +105,11 @@
 }
 
 static struct file_system_type hfs_fs = {
-	owner:		THIS_MODULE,
-	name:		"hfs",
-	get_sb:		hfs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "hfs",
+	.get_sb		= hfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 /*================ File-local functions ================*/
@@ -181,8 +181,8 @@
 	/* release the MDB's resources */
 	hfs_mdb_put(mdb, sb->s_flags & MS_RDONLY);
 
-	kfree(sb->u.generic_sbp);
-	sb->u.generic_sbp = NULL;
+	kfree(sb->s_fs_info);
+	sb->s_fs_info = NULL;
 }
 
 /*
@@ -459,7 +459,7 @@
 	sbi = kmalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	s->u.generic_sbp = sbi;
+	s->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct hfs_sb_info));
 
 	if (!parse_options((char *)data, sbi, &part)) {
@@ -533,7 +533,7 @@
 	hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
 bail2:
 	kfree(sbi);
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	return -EINVAL;	
 }
 
diff -Nru a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c
--- a/fs/hfs/sysdep.c	Fri Oct 11 21:23:00 2002
+++ b/fs/hfs/sysdep.c	Fri Oct 11 21:23:00 2002
@@ -25,10 +25,10 @@
 static void hfs_dentry_iput(struct dentry *, struct inode *);
 struct dentry_operations hfs_dentry_operations =
 {
-	d_revalidate:	hfs_revalidate_dentry,	
-	d_hash:		hfs_hash_dentry,
-	d_compare:	hfs_compare_dentry,
-	d_iput:		hfs_dentry_iput,
+	.d_revalidate	= hfs_revalidate_dentry,	
+	.d_hash		= hfs_hash_dentry,
+	.d_compare	= hfs_compare_dentry,
+	.d_iput		= hfs_dentry_iput,
 };
 
 /*
diff -Nru a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c
--- a/fs/hpfs/dentry.c	Fri Oct 11 21:23:04 2002
+++ b/fs/hpfs/dentry.c	Fri Oct 11 21:23:04 2002
@@ -50,8 +50,8 @@
 }
 
 struct dentry_operations hpfs_dentry_operations = {
-	d_hash:		hpfs_hash_dentry,
-	d_compare:	hpfs_compare_dentry,
+	.d_hash		= hpfs_hash_dentry,
+	.d_compare	= hpfs_compare_dentry,
 };
 
 void hpfs_set_dentry_operations(struct dentry *dentry)
diff -Nru a/fs/hpfs/file.c b/fs/hpfs/file.c
--- a/fs/hpfs/file.c	Fri Oct 11 21:22:57 2002
+++ b/fs/hpfs/file.c	Fri Oct 11 21:22:57 2002
@@ -111,17 +111,17 @@
 	return cont_prepare_write(page,from,to,hpfs_get_block,
 		&hpfs_i(page->mapping->host)->mmu_private);
 }
-static int _hpfs_bmap(struct address_space *mapping, long block)
+static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,hpfs_get_block);
 }
 struct address_space_operations hpfs_aops = {
-	readpage: hpfs_readpage,
-	writepage: hpfs_writepage,
-	sync_page: block_sync_page,
-	prepare_write: hpfs_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: _hpfs_bmap
+	.readpage = hpfs_readpage,
+	.writepage = hpfs_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = hpfs_prepare_write,
+	.commit_write = generic_commit_write,
+	.bmap = _hpfs_bmap
 };
 
 ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
diff -Nru a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
--- a/fs/hpfs/hpfs_fn.h	Fri Oct 11 21:23:00 2002
+++ b/fs/hpfs/hpfs_fn.h	Fri Oct 11 21:23:00 2002
@@ -296,7 +296,7 @@
 
 static inline struct hpfs_sb_info *hpfs_sb(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 /* super.c */
diff -Nru a/fs/hpfs/inode.c b/fs/hpfs/inode.c
--- a/fs/hpfs/inode.c	Fri Oct 11 21:22:55 2002
+++ b/fs/hpfs/inode.c	Fri Oct 11 21:22:55 2002
@@ -14,47 +14,47 @@
 
 static struct file_operations hpfs_file_ops =
 {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		hpfs_file_write,
-	mmap:		generic_file_mmap,
-	open:		hpfs_open,
-	release:	hpfs_file_release,
-	fsync:		hpfs_file_fsync,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= hpfs_file_write,
+	.mmap		= generic_file_mmap,
+	.open		= hpfs_open,
+	.release	= hpfs_file_release,
+	.fsync		= hpfs_file_fsync,
+	.sendfile	= generic_file_sendfile,
 };
 
 static struct inode_operations hpfs_file_iops =
 {
-	truncate:	hpfs_truncate,
-	setattr:	hpfs_notify_change,
+	.truncate	= hpfs_truncate,
+	.setattr	= hpfs_notify_change,
 };
 
 static struct file_operations hpfs_dir_ops =
 {
-	llseek:		hpfs_dir_lseek,
-	read:		generic_read_dir,
-	readdir:	hpfs_readdir,
-	open:		hpfs_open,
-	release:	hpfs_dir_release,
-	fsync:		hpfs_file_fsync,
+	.llseek		= hpfs_dir_lseek,
+	.read		= generic_read_dir,
+	.readdir	= hpfs_readdir,
+	.open		= hpfs_open,
+	.release	= hpfs_dir_release,
+	.fsync		= hpfs_file_fsync,
 };
 
 static struct inode_operations hpfs_dir_iops =
 {
-	create:		hpfs_create,
-	lookup:		hpfs_lookup,
-	unlink:		hpfs_unlink,
-	symlink:	hpfs_symlink,
-	mkdir:		hpfs_mkdir,
-	rmdir:		hpfs_rmdir,
-	mknod:		hpfs_mknod,
-	rename:		hpfs_rename,
-	setattr:	hpfs_notify_change,
+	.create		= hpfs_create,
+	.lookup		= hpfs_lookup,
+	.unlink		= hpfs_unlink,
+	.symlink	= hpfs_symlink,
+	.mkdir		= hpfs_mkdir,
+	.rmdir		= hpfs_rmdir,
+	.mknod		= hpfs_mknod,
+	.rename		= hpfs_rename,
+	.setattr	= hpfs_notify_change,
 };
 
 struct address_space_operations hpfs_symlink_aops = {
-	readpage:	hpfs_symlink_readpage
+	.readpage	= hpfs_symlink_readpage
 };
 
 void hpfs_read_inode(struct inode *i)
diff -Nru a/fs/hpfs/super.c b/fs/hpfs/super.c
--- a/fs/hpfs/super.c	Fri Oct 11 21:23:00 2002
+++ b/fs/hpfs/super.c	Fri Oct 11 21:23:00 2002
@@ -105,7 +105,7 @@
 	if (sbi->sb_cp_table) kfree(sbi->sb_cp_table);
 	if (sbi->sb_bmp_dir) kfree(sbi->sb_bmp_dir);
 	unmark_dirty(s);
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	kfree(sbi);
 }
 
@@ -206,13 +206,13 @@
 
 static struct super_operations hpfs_sops =
 {
-	alloc_inode:	hpfs_alloc_inode,
-	destroy_inode:	hpfs_destroy_inode,
-        read_inode:	hpfs_read_inode,
-	delete_inode:	hpfs_delete_inode,
-	put_super:	hpfs_put_super,
-	statfs:		hpfs_statfs,
-	remount_fs:	hpfs_remount_fs,
+	.alloc_inode	= hpfs_alloc_inode,
+	.destroy_inode	= hpfs_destroy_inode,
+        .read_inode	= hpfs_read_inode,
+	.delete_inode	= hpfs_delete_inode,
+	.put_super	= hpfs_put_super,
+	.statfs		= hpfs_statfs,
+	.remount_fs	= hpfs_remount_fs,
 };
 
 /*
@@ -440,7 +440,7 @@
 	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	s->u.generic_sbp = sbi;
+	s->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(*sbi));
 
 	sbi->sb_bmp_dir = NULL;
@@ -626,7 +626,7 @@
 bail0:
 	if (sbi->sb_bmp_dir) kfree(sbi->sb_bmp_dir);
 	if (sbi->sb_cp_table) kfree(sbi->sb_cp_table);
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	kfree(sbi);
 	return -EINVAL;
 }
@@ -638,11 +638,11 @@
 }
 
 static struct file_system_type hpfs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"hpfs",
-	get_sb:		hpfs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "hpfs",
+	.get_sb		= hpfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_hpfs_fs(void)
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Fri Oct 11 21:23:05 2002
+++ b/fs/inode.c	Fri Oct 11 21:23:05 2002
@@ -101,14 +101,6 @@
 	if (inode) {
 		struct address_space * const mapping = &inode->i_data;
 
-		inode->i_security = NULL;
-		if (security_ops->inode_alloc_security(inode)) {
-			if (inode->i_sb->s_op->destroy_inode)
-				inode->i_sb->s_op->destroy_inode(inode);
-			else
-				kmem_cache_free(inode_cachep, (inode));
-			return NULL;
-		}
 		inode->i_sb = sb;
 		inode->i_dev = sb->s_dev;
 		inode->i_blkbits = sb->s_blocksize_bits;
@@ -127,6 +119,14 @@
 		inode->i_pipe = NULL;
 		inode->i_bdev = NULL;
 		inode->i_cdev = NULL;
+		inode->i_security = NULL;
+		if (security_ops->inode_alloc_security(inode)) {
+			if (inode->i_sb->s_op->destroy_inode)
+				inode->i_sb->s_op->destroy_inode(inode);
+			else
+				kmem_cache_free(inode_cachep, (inode));
+			return NULL;
+		}
 
 		mapping->a_ops = &empty_aops;
  		mapping->host = inode;
@@ -526,7 +526,7 @@
 	inode->i_state &= ~(I_LOCK|I_NEW);
 	wake_up_inode(inode);
 }
-
+EXPORT_SYMBOL(unlock_new_inode);
 
 /*
  * This is called without the inode lock held.. Be careful.
@@ -686,15 +686,29 @@
 	return inode;
 }
 
-/*
- * This is iget without the read_inode portion of get_new_inode
- * the filesystem gets back a new locked and hashed inode and gets
- * to fill it in before unlocking it via unlock_new_inode().
- */
-struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data)
+/**
+ * ifind - internal function, you want ilookup5() or iget5().
+ * @sb:		super block of file system to search
+ * @hashval:	hash value (usually inode number) to search for
+ * @test:	callback used for comparisons between inodes
+ * @data:	opaque data pointer to pass to @test
+ *
+ * ifind() searches for the inode specified by @hashval and @data in the inode
+ * cache. This is a generalized version of ifind_fast() for file systems where
+ * the inode number is not sufficient for unique identification of an inode.
+ *
+ * If the inode is in the cache, the inode is returned with an incremented
+ * reference count.
+ *
+ * Otherwise NULL is returned.
+ *
+ * Note, @test is called with the inode_lock held, so can't sleep.
+ */
+static inline struct inode *ifind(struct super_block *sb,
+		struct list_head *head, int (*test)(struct inode *, void *),
+		void *data)
 {
-	struct list_head * head = inode_hashtable + hash(sb, hashval);
-	struct inode * inode;
+	struct inode *inode;
 
 	spin_lock(&inode_lock);
 	inode = find_inode(sb, head, test, data);
@@ -705,25 +719,27 @@
 		return inode;
 	}
 	spin_unlock(&inode_lock);
-
-	/*
-	 * get_new_inode() will do the right thing, re-trying the search
-	 * in case it had to block at any point.
-	 */
-	return get_new_inode(sb, head, test, set, data);
+	return NULL;
 }
 
-/*
- * Because most filesystems are based on 32-bit unique inode numbers some
- * functions are duplicated to keep iget_locked as a fast path. We can avoid
- * unnecessary pointer dereferences and function calls for this specific
- * case. The duplicated functions (find_inode_fast and get_new_inode_fast)
- * have the same pre- and post-conditions as their original counterparts.
+/**
+ * ifind_fast - internal function, you want ilookup() or iget().
+ * @sb:		super block of file system to search
+ * @ino:	inode number to search for
+ *
+ * ifind_fast() searches for the inode @ino in the inode cache. This is for
+ * file systems where the inode number is sufficient for unique identification
+ * of an inode.
+ *
+ * If the inode is in the cache, the inode is returned with an incremented
+ * reference count.
+ *
+ * Otherwise NULL is returned.
  */
-struct inode *iget_locked(struct super_block *sb, unsigned long ino)
+static inline struct inode *ifind_fast(struct super_block *sb,
+		struct list_head *head, unsigned long ino)
 {
-	struct list_head * head = inode_hashtable + hash(sb, ino);
-	struct inode * inode;
+	struct inode *inode;
 
 	spin_lock(&inode_lock);
 	inode = find_inode_fast(sb, head, ino);
@@ -734,17 +750,131 @@
 		return inode;
 	}
 	spin_unlock(&inode_lock);
+	return NULL;
+}
+
+/**
+ * ilookup5 - search for an inode in the inode cache
+ * @sb:		super block of file system to search
+ * @hashval:	hash value (usually inode number) to search for
+ * @test:	callback used for comparisons between inodes
+ * @data:	opaque data pointer to pass to @test
+ *
+ * ilookup5() uses ifind() to search for the inode specified by @hashval and
+ * @data in the inode cache. This is a generalized version of ilookup() for
+ * file systems where the inode number is not sufficient for unique
+ * identification of an inode.
+ *
+ * If the inode is in the cache, the inode is returned with an incremented
+ * reference count.
+ *
+ * Otherwise NULL is returned.
+ *
+ * Note, @test is called with the inode_lock held, so can't sleep.
+ */
+struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
+		int (*test)(struct inode *, void *), void *data)
+{
+	struct list_head *head = inode_hashtable + hash(sb, hashval);
+
+	return ifind(sb, head, test, data);
+}
+EXPORT_SYMBOL(ilookup5);
 
+/**
+ * ilookup - search for an inode in the inode cache
+ * @sb:		super block of file system to search
+ * @ino:	inode number to search for
+ *
+ * ilookup() uses ifind_fast() to search for the inode @ino in the inode cache.
+ * This is for file systems where the inode number is sufficient for unique
+ * identification of an inode.
+ *
+ * If the inode is in the cache, the inode is returned with an incremented
+ * reference count.
+ *
+ * Otherwise NULL is returned.
+ */
+struct inode *ilookup(struct super_block *sb, unsigned long ino)
+{
+	struct list_head *head = inode_hashtable + hash(sb, ino);
+
+	return ifind_fast(sb, head, ino);
+}
+EXPORT_SYMBOL(ilookup);
+
+/**
+ * iget5_locked - obtain an inode from a mounted file system
+ * @sb:		super block of file system
+ * @hashval:	hash value (usually inode number) to get
+ * @test:	callback used for comparisons between inodes
+ * @set:	callback used to initialize a new struct inode
+ * @data:	opaque data pointer to pass to @test and @set
+ *
+ * This is iget() without the read_inode() portion of get_new_inode().
+ *
+ * iget5_locked() uses ifind() to search for the inode specified by @hashval
+ * and @data in the inode cache and if present it is returned with an increased
+ * reference count. This is a generalized version of iget_locked() for file
+ * systems where the inode number is not sufficient for unique identification
+ * of an inode.
+ *
+ * If the inode is not in cache, get_new_inode() is called to allocate a new
+ * inode and this is returned locked, hashed, and with the I_NEW flag set. The
+ * file system gets to fill it in before unlocking it via unlock_new_inode().
+ *
+ * Note both @test and @set are called with the inode_lock held, so can't sleep.
+ */
+struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
+		int (*test)(struct inode *, void *),
+		int (*set)(struct inode *, void *), void *data)
+{
+	struct list_head *head = inode_hashtable + hash(sb, hashval);
+	struct inode *inode;
+
+	inode = ifind(sb, head, test, data);
+	if (inode)
+		return inode;
+	/*
+	 * get_new_inode() will do the right thing, re-trying the search
+	 * in case it had to block at any point.
+	 */
+	return get_new_inode(sb, head, test, set, data);
+}
+EXPORT_SYMBOL(iget5_locked);
+
+/**
+ * iget_locked - obtain an inode from a mounted file system
+ * @sb:		super block of file system
+ * @ino:	inode number to get
+ *
+ * This is iget() without the read_inode() portion of get_new_inode_fast().
+ *
+ * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
+ * the inode cache and if present it is returned with an increased reference
+ * count. This is for file systems where the inode number is sufficient for
+ * unique identification of an inode.
+ *
+ * If the inode is not in cache, get_new_inode_fast() is called to allocate a
+ * new inode and this is returned locked, hashed, and with the I_NEW flag set.
+ * The file system gets to fill it in before unlocking it via
+ * unlock_new_inode().
+ */
+struct inode *iget_locked(struct super_block *sb, unsigned long ino)
+{
+	struct list_head *head = inode_hashtable + hash(sb, ino);
+	struct inode *inode;
+
+	inode = ifind_fast(sb, head, ino);
+	if (inode)
+		return inode;
 	/*
 	 * get_new_inode_fast() will do the right thing, re-trying the search
 	 * in case it had to block at any point.
 	 */
 	return get_new_inode_fast(sb, head, ino);
 }
-
-EXPORT_SYMBOL(iget5_locked);
 EXPORT_SYMBOL(iget_locked);
-EXPORT_SYMBOL(unlock_new_inode);
 
 /**
  *	__insert_inode_hash - hash an inode
@@ -907,9 +1037,9 @@
  *	file.
  */
  
-int bmap(struct inode * inode, int block)
+sector_t bmap(struct inode * inode, sector_t block)
 {
-	int res = 0;
+	sector_t res = 0;
 	if (inode->i_mapping->a_ops->bmap)
 		res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block);
 	return res;
diff -Nru a/fs/isofs/dir.c b/fs/isofs/dir.c
--- a/fs/isofs/dir.c	Fri Oct 11 21:22:55 2002
+++ b/fs/isofs/dir.c	Fri Oct 11 21:22:55 2002
@@ -254,11 +254,12 @@
 	struct iso_directory_record * tmpde;
 	struct inode *inode = filp->f_dentry->d_inode;
 
-	lock_kernel();
 
-	tmpname = (char *) __get_free_page(GFP_KERNEL);
-	if (!tmpname)
+	tmpname = (char *)__get_free_page(GFP_KERNEL);
+	if (tmpname == NULL)
 		return -ENOMEM;
+
+	lock_kernel();
 	tmpde = (struct iso_directory_record *) (tmpname+1024);
 
 	result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
diff -Nru a/fs/isofs/inode.c b/fs/isofs/inode.c
--- a/fs/isofs/inode.c	Fri Oct 11 21:23:04 2002
+++ b/fs/isofs/inode.c	Fri Oct 11 21:23:04 2002
@@ -34,11 +34,6 @@
 
 #include "zisofs.h"
 
-/*
- * We have no support for "multi volume" CDs, but more and more disks carry
- * wrong information within the volume descriptors.
- */
-#define IGNORE_WRONG_MULTI_VOLUME_SPECS
 #define BEQUIET
 
 #ifdef LEAK_CHECK
@@ -74,7 +69,7 @@
 #endif
 
 	kfree(sbi);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	return;
 }
 
@@ -550,25 +545,12 @@
 	sbi = kmalloc(sizeof(struct isofs_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	s->u.generic_sbp = sbi;
+	s->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct isofs_sb_info));
 
 	if (!parse_options((char *) data, &opt))
 		goto out_freesbi;
 
-#if 0
-	printk("map = %c\n", opt.map);
-	printk("rock = %c\n", opt.rock);
-	printk("joliet = %c\n", opt.joliet);
-	printk("check = %c\n", opt.check);
-	printk("cruft = %c\n", opt.cruft);
-	printk("unhide = %c\n", opt.unhide);
-	printk("blocksize = %d\n", opt.blocksize);
-	printk("gid = %d\n", opt.gid);
-	printk("uid = %d\n", opt.uid);
-	printk("iocharset = %s\n", opt.iocharset);
-#endif
-
 	/*
 	 * First of all, get the hardware blocksize for this device.
 	 * If we don't know what it is, or the hardware blocksize is
@@ -673,19 +655,11 @@
 
 	if(sbi->s_high_sierra){
 	  rootp = (struct iso_directory_record *) h_pri->root_directory_record;
-#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
-	  if (isonum_723 (h_pri->volume_set_size) != 1)
-		goto out_no_support;
-#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */
 	  sbi->s_nzones = isonum_733 (h_pri->volume_space_size);
 	  sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size);
 	  sbi->s_max_size = isonum_733(h_pri->volume_space_size);
 	} else {
 	  rootp = (struct iso_directory_record *) pri->root_directory_record;
-#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
-	  if (isonum_723 (pri->volume_set_size) != 1)
-		goto out_no_support;
-#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */
 	  sbi->s_nzones = isonum_733 (pri->volume_space_size);
 	  sbi->s_log_zone_size = isonum_723 (pri->logical_block_size);
 	  sbi->s_max_size = isonum_733(pri->volume_space_size);
@@ -898,11 +872,6 @@
 	printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n",
 		orig_zonesize, opt.blocksize);
 	goto out_freebh;
-#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
-out_no_support:
-	printk(KERN_WARNING "Multi-volume disks not supported.\n");
-	goto out_freebh;
-#endif
 out_unknown_format:
 	if (!silent)
 		printk(KERN_WARNING "Unable to identify CD-ROM format.\n");
@@ -911,7 +880,7 @@
 	brelse(bh);
 out_freesbi:
 	kfree(sbi);
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	return -EINVAL;
 }
 
@@ -934,21 +903,22 @@
  * or getblk() if they are not.  Returns the number of blocks inserted
  * (0 == error.)
  */
-int isofs_get_blocks(struct inode *inode, sector_t iblock,
+int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
 		     struct buffer_head **bh, unsigned long nblocks)
 {
 	unsigned long b_off;
 	unsigned offset, sect_size;
 	unsigned int firstext;
 	unsigned long nextino;
+	long iblock = (long)iblock_s;
 	int section, rv;
 	struct iso_inode_info *ei = ISOFS_I(inode);
 
 	lock_kernel();
 
 	rv = 0;
-	if (iblock < 0) {
-		printk("isofs_get_blocks: block < 0\n");
+	if (iblock < 0 || iblock != iblock_s) {
+		printk("isofs_get_blocks: block number too large\n");
 		goto abort;
 	}
 
@@ -1044,9 +1014,9 @@
 	return 0;
 }
 
-struct buffer_head *isofs_bread(struct inode *inode, unsigned int block)
+struct buffer_head *isofs_bread(struct inode *inode, sector_t block)
 {
-	unsigned int blknr = isofs_bmap(inode, block);
+	sector_t blknr = isofs_bmap(inode, block);
 	if (!blknr)
 		return NULL;
 	return sb_bread(inode->i_sb, blknr);
@@ -1057,7 +1027,7 @@
 	return block_read_full_page(page,isofs_get_block);
 }
 
-static int _isofs_bmap(struct address_space *mapping, long block)
+static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,isofs_get_block);
 }
@@ -1313,7 +1283,7 @@
 		iso_date(de->date, high_sierra);
 
 	ei->i_first_extent = (isonum_733 (de->extent) +
-					   isonum_711 (de->ext_attr_length));
+			      isonum_711 (de->ext_attr_length));
 
 	/* Set the number of blocks for stat() - should be done before RR */
 	inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */
@@ -1334,51 +1304,30 @@
 	/* get the volume sequence number */
 	volume_seq_no = isonum_723 (de->volume_sequence_number) ;
 
-	/*
-	 * Disable checking if we see any volume number other than 0 or 1.
-	 * We could use the cruft option, but that has multiple purposes, one
-	 * of which is limiting the file size to 16Mb.  Thus we silently allow
-	 * volume numbers of 0 to go through without complaining.
-	 */
-	if (sbi->s_cruft == 'n' &&
-	    (volume_seq_no != 0) && (volume_seq_no != 1)) {
-		printk(KERN_WARNING "Warning: defective CD-ROM "
-		       "(volume sequence number %d). "
-		       "Enabling \"cruft\" mount option.\n", volume_seq_no);
-		sbi->s_cruft = 'y';
-	}
-
 	/* Install the inode operations vector */
-#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
-	if (sbi->s_cruft != 'y' &&
-	    (volume_seq_no != 0) && (volume_seq_no != 1)) {
-		printk(KERN_WARNING "Multi-volume CD somehow got mounted.\n");
-	} else
-#endif /*IGNORE_WRONG_MULTI_VOLUME_SPECS */
-	{
-		if (S_ISREG(inode->i_mode)) {
-			inode->i_fop = &generic_ro_fops;
-			switch ( ei->i_file_format ) {
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_fop = &generic_ro_fops;
+		switch ( ei->i_file_format ) {
 #ifdef CONFIG_ZISOFS
-			case isofs_file_compressed:
-				inode->i_data.a_ops = &zisofs_aops;
-				break;
+		case isofs_file_compressed:
+			inode->i_data.a_ops = &zisofs_aops;
+			break;
 #endif
-			default:
-				inode->i_data.a_ops = &isofs_aops;
-				break;
-			}
-		} else if (S_ISDIR(inode->i_mode)) {
-			inode->i_op = &isofs_dir_inode_operations;
-			inode->i_fop = &isofs_dir_operations;
-		} else if (S_ISLNK(inode->i_mode)) {
-			inode->i_op = &page_symlink_inode_operations;
-			inode->i_data.a_ops = &isofs_symlink_aops;
-		} else
-			/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
-			init_special_inode(inode, inode->i_mode,
-					   kdev_t_to_nr(inode->i_rdev));
-	}
+		default:
+			inode->i_data.a_ops = &isofs_aops;
+			break;
+		}
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &isofs_dir_inode_operations;
+		inode->i_fop = &isofs_dir_operations;
+	} else if (S_ISLNK(inode->i_mode)) {
+		inode->i_op = &page_symlink_inode_operations;
+		inode->i_data.a_ops = &isofs_symlink_aops;
+	} else
+		/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
+		init_special_inode(inode, inode->i_mode,
+				   kdev_t_to_nr(inode->i_rdev));
+
  out:
 	if (tmpde)
 		kfree(tmpde);
diff -Nru a/fs/jbd/commit.c b/fs/jbd/commit.c
--- a/fs/jbd/commit.c	Fri Oct 11 21:23:03 2002
+++ b/fs/jbd/commit.c	Fri Oct 11 21:23:03 2002
@@ -355,8 +355,8 @@
 			}
 			
 			bh = jh2bh(descriptor);
-			jbd_debug(4, "JBD: got buffer %ld (%p)\n",
-				bh->b_blocknr, bh->b_data);
+			jbd_debug(4, "JBD: got buffer %llu (%p)\n",
+				(unsigned long long)bh->b_blocknr, bh->b_data);
 			header = (journal_header_t *)&bh->b_data[0];
 			header->h_magic     = htonl(JFS_MAGIC_NUMBER);
 			header->h_blocktype = htonl(JFS_DESCRIPTOR_BLOCK);
diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c
--- a/fs/jbd/journal.c	Fri Oct 11 21:22:54 2002
+++ b/fs/jbd/journal.c	Fri Oct 11 21:22:54 2002
@@ -1526,7 +1526,7 @@
  * Simple support for retying memory allocations.  Introduced to help to
  * debug different VM deadlock avoidance strategies. 
  */
-void * __jbd_kmalloc (char *where, size_t size, int flags, int retry)
+void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry)
 {
 	void *p;
 	static unsigned long last_warning;
diff -Nru a/fs/jbd/revoke.c b/fs/jbd/revoke.c
--- a/fs/jbd/revoke.c	Fri Oct 11 21:22:53 2002
+++ b/fs/jbd/revoke.c	Fri Oct 11 21:22:53 2002
@@ -388,7 +388,7 @@
 		record = find_revoke_record(journal, bh->b_blocknr);
 		if (record) {
 			jbd_debug(4, "cancelled existing revoke on "
-				  "blocknr %lu\n", bh->b_blocknr);
+				  "blocknr %llu\n", (u64)bh->b_blocknr);
 			list_del(&record->hash);
 			kmem_cache_free(revoke_record_cache, record);
 			did_revoke = 1;
diff -Nru a/fs/jbd/transaction.c b/fs/jbd/transaction.c
--- a/fs/jbd/transaction.c	Fri Oct 11 21:22:55 2002
+++ b/fs/jbd/transaction.c	Fri Oct 11 21:22:55 2002
@@ -1434,9 +1434,10 @@
 	 * by 30x or more...
 	 */
 	if (handle->h_sync) {
+		set_current_state(TASK_RUNNING);
 		do {
 			old_handle_count = transaction->t_handle_count;
-			yield();
+			schedule();
 		} while (old_handle_count != transaction->t_handle_count);
 	}
 
diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
--- a/fs/jffs/inode-v23.c	Fri Oct 11 21:23:00 2002
+++ b/fs/jffs/inode-v23.c	Fri Oct 11 21:23:00 2002
@@ -88,7 +88,7 @@
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-	sb->u.generic_sbp = (void *) 0;
+	sb->s_fs_info = (void *) 0;
 	sb->s_maxbytes = 0xFFFFFFFF;
 
 	/* Build the file system.  */
@@ -111,7 +111,7 @@
 		goto jffs_sb_err3;
 	}
 
-	c = (struct jffs_control *) sb->u.generic_sbp;
+	c = (struct jffs_control *) sb->s_fs_info;
 
 #ifdef CONFIG_JFFS_PROC_FS
 	/* Set up the jffs proc file system.  */
@@ -149,7 +149,7 @@
 jffs_sb_err3:
 	iput(root_inode);
 jffs_sb_err2:
-	jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp);
+	jffs_cleanup_control((struct jffs_control *)sb->s_fs_info);
 jffs_sb_err1:
 	printk(KERN_WARNING "JFFS: Failed to mount device %s.\n",
 	       sb->s_id);
@@ -161,7 +161,7 @@
 static void
 jffs_put_super(struct super_block *sb)
 {
-	struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *) sb->s_fs_info;
 
 	D2(printk("jffs_put_super()\n"));
 
@@ -177,7 +177,7 @@
 
 	D1(printk (KERN_NOTICE "jffs_put_super(): Successfully waited on thread.\n"));
 
-	jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp);
+	jffs_cleanup_control((struct jffs_control *)sb->s_fs_info);
 	D1(printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n",
 	       sb->s_id));
 }
@@ -204,7 +204,7 @@
 	if ((res = inode_change_ok(inode, iattr))) 
 		goto out;
 
-	c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+	c = (struct jffs_control *)inode->i_sb->s_fs_info;
 	fmc = c->fmc;
 
 	D3(printk (KERN_NOTICE "notify_change(): down biglock\n"));
@@ -355,7 +355,7 @@
 		return NULL;
 	}
 
-	c = (struct jffs_control *)sb->u.generic_sbp;
+	c = (struct jffs_control *)sb->s_fs_info;
 
 	inode->i_ino = raw_inode->ino;
 	inode->i_mode = raw_inode->mode;
@@ -382,7 +382,7 @@
 int
 jffs_statfs(struct super_block *sb, struct statfs *buf)
 {
-	struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *) sb->s_fs_info;
 	struct jffs_fmcontrol *fmc;
 
 	lock_kernel();
@@ -436,7 +436,7 @@
 		 new_dir, new_dentry->d_name.name));
 
 	lock_kernel();
-	c = (struct jffs_control *)old_dir->i_sb->u.generic_sbp;
+	c = (struct jffs_control *)old_dir->i_sb->s_fs_info;
 	ASSERT(if (!c) {
 		printk(KERN_ERR "jffs_rename(): The old_dir inode "
 		       "didn't have a reference to a jffs_file struct\n");
@@ -572,7 +572,7 @@
 	struct jffs_file *f;
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info;
 	int j;
 	int ddino;
 	lock_kernel();
@@ -643,7 +643,7 @@
 {
 	struct jffs_file *d;
 	struct jffs_file *f;
-	struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *)dir->i_sb->s_fs_info;
 	int len;
 	int r = 0;
 	const char *name;
@@ -743,7 +743,7 @@
 	int result;
 	struct inode *inode = (struct inode*)page->mapping->host;
 	struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip;
-	struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info;
 	int r;
 	loff_t offset;
 
@@ -919,7 +919,7 @@
 static int
 jffs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *)dir->i_sb->s_fs_info;
 	int ret;
 	D3(printk("***jffs_rmdir()\n"));
 	D3(printk (KERN_NOTICE "rmdir(): down biglock\n"));
@@ -937,7 +937,7 @@
 static int
 jffs_unlink(struct inode *dir, struct dentry *dentry)
 {
-	struct jffs_control *c = (struct jffs_control *)dir->i_sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *)dir->i_sb->s_fs_info;
 	int ret; 
 
 	lock_kernel();
@@ -1561,7 +1561,7 @@
 	D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n",
 		  cmd, arg));
 
-	if (!(c = (struct jffs_control *)inode->i_sb->u.generic_sbp)) {
+	if (!(c = (struct jffs_control *)inode->i_sb->s_fs_info)) {
 		printk(KERN_ERR "JFFS: Bad inode in ioctl() call. "
 		       "(cmd = 0x%08x)\n", cmd);
 		return -EIO;
@@ -1615,9 +1615,9 @@
 
 
 static struct address_space_operations jffs_address_operations = {
-	readpage: jffs_readpage,
-	prepare_write: jffs_prepare_write,
-	commit_write: jffs_commit_write,
+	.readpage	= jffs_readpage,
+	.prepare_write	= jffs_prepare_write,
+	.commit_write	= jffs_commit_write,
 };
 
 static int jffs_fsync(struct file *f, struct dentry *d, int datasync)
@@ -1634,41 +1634,41 @@
 
 static struct file_operations jffs_file_operations =
 {
-	open:		generic_file_open,
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		generic_file_write,
-	ioctl:		jffs_ioctl,
-	mmap:		generic_file_mmap,
-	fsync:		jffs_fsync,
-	sendfile:	generic_file_sendfile,
+	.open		= generic_file_open,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.ioctl		= jffs_ioctl,
+	.mmap		= generic_file_mmap,
+	.fsync		= jffs_fsync,
+	.sendfile	= generic_file_sendfile,
 };
 
 
 static struct inode_operations jffs_file_inode_operations =
 {
-	lookup:  jffs_lookup,          /* lookup */
-	setattr: jffs_setattr,
+	.lookup		= jffs_lookup,          /* lookup */
+	.setattr	= jffs_setattr,
 };
 
 
 static struct file_operations jffs_dir_operations =
 {
-	readdir:	jffs_readdir,
+	.readdir	= jffs_readdir,
 };
 
 
 static struct inode_operations jffs_dir_inode_operations =
 {
-	create:   jffs_create,
-	lookup:   jffs_lookup,
-	unlink:   jffs_unlink,
-	symlink:  jffs_symlink,
-	mkdir:    jffs_mkdir,
-	rmdir:    jffs_rmdir,
-	mknod:    jffs_mknod,
-	rename:   jffs_rename,
-	setattr:  jffs_setattr,
+	.create		= jffs_create,
+	.lookup		= jffs_lookup,
+	.unlink		= jffs_unlink,
+	.symlink	= jffs_symlink,
+	.mkdir		= jffs_mkdir,
+	.rmdir		= jffs_rmdir,
+	.mknod		= jffs_mknod,
+	.rename		= jffs_rename,
+	.setattr	= jffs_setattr,
 };
 
 
@@ -1686,7 +1686,7 @@
 			 "No super block!\n"));
 		return;
 	}
-	c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
+	c = (struct jffs_control *)inode->i_sb->s_fs_info;
 	D3(printk (KERN_NOTICE "read_inode(): down biglock\n"));
 	down(&c->fmc->biglock);
 	if (!(f = jffs_find_file(c, inode->i_ino))) {
@@ -1748,7 +1748,7 @@
 	inode->u.generic_ip = 0;
 	clear_inode(inode);
 	if (inode->i_nlink == 0) {
-		c = (struct jffs_control *) inode->i_sb->u.generic_sbp;
+		c = (struct jffs_control *) inode->i_sb->s_fs_info;
 		f = (struct jffs_file *) jffs_find_file (c, inode->i_ino);
 		jffs_possibly_delete_file(f);
 	}
@@ -1760,7 +1760,7 @@
 void
 jffs_write_super(struct super_block *sb)
 {
-	struct jffs_control *c = (struct jffs_control *)sb->u.generic_sbp;
+	struct jffs_control *c = (struct jffs_control *)sb->s_fs_info;
 	lock_kernel();
 	jffs_garbage_collect_trigger(c);
 	unlock_kernel();
@@ -1768,11 +1768,11 @@
 
 static struct super_operations jffs_ops =
 {
-	read_inode:   jffs_read_inode,
-	delete_inode: jffs_delete_inode,
-	put_super:    jffs_put_super,
-	write_super:  jffs_write_super,
-	statfs:       jffs_statfs,
+	.read_inode	= jffs_read_inode,
+	.delete_inode 	= jffs_delete_inode,
+	.put_super	= jffs_put_super,
+	.write_super	= jffs_write_super,
+	.statfs		= jffs_statfs,
 };
 
 static struct super_block *jffs_get_sb(struct file_system_type *fs_type,
@@ -1782,11 +1782,11 @@
 }
 
 static struct file_system_type jffs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"jffs",
-	get_sb:		jffs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "jffs",
+	.get_sb		= jffs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init
diff -Nru a/fs/jffs/intrep.c b/fs/jffs/intrep.c
--- a/fs/jffs/intrep.c	Fri Oct 11 21:22:59 2002
+++ b/fs/jffs/intrep.c	Fri Oct 11 21:23:00 2002
@@ -614,7 +614,7 @@
 		printk("JFFS: Failed to build file system.\n");
 		goto jffs_build_fs_fail;
 	}
-	sb->u.generic_sbp = (void *)c;
+	sb->s_fs_info = (void *)c;
 	c->building_fs = 0;
 
 	D1(jffs_print_hash_table(c));
@@ -3380,9 +3380,9 @@
 
 			spin_lock_irq(&current->sig->siglock);
 			if (current->sig->shared_pending.head)
-				signr = dequeue_signal(&current->sig->shared_pending, &current->blocked, &info);
+				signr = dequeue_signal(&current->sig->shared_pending, &info);
 			if (!signr)
-				signr = dequeue_signal(&current->pending, &current->blocked, &info);
+				signr = dequeue_signal(&current->pending, &info);
 			spin_unlock_irq(&current->sig->siglock);
 
 			switch(signr) {
diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c
--- a/fs/jffs2/background.c	Fri Oct 11 21:22:50 2002
+++ b/fs/jffs2/background.c	Fri Oct 11 21:22:50 2002
@@ -116,9 +116,9 @@
 
                         spin_lock_irq(&current->sig->siglock);
 			if (current->sig->shared_pending.head)
-				signr = dequeue_signal(&current->sig->shared_pending, &current->blocked, &info);
+				signr = dequeue_signal(&current->sig->shared_pending, &info);
 			if (!signr)
-				signr = dequeue_signal(&current->pending, &current->blocked, &info);
+				signr = dequeue_signal(&current->pending, &info);
                         spin_unlock_irq(&current->sig->siglock);
 
                         switch(signr) {
diff -Nru a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
--- a/fs/jffs2/os-linux.h	Fri Oct 11 21:22:53 2002
+++ b/fs/jffs2/os-linux.h	Fri Oct 11 21:22:53 2002
@@ -18,7 +18,7 @@
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
 #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
 #define OFNI_EDONI_2SFFJ(f)  (&(f)->vfs_inode)
-#define JFFS2_SB_INFO(sb) (sb->u.generic_sbp)
+#define JFFS2_SB_INFO(sb) (sb->s_fs_info)
 #define OFNI_BS_2SFFJ(c)  ((struct super_block *)c->os_priv)
 #elif defined(JFFS2_OUT_OF_KERNEL)
 #define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c
--- a/fs/jffs2/super.c	Fri Oct 11 21:22:55 2002
+++ b/fs/jffs2/super.c	Fri Oct 11 21:22:55 2002
@@ -93,7 +93,7 @@
 	/* For persistence of NFS exports etc. we use the same s_dev
 	   each time we mount the device, don't just use an anonymous
 	   device */
-	sb->u.generic_sbp = p;
+	sb->s_fs_info = p;
 	p->os_priv = sb;
 	sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index);
 
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Fri Oct 11 21:22:50 2002
+++ b/fs/jfs/inode.c	Fri Oct 11 21:22:50 2002
@@ -305,7 +305,7 @@
 	return block_prepare_write(page, from, to, jfs_get_block);
 }
 
-static int jfs_bmap(struct address_space *mapping, long block)
+static sector_t jfs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping, block, jfs_get_block);
 }
diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
--- a/fs/jfs/jfs_incore.h	Fri Oct 11 21:22:52 2002
+++ b/fs/jfs/jfs_incore.h	Fri Oct 11 21:22:52 2002
@@ -162,7 +162,7 @@
 
 static inline struct jfs_sb_info *JFS_SBI(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline int isReadOnly(struct inode *inode)
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Fri Oct 11 21:22:57 2002
+++ b/fs/jfs/super.c	Fri Oct 11 21:22:57 2002
@@ -248,7 +248,7 @@
 	if (!sbi)
 		return -ENOSPC;
 	memset(sbi, 0, sizeof (struct jfs_sb_info));
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 
 	if (!parse_options((char *) data, sb, &newLVSize)) {
 		kfree(sbi);
diff -Nru a/fs/libfs.c b/fs/libfs.c
--- a/fs/libfs.c	Fri Oct 11 21:22:51 2002
+++ b/fs/libfs.c	Fri Oct 11 21:22:51 2002
@@ -208,3 +208,73 @@
 	deactivate_super(s);
 	return ERR_PTR(-ENOMEM);
 }
+
+int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode = old_dentry->d_inode;
+
+	inode->i_nlink++;
+	atomic_inc(&inode->i_count);
+	dget(dentry);
+	d_instantiate(dentry, inode);
+	return 0;
+}
+
+static inline int simple_positive(struct dentry *dentry)
+{
+	return dentry->d_inode && !d_unhashed(dentry);
+}
+
+int simple_empty(struct dentry *dentry)
+{
+	struct dentry *child;
+	int ret = 0;
+
+	spin_lock(&dcache_lock);
+	list_for_each_entry(child, &dentry->d_subdirs, d_child)
+		if (simple_positive(child))
+			goto out;
+	ret = 1;
+out:
+	spin_unlock(&dcache_lock);
+	return ret;
+}
+
+int simple_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode = dentry->d_inode;
+
+	inode->i_nlink--;
+	dput(dentry);
+	return 0;
+}
+
+int simple_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	if (!simple_empty(dentry))
+		return -ENOTEMPTY;
+
+	dentry->d_inode->i_nlink--;
+	simple_unlink(dir, dentry);
+	dir->i_nlink--;
+	return 0;
+}
+
+int simple_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
+{
+	struct inode *inode;
+
+	if (!simple_empty(new_dentry))
+		return -ENOTEMPTY;
+
+	inode = new_dentry->d_inode;
+	if (inode) {
+		inode->i_nlink--;
+		dput(new_dentry);
+	}
+	if (S_ISDIR(old_dentry->d_inode->i_mode)) {
+		old_dir->i_nlink--;
+		new_dir->i_nlink++;
+	}
+	return 0;
+}
diff -Nru a/fs/lockd/svc.c b/fs/lockd/svc.c
--- a/fs/lockd/svc.c	Fri Oct 11 21:23:00 2002
+++ b/fs/lockd/svc.c	Fri Oct 11 21:23:00 2002
@@ -389,5 +389,6 @@
 	.pg_nvers	= NLM_NRVERS,		/* number of entries in nlmsvc_version */
 	.pg_vers	= nlmsvc_version,	/* version table */
 	.pg_name	= "lockd",		/* service name */
+	.pg_class	= "nfsd",		/* share authentication with nfsd */
 	.pg_stats	= &nlmsvc_stats,	/* stats table */
 };
diff -Nru a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
--- a/fs/lockd/svc4proc.c	Fri Oct 11 21:22:55 2002
+++ b/fs/lockd/svc4proc.c	Fri Oct 11 21:22:55 2002
@@ -244,6 +244,7 @@
 	u32		stat;
 
 	dprintk("lockd: TEST_MSG      called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
 		stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
@@ -258,6 +259,7 @@
 	u32		stat;
 
 	dprintk("lockd: LOCK_MSG      called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
 		stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
@@ -272,6 +274,7 @@
 	u32		stat;
 
 	dprintk("lockd: CANCEL_MSG    called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
 		stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
@@ -286,6 +289,7 @@
 	u32		stat;
 
 	dprintk("lockd: UNLOCK_MSG    called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
 		stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
@@ -300,6 +304,7 @@
 	u32		stat;
 
 	dprintk("lockd: GRANTED_MSG   called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
 		stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
diff -Nru a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
--- a/fs/lockd/svcproc.c	Fri Oct 11 21:23:00 2002
+++ b/fs/lockd/svcproc.c	Fri Oct 11 21:23:01 2002
@@ -272,6 +272,7 @@
 	u32		stat;
 
 	dprintk("lockd: TEST_MSG      called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlmsvc_proc_test(rqstp, argp, &res)) == 0)
 		stat = nlmsvc_callback(rqstp, NLMPROC_TEST_RES, &res);
@@ -286,6 +287,7 @@
 	u32		stat;
 
 	dprintk("lockd: LOCK_MSG      called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlmsvc_proc_lock(rqstp, argp, &res)) == 0)
 		stat = nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, &res);
@@ -300,6 +302,7 @@
 	u32		stat;
 
 	dprintk("lockd: CANCEL_MSG    called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlmsvc_proc_cancel(rqstp, argp, &res)) == 0)
 		stat = nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
@@ -314,6 +317,7 @@
 	u32		stat;
 
 	dprintk("lockd: UNLOCK_MSG    called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlmsvc_proc_unlock(rqstp, argp, &res)) == 0)
 		stat = nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
@@ -328,6 +332,7 @@
 	u32		stat;
 
 	dprintk("lockd: GRANTED_MSG   called\n");
+	memset(&res, 0, sizeof(res));
 
 	if ((stat = nlmsvc_proc_granted(rqstp, argp, &res)) == 0)
 		stat = nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
diff -Nru a/fs/minix/inode.c b/fs/minix/inode.c
--- a/fs/minix/inode.c	Fri Oct 11 21:22:59 2002
+++ b/fs/minix/inode.c	Fri Oct 11 21:22:59 2002
@@ -43,7 +43,7 @@
 		brelse(sbi->s_zmap[i]);
 	brelse (sbi->s_sbh);
 	kfree(sbi->s_imap);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(sbi);
 
 	return;
@@ -145,7 +145,7 @@
 	sbi = kmalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	s->u.generic_sbp = sbi;
+	s->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct minix_sb_info));
 
 	/* N.B. These should be compile-time tests.
@@ -288,7 +288,7 @@
 out_bad_sb:
 	printk("MINIX-fs: unable to read superblock\n");
  out:
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	kfree(sbi);
 	return -EINVAL;
 }
@@ -328,7 +328,7 @@
 {
 	return block_prepare_write(page,from,to,minix_get_block);
 }
-static int minix_bmap(struct address_space *mapping, long block)
+static sector_t minix_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,minix_get_block);
 }
diff -Nru a/fs/minix/minix.h b/fs/minix/minix.h
--- a/fs/minix/minix.h	Fri Oct 11 21:23:05 2002
+++ b/fs/minix/minix.h	Fri Oct 11 21:23:05 2002
@@ -87,7 +87,7 @@
 
 static inline struct minix_sb_info *minix_sb(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct minix_inode_info *minix_i(struct inode *inode)
diff -Nru a/fs/mpage.c b/fs/mpage.c
--- a/fs/mpage.c	Fri Oct 11 21:22:54 2002
+++ b/fs/mpage.c	Fri Oct 11 21:22:54 2002
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/kdev_t.h>
 #include <linux/bio.h>
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
diff -Nru a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c
--- a/fs/msdos/msdosfs_syms.c	Fri Oct 11 21:23:00 2002
+++ b/fs/msdos/msdosfs_syms.c	Fri Oct 11 21:23:00 2002
@@ -31,11 +31,11 @@
 }
 
 static struct file_system_type msdos_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"msdos",
-	get_sb:		msdos_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "msdos",
+	.get_sb		= msdos_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_msdos_fs(void)
diff -Nru a/fs/msdos/namei.c b/fs/msdos/namei.c
--- a/fs/msdos/namei.c	Fri Oct 11 21:22:58 2002
+++ b/fs/msdos/namei.c	Fri Oct 11 21:22:58 2002
@@ -189,8 +189,8 @@
 
 
 static struct dentry_operations msdos_dentry_operations = {
-	d_hash:		msdos_hash,
-	d_compare:	msdos_cmp,
+	.d_hash		= msdos_hash,
+	.d_compare	= msdos_cmp,
 };
 
 /*
@@ -590,13 +590,13 @@
 
 /* The public inode operations for the msdos fs */
 struct inode_operations msdos_dir_inode_operations = {
-	create:		msdos_create,
-	lookup:		msdos_lookup,
-	unlink:		msdos_unlink,
-	mkdir:		msdos_mkdir,
-	rmdir:		msdos_rmdir,
-	rename:		msdos_rename,
-	setattr:	fat_notify_change,
+	.create		= msdos_create,
+	.lookup		= msdos_lookup,
+	.unlink		= msdos_unlink,
+	.mkdir		= msdos_mkdir,
+	.rmdir		= msdos_rmdir,
+	.rename		= msdos_rename,
+	.setattr	= fat_notify_change,
 };
 
 int msdos_fill_super(struct super_block *sb,void *data, int silent)
diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
--- a/fs/ncpfs/inode.c	Fri Oct 11 21:22:58 2002
+++ b/fs/ncpfs/inode.c	Fri Oct 11 21:22:58 2002
@@ -401,7 +401,7 @@
 	server = kmalloc(sizeof(struct ncp_server), GFP_KERNEL);
 	if (!server)
 		return -ENOMEM;
-	sb->u.generic_sbp = server;
+	sb->s_fs_info = server;
 	memset(server, 0, sizeof(struct ncp_server));
 
 	error = -EFAULT;
@@ -668,7 +668,7 @@
 	 */
 	fput(ncp_filp);
 out:
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(server);
 	return error;
 }
@@ -707,7 +707,7 @@
 	if (server->auth.object_name)
 		ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
 	vfree(server->packet);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(server);
 }
 
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Fri Oct 11 21:22:58 2002
+++ b/fs/nfs/dir.c	Fri Oct 11 21:22:58 2002
@@ -107,7 +107,7 @@
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
 
  again:
-	error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, page,
+	error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
 					  NFS_SERVER(inode)->dtsize, desc->plus);
 	if (error < 0) {
 		/* We requested READDIRPLUS, but the server doesn't grok it */
@@ -130,7 +130,6 @@
 	return 0;
  error:
 	SetPageError(page);
-	kunmap(page);
 	unlock_page(page);
 	invalidate_inode_pages(inode->i_mapping);
 	desc->error = error;
@@ -341,7 +340,7 @@
 		status = -ENOMEM;
 		goto out;
 	}
-	desc->error = NFS_PROTO(inode)->readdir(inode, cred, desc->target,
+	desc->error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->target,
 						page,
 						NFS_SERVER(inode)->dtsize,
 						desc->plus);
@@ -1022,16 +1021,23 @@
 	struct nfs_fattr sym_attr;
 	struct nfs_fh sym_fh;
 	struct qstr qsymname;
-	unsigned int maxlen;
 	int error;
 
 	dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
 		dir->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
-	maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
-	if (strlen(symname) > maxlen)
-		goto out;
+	switch (NFS_PROTO(dir)->version) {
+		case 2:
+			if (strlen(symname) > NFS2_MAXPATHLEN)
+				goto out;
+			break;
+		case 3:
+			if (strlen(symname) > NFS3_MAXPATHLEN)
+				goto out;
+		default:
+			break;
+	}
 
 #ifdef NFS_PARANOIA
 if (dentry->d_inode)
diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Fri Oct 11 21:23:00 2002
+++ b/fs/nfs/file.c	Fri Oct 11 21:23:00 2002
@@ -35,15 +35,17 @@
 #define NFSDBG_FACILITY		NFSDBG_FILE
 
 static int  nfs_file_mmap(struct file *, struct vm_area_struct *);
-static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *);
-static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
+static ssize_t nfs_file_read(struct kiocb *, char *, size_t, loff_t);
+static ssize_t nfs_file_write(struct kiocb *, const char *, size_t, loff_t);
 static int  nfs_file_flush(struct file *);
 static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);
 
 struct file_operations nfs_file_operations = {
 	.llseek		= remote_llseek,
-	.read		= nfs_file_read,
-	.write		= nfs_file_write,
+	.read		= do_sync_read,
+	.write		= do_sync_write,
+	.aio_read		= nfs_file_read,
+	.aio_write		= nfs_file_write,
 	.mmap		= nfs_file_mmap,
 	.open		= nfs_open,
 	.flush		= nfs_file_flush,
@@ -89,19 +91,19 @@
 }
 
 static ssize_t
-nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
+nfs_file_read(struct kiocb *iocb, char * buf, size_t count, loff_t pos)
 {
-	struct dentry * dentry = file->f_dentry;
+	struct dentry * dentry = iocb->ki_filp->f_dentry;
 	struct inode * inode = dentry->d_inode;
 	ssize_t result;
 
 	dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		(unsigned long) count, (unsigned long) *ppos);
+		(unsigned long) count, (unsigned long) pos);
 
 	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (!result)
-		result = generic_file_read(file, buf, count, ppos);
+		result = generic_file_aio_read(iocb, buf, count, pos);
 	return result;
 }
 
@@ -209,15 +211,15 @@
  * Write to a file (through the page cache).
  */
 static ssize_t
-nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+nfs_file_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos)
 {
-	struct dentry * dentry = file->f_dentry;
+	struct dentry * dentry = iocb->ki_filp->f_dentry;
 	struct inode * inode = dentry->d_inode;
 	ssize_t result;
 
 	dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		inode->i_ino, (unsigned long) count, (unsigned long) *ppos);
+		inode->i_ino, (unsigned long) count, (unsigned long) pos);
 
 	result = -EBUSY;
 	if (IS_SWAPFILE(inode))
@@ -230,7 +232,7 @@
 	if (!count)
 		goto out;
 
-	result = generic_file_write(file, buf, count, ppos);
+	result = generic_file_aio_write(iocb, buf, count, pos);
 out:
 	return result;
 
diff -Nru a/fs/nfs/flushd.c b/fs/nfs/flushd.c
--- a/fs/nfs/flushd.c	Fri Oct 11 21:23:00 2002
+++ b/fs/nfs/flushd.c	Fri Oct 11 21:23:00 2002
@@ -171,7 +171,7 @@
 			nfs_pagein_list(&head, server->rpages);
 			continue;
 		}
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 		if (nfs_scan_lru_commit_timeout(server, &head)) {
 			spin_unlock(&nfs_wreq_lock);
 			nfs_commit_list(&head, FLUSH_AGING);
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Fri Oct 11 21:23:03 2002
+++ b/fs/nfs/inode.c	Fri Oct 11 21:23:03 2002
@@ -716,12 +716,14 @@
 		inode->i_mtime = nfs_time_to_secs(new_mtime);
 		NFS_MTIME_UPDATE(inode) = fattr->timestamp;
 		NFS_CACHE_ISIZE(inode) = new_size;
+		if (fattr->valid & NFS_ATTR_FATTR_V4)
+			NFS_CHANGE_ATTR(inode) = fattr->change_attr;
 		inode->i_size = new_isize;
 		inode->i_mode = fattr->mode;
 		inode->i_nlink = fattr->nlink;
 		inode->i_uid = fattr->uid;
 		inode->i_gid = fattr->gid;
-		if (fattr->valid & NFS_ATTR_FATTR_V3) {
+		if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 			/*
 			 * report the blocks in 512byte units
 			 */
@@ -781,7 +783,7 @@
 	if (error)
 		goto out;
 
-	error = NFS_PROTO(inode)->setattr(inode, &fattr, attr);
+	error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
 	if (error)
 		goto out;
 	/*
@@ -1067,12 +1069,25 @@
 		invalid = 1;
 	}
 
+	if ((fattr->valid & NFS_ATTR_FATTR_V4)
+	    && NFS_CHANGE_ATTR(inode) != fattr->change_attr) {
+#ifdef NFS_DEBUG_VERBOSE
+		printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n",
+		       inode->i_sb->s_id, inode->i_ino);
+#endif
+		invalid = 1;
+	}
+
 	/* Check Weak Cache Consistency data.
 	 * If size and mtime match the pre-operation values, we can
 	 * assume that any attribute changes were caused by our NFS
          * operation, so there's no need to invalidate the caches.
          */
-        if ((fattr->valid & NFS_ATTR_WCC)
+	if ((fattr->valid & NFS_ATTR_PRE_CHANGE)
+	    && NFS_CHANGE_ATTR(inode) == fattr->pre_change_attr) {
+		invalid = 0;
+	}
+	else if ((fattr->valid & NFS_ATTR_WCC)
 	    && NFS_CACHE_ISIZE(inode) == fattr->pre_size
 	    && NFS_CACHE_MTIME(inode) == fattr->pre_mtime) {
 		invalid = 0;
@@ -1110,12 +1125,15 @@
 		}
 	}
 
+	if (fattr->valid & NFS_ATTR_FATTR_V4)
+		NFS_CHANGE_ATTR(inode) = fattr->change_attr;
+
 	inode->i_mode = fattr->mode;
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
 	inode->i_gid = fattr->gid;
 
-	if (fattr->valid & NFS_ATTR_FATTR_V3) {
+	if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 		/*
 		 * report the blocks in 512byte units
 		 */
@@ -1167,7 +1185,7 @@
 
 static int nfs_set_super(struct super_block *s, void *data)
 {
-	s->u.generic_sbp = data;
+	s->s_fs_info = data;
 	return set_anon_super(s, data);
 }
  
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Fri Oct 11 21:22:55 2002
+++ b/fs/nfs/nfs2xdr.c	Fri Oct 11 21:22:55 2002
@@ -107,7 +107,7 @@
 	fattr->du.nfs2.blocksize = ntohl(*p++);
 	fattr->rdev = ntohl(*p++);
 	fattr->du.nfs2.blocks = ntohl(*p++);
-	fattr->fsid = ntohl(*p++);
+	fattr->fsid_u.nfs3 = ntohl(*p++);
 	fattr->fileid = ntohl(*p++);
 	p = xdr_decode_time(p, &fattr->atime);
 	p = xdr_decode_time(p, &fattr->mtime);
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Fri Oct 11 21:22:58 2002
+++ b/fs/nfs/nfs3proc.c	Fri Oct 11 21:22:58 2002
@@ -14,6 +14,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
 #include <linux/smp_lock.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
@@ -53,6 +54,17 @@
 #define rpc_call_sync(clnt, msg, flags) \
 		nfs3_rpc_wrapper(clnt, msg, flags)
 
+static int
+nfs3_async_handle_jukebox(struct rpc_task *task)
+{
+	if (task->tk_status != -EJUKEBOX)
+		return 0;
+	task->tk_status = 0;
+	rpc_restart_call(task);
+	rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
+	return 1;
+}
+
 /*
  * Bare-bones access to getattr: this is for nfs_read_super.
  */
@@ -86,9 +98,10 @@
 }
 
 static int
-nfs3_proc_setattr(struct inode *inode, struct nfs_fattr *fattr,
+nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 			struct iattr *sattr)
 {
+	struct inode *inode = dentry->d_inode;
 	struct nfs3_sattrargs	arg = {
 		.fh		= NFS_FH(inode),
 		.sattr		= sattr,
@@ -390,16 +403,20 @@
 	return 0;
 }
 
-static void
-nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
+static int
+nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
 {
+	struct rpc_message *msg = &task->tk_msg;
 	struct nfs_fattr	*dir_attr;
 
+	if (nfs3_async_handle_jukebox(task))
+		return 1;
 	if (msg->rpc_argp) {
 		dir_attr = (struct nfs_fattr*)msg->rpc_resp;
 		nfs_refresh_inode(dir->d_inode, dir_attr);
 		kfree(msg->rpc_argp);
 	}
+	return 0;
 }
 
 static int
@@ -543,9 +560,10 @@
  * readdirplus.
  */
 static int
-nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred,
+nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 		  u64 cookie, struct page *page, unsigned int count, int plus)
 {
+	struct inode		*dir = dentry->d_inode;
 	struct nfs_fattr	dir_attr;
 	u32			*verf = NFS_COOKIEVERF(dir);
 	struct nfs3_readdirargs	arg = {
@@ -644,6 +662,146 @@
 
 extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
 
+static void
+nfs3_read_done(struct rpc_task *task)
+{
+	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
+
+	if (nfs3_async_handle_jukebox(task))
+		return;
+	nfs_readpage_result(task, data->u.v3.res.count, data->u.v3.res.eof);
+}
+
+static void
+nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+{
+	struct rpc_task		*task = &data->task;
+	struct inode		*inode = data->inode;
+	struct nfs_page		*req;
+	int			flags;
+	struct rpc_message	msg;
+	
+	req = nfs_list_entry(data->pages.next);
+	data->u.v3.args.fh     = NFS_FH(inode);
+	data->u.v3.args.offset = req_offset(req) + req->wb_offset;
+	data->u.v3.args.pgbase = req->wb_offset;
+	data->u.v3.args.pages  = data->pagevec;
+	data->u.v3.args.count  = count;
+	data->u.v3.res.fattr   = &data->fattr;
+	data->u.v3.res.count   = count;
+	data->u.v3.res.eof     = 0;
+	
+	/* N.B. Do we need to test? Never called for swapfile inode */
+	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_readdata_release;
+
+	msg.rpc_proc = NFS3PROC_READ;
+	msg.rpc_argp = &data->u.v3.args;
+	msg.rpc_resp = &data->u.v3.res;
+	msg.rpc_cred = data->cred;
+	rpc_call_setup(&data->task, &msg, 0);
+}
+
+static void
+nfs3_write_done(struct rpc_task *task)
+{
+	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+
+	if (nfs3_async_handle_jukebox(task))
+		return;
+	nfs_writeback_done(task, data->u.v3.args.stable,
+			   data->u.v3.args.count, data->u.v3.res.count);
+}
+
+static void
+nfs3_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
+{
+	struct rpc_task		*task = &data->task;
+	struct inode		*inode = data->inode;
+	struct nfs_page		*req;
+	int			stable;
+	int			flags;
+	struct rpc_message	msg;
+
+	if (how & FLUSH_STABLE) {
+		if (!NFS_I(inode)->ncommit)
+			stable = NFS_FILE_SYNC;
+		else
+			stable = NFS_DATA_SYNC;
+	} else
+		stable = NFS_UNSTABLE;
+	
+	req = nfs_list_entry(data->pages.next);
+	data->u.v3.args.fh     = NFS_FH(inode);
+	data->u.v3.args.offset = req_offset(req) + req->wb_offset;
+	data->u.v3.args.pgbase = req->wb_offset;
+	data->u.v3.args.count  = count;
+	data->u.v3.args.stable = stable;
+	data->u.v3.args.pages  = data->pagevec;
+	data->u.v3.res.fattr   = &data->fattr;
+	data->u.v3.res.count   = count;
+	data->u.v3.res.verf    = &data->verf;
+
+	/* Set the initial flags for the task.  */
+	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs3_write_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_writedata_release;
+
+	msg.rpc_proc = NFS3PROC_WRITE;
+	msg.rpc_argp = &data->u.v3.args;
+	msg.rpc_resp = &data->u.v3.res;
+	msg.rpc_cred = data->cred;
+	rpc_call_setup(&data->task, &msg, 0);
+}
+
+static void
+nfs3_commit_done(struct rpc_task *task)
+{
+	if (nfs3_async_handle_jukebox(task))
+		return;
+	nfs_commit_done(task);
+}
+
+static void
+nfs3_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
+{
+	struct rpc_task		*task = &data->task;
+	struct inode		*inode = data->inode;
+	int			flags;
+	struct rpc_message	msg;
+
+	data->u.v3.args.fh     = NFS_FH(data->inode);
+	data->u.v3.args.offset = start;
+	data->u.v3.args.count  = len;
+	data->u.v3.res.count   = len;
+	data->u.v3.res.fattr   = &data->fattr;
+	data->u.v3.res.verf    = &data->verf;
+	
+	/* Set the initial flags for the task.  */
+	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_writedata_release;
+	
+	msg.rpc_proc = NFS3PROC_COMMIT;
+	msg.rpc_argp = &data->u.v3.args;
+	msg.rpc_resp = &data->u.v3.res;
+	msg.rpc_cred = data->cred;
+	rpc_call_setup(&data->task, &msg, 0);
+}
+
 struct nfs_rpc_ops	nfs_v3_clientops = {
 	.version	= 3,			/* protocol version */
 	.getroot	= nfs3_proc_get_root,
@@ -667,4 +825,7 @@
 	.mknod		= nfs3_proc_mknod,
 	.statfs		= nfs3_proc_statfs,
 	.decode_dirent	= nfs3_decode_dirent,
+	.read_setup	= nfs3_proc_read_setup,
+	.write_setup	= nfs3_proc_write_setup,
+	.commit_setup	= nfs3_proc_commit_setup,
 };
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Fri Oct 11 21:23:05 2002
+++ b/fs/nfs/nfs3xdr.c	Fri Oct 11 21:23:05 2002
@@ -173,7 +173,7 @@
 	/* Turn remote device info into Linux-specific dev_t */
 	fattr->rdev = ntohl(*p++) << MINORBITS;
 	fattr->rdev |= ntohl(*p++) & MINORMASK;
-	p = xdr_decode_hyper(p, &fattr->fsid);
+	p = xdr_decode_hyper(p, &fattr->fsid_u.nfs3);
 	p = xdr_decode_hyper(p, &fattr->fileid);
 	p = xdr_decode_time3(p, &fattr->atime);
 	p = xdr_decode_time3(p, &fattr->mtime);
diff -Nru a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
--- a/fs/nfs/pagelist.c	Fri Oct 11 21:22:55 2002
+++ b/fs/nfs/pagelist.c	Fri Oct 11 21:22:55 2002
@@ -14,6 +14,7 @@
 #include <linux/file.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs3.h>
+#include <linux/nfs4.h>
 #include <linux/nfs_page.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_flushd.h>
@@ -506,7 +507,7 @@
 			continue;
 		}
 
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 		/* Let's try to free up some completed NFSv3 unstable writes */
 		nfs_scan_lru_commit(server, &head);
 		if (!list_empty(&head)) {
diff -Nru a/fs/nfs/proc.c b/fs/nfs/proc.c
--- a/fs/nfs/proc.c	Fri Oct 11 21:23:04 2002
+++ b/fs/nfs/proc.c	Fri Oct 11 21:23:04 2002
@@ -41,6 +41,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
 #include <linux/smp_lock.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PROC
@@ -78,9 +79,10 @@
 }
 
 static int
-nfs_proc_setattr(struct inode *inode, struct nfs_fattr *fattr,
+nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 		 struct iattr *sattr)
 {
+	struct inode *inode = dentry->d_inode;
 	struct nfs_sattrargs	arg = { 
 		.fh	= NFS_FH(inode),
 		.sattr	= sattr
@@ -310,13 +312,16 @@
 	return 0;
 }
 
-static void
-nfs_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
+static int
+nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
 {
+	struct rpc_message *msg = &task->tk_msg;
+	
 	if (msg->rpc_argp) {
 		NFS_CACHEINV(dir->d_inode);
 		kfree(msg->rpc_argp);
 	}
+	return 0;
 }
 
 static int
@@ -425,9 +430,10 @@
  * from nfs_readdir by calling the decode_entry function directly.
  */
 static int
-nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred,
+nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 		 u64 cookie, struct page *page, unsigned int count, int plus)
 {
+	struct inode		*dir = dentry->d_inode;
 	struct nfs_readdirargs	arg = {
 		.fh		= NFS_FH(dir),
 		.cookie		= cookie,
@@ -467,6 +473,100 @@
 
 extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
 
+static void
+nfs_read_done(struct rpc_task *task)
+{
+	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
+	nfs_readpage_result(task, data->u.v3.res.count, data->u.v3.res.eof);
+}
+
+static void
+nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+{
+	struct rpc_task		*task = &data->task;
+	struct inode		*inode = data->inode;
+	struct nfs_page		*req;
+	int			flags;
+	struct rpc_message	msg;
+	
+	req = nfs_list_entry(data->pages.next);
+	data->u.v3.args.fh     = NFS_FH(inode);
+	data->u.v3.args.offset = req_offset(req) + req->wb_offset;
+	data->u.v3.args.pgbase = req->wb_offset;
+	data->u.v3.args.pages  = data->pagevec;
+	data->u.v3.args.count  = count;
+	data->u.v3.res.fattr   = &data->fattr;
+	data->u.v3.res.count   = count;
+	data->u.v3.res.eof     = 0;
+	
+	/* N.B. Do we need to test? Never called for swapfile inode */
+	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_readdata_release;
+
+	msg.rpc_proc = NFSPROC_READ;
+	msg.rpc_argp = &data->u.v3.args;
+	msg.rpc_resp = &data->u.v3.res;
+	msg.rpc_cred = data->cred;
+	rpc_call_setup(&data->task, &msg, 0);
+}
+
+static void
+nfs_write_done(struct rpc_task *task)
+{
+	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	nfs_writeback_done(task, data->u.v3.args.stable,
+			   data->u.v3.args.count, data->u.v3.res.count);
+}
+
+static void
+nfs_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
+{
+	struct rpc_task		*task = &data->task;
+	struct inode		*inode = data->inode;
+	struct nfs_page		*req;
+	int			flags;
+	struct rpc_message	msg;
+
+	/* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */
+	
+	req = nfs_list_entry(data->pages.next);
+	data->u.v3.args.fh     = NFS_FH(inode);
+	data->u.v3.args.offset = req_offset(req) + req->wb_offset;
+	data->u.v3.args.pgbase = req->wb_offset;
+	data->u.v3.args.count  = count;
+	data->u.v3.args.stable = NFS_FILE_SYNC;
+	data->u.v3.args.pages  = data->pagevec;
+	data->u.v3.res.fattr   = &data->fattr;
+	data->u.v3.res.count   = count;
+	data->u.v3.res.verf    = &data->verf;
+
+	/* Set the initial flags for the task.  */
+	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs_write_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_writedata_release;
+
+	msg.rpc_proc = NFSPROC_WRITE;
+	msg.rpc_argp = &data->u.v3.args;
+	msg.rpc_resp = &data->u.v3.res;
+	msg.rpc_cred = data->cred;
+	rpc_call_setup(&data->task, &msg, 0);
+}
+
+static void
+nfs_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
+{
+	BUG();
+}
+
 struct nfs_rpc_ops	nfs_v2_clientops = {
 	.version	= 2,		       /* protocol version */
 	.getroot	= nfs_proc_get_root,
@@ -491,4 +591,7 @@
 	.mknod		= nfs_proc_mknod,
 	.statfs		= nfs_proc_statfs,
 	.decode_dirent	= nfs_decode_dirent,
+	.read_setup	= nfs_proc_read_setup,
+	.write_setup	= nfs_proc_write_setup,
+	.commit_setup	= nfs_proc_commit_setup,
 };
diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c	Fri Oct 11 21:22:50 2002
+++ b/fs/nfs/read.c	Fri Oct 11 21:22:50 2002
@@ -34,27 +34,6 @@
 
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
-struct nfs_read_data {
-	struct rpc_task		task;
-	struct inode		*inode;
-	struct rpc_cred		*cred;
-	struct nfs_readargs	args;	/* XDR argument struct */
-	struct nfs_readres	res;	/* ... and result struct */
-	struct nfs_fattr	fattr;	/* fattr storage */
-	struct list_head	pages;	/* Coalesced read requests */
-	struct page		*pagevec[NFS_READ_MAXIOV];
-};
-
-/*
- * Local function declarations
- */
-static void	nfs_readpage_result(struct rpc_task *task);
-
-/* Hack for future NFS swap support */
-#ifndef IS_SWAPFILE
-# define IS_SWAPFILE(inode)	(0)
-#endif
-
 static kmem_cache_t *nfs_rdata_cachep;
 
 static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
@@ -64,7 +43,6 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
-		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -74,7 +52,7 @@
 	kmem_cache_free(nfs_rdata_cachep, p);
 }
 
-static void nfs_readdata_release(struct rpc_task *task)
+void nfs_readdata_release(struct rpc_task *task)
 {
         struct nfs_read_data   *data = (struct nfs_read_data *)task->tk_calldata;
         nfs_readdata_free(data);
@@ -190,29 +168,32 @@
 static void
 nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
 {
+	struct inode		*inode;
 	struct nfs_page		*req;
 	struct page		**pages;
 	unsigned int		count;
 
-	pages = data->args.pages;
+	pages = data->pagevec;
 	count = 0;
 	while (!list_empty(head)) {
-		struct nfs_page *req = nfs_list_entry(head->next);
+		req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
 		*pages++ = req->wb_page;
 		count += req->wb_bytes;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->inode	  = req->wb_inode;
+	data->inode	  = inode = req->wb_inode;
 	data->cred	  = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_inode);
-	data->args.offset = req_offset(req) + req->wb_offset;
-	data->args.pgbase = req->wb_offset;
-	data->args.count  = count;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.eof     = 0;
+
+	NFS_PROTO(inode)->read_setup(data, count);
+
+	dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu.\n",
+			data->task.tk_pid,
+			inode->i_sb->s_id,
+			(long long)NFS_FILEID(inode),
+			count,
+			(unsigned long long)req_offset(req) + req->wb_offset);
 }
 
 static void
@@ -236,50 +217,20 @@
 static int
 nfs_pagein_one(struct list_head *head, struct inode *inode)
 {
-	struct rpc_task		*task;
 	struct rpc_clnt		*clnt = NFS_CLIENT(inode);
 	struct nfs_read_data	*data;
-	struct rpc_message	msg;
-	int			flags;
 	sigset_t		oldset;
 
 	data = nfs_readdata_alloc();
 	if (!data)
 		goto out_bad;
-	task = &data->task;
-
-	/* N.B. Do we need to test? Never called for swapfile inode */
-	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
 
 	nfs_read_rpcsetup(head, data);
 
-	/* Finalize the task. */
-	rpc_init_task(task, clnt, nfs_readpage_result, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_readdata_release;
-
-#ifdef CONFIG_NFS_V3
-	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
-#else
-	msg.rpc_proc = NFSPROC_READ;
-#endif
-	msg.rpc_argp = &data->args;
-	msg.rpc_resp = &data->res;
-	msg.rpc_cred = data->cred;
-
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu.\n",
-		task->tk_pid,
-		inode->i_sb->s_id,
-		(long long)NFS_FILEID(inode),
-		(unsigned int)data->args.count,
-		(unsigned long long)data->args.offset);
-
 	rpc_clnt_sigmask(clnt, &oldset);
-	rpc_call_setup(task, &msg, 0);
 	lock_kernel();
-	rpc_execute(task);
+	rpc_execute(&data->task);
 	unlock_kernel();
 	rpc_clnt_sigunmask(clnt, &oldset);
 	return 0;
@@ -399,19 +350,15 @@
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
  */
-static void
-nfs_readpage_result(struct rpc_task *task)
+void
+nfs_readpage_result(struct rpc_task *task, unsigned int count, int eof)
 {
 	struct nfs_read_data	*data = (struct nfs_read_data *) task->tk_calldata;
 	struct inode		*inode = data->inode;
-	unsigned int		count = data->res.count;
 
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
 		task->tk_pid, task->tk_status);
 
-	if (nfs_async_handle_jukebox(task))
-		return;
-
 	nfs_refresh_inode(inode, &data->fattr);
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
@@ -424,7 +371,7 @@
 				memset(p + count, 0, PAGE_CACHE_SIZE - count);
 				kunmap(page);
 				count = 0;
-				if (data->res.eof)
+				if (eof)
 					SetPageUptodate(page);
 				else
 					SetPageError(page);
diff -Nru a/fs/nfs/unlink.c b/fs/nfs/unlink.c
--- a/fs/nfs/unlink.c	Fri Oct 11 21:23:04 2002
+++ b/fs/nfs/unlink.c	Fri Oct 11 21:23:04 2002
@@ -123,13 +123,12 @@
 	struct dentry		*dir = data->dir;
 	struct inode		*dir_i;
 
-	if (nfs_async_handle_jukebox(task))
-		return;
 	if (!dir)
 		return;
 	dir_i = dir->d_inode;
 	nfs_zap_caches(dir_i);
-	NFS_PROTO(dir_i)->unlink_done(dir, &task->tk_msg);
+	if (NFS_PROTO(dir_i)->unlink_done(dir, task))
+		return;
 	put_rpccred(data->cred);
 	data->cred = NULL;
 	dput(dir);
diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Fri Oct 11 21:23:02 2002
+++ b/fs/nfs/write.c	Fri Oct 11 21:23:02 2002
@@ -64,38 +64,12 @@
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
 /*
- * Local structures
- *
- * This is the struct where the WRITE/COMMIT arguments go.
- */
-struct nfs_write_data {
-	struct rpc_task		task;
-	struct inode		*inode;
-	struct rpc_cred		*cred;
-	struct nfs_writeargs	args;		/* argument struct */
-	struct nfs_writeres	res;		/* result struct */
-	struct nfs_fattr	fattr;
-	struct nfs_writeverf	verf;
-	struct list_head	pages;		/* Coalesced requests we wish to flush */
-	struct page		*pagevec[NFS_WRITE_MAXIOV];
-};
-
-/*
  * Local function declarations
  */
 static struct nfs_page * nfs_update_request(struct file*, struct inode *,
 					    struct page *,
 					    unsigned int, unsigned int);
 static void	nfs_strategy(struct inode *inode);
-static void	nfs_writeback_done(struct rpc_task *);
-#ifdef CONFIG_NFS_V3
-static void	nfs_commit_done(struct rpc_task *);
-#endif
-
-/* Hack for future NFS swap support */
-#ifndef IS_SWAPFILE
-# define IS_SWAPFILE(inode)	(0)
-#endif
 
 static kmem_cache_t *nfs_wdata_cachep;
 
@@ -106,7 +80,6 @@
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
-		p->args.pages = p->pagevec;
 	}
 	return p;
 }
@@ -116,7 +89,7 @@
 	kmem_cache_free(nfs_wdata_cachep, p);
 }
 
-static void nfs_writedata_release(struct rpc_task *task)
+void nfs_writedata_release(struct rpc_task *task)
 {
 	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;
 	nfs_writedata_free(wdata);
@@ -414,7 +387,7 @@
 	return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty;
 }
 
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 /*
  * Add a request to the inode's commit list.
  */
@@ -552,7 +525,7 @@
 	return res;
 }
 
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 /**
  * nfs_scan_lru_commit_timeout - Scan LRU list for timed out commit requests
  * @server: NFS superblock data
@@ -747,7 +720,7 @@
 
 	dirty  = NFS_I(inode)->ndirty;
 	wpages = NFS_SERVER(inode)->wpages;
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 	if (NFS_PROTO(inode)->version == 2) {
 		if (dirty >= NFS_STRATEGY_PAGES * wpages)
 			nfs_flush_file(inode, NULL, 0, 0, 0);
@@ -860,8 +833,10 @@
  * Set up the argument/result storage required for the RPC call.
  */
 static void
-nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
+nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
 {
+	struct rpc_task		*task = &data->task;
+	struct inode		*inode;
 	struct nfs_page		*req;
 	struct page		**pages;
 	unsigned int		count;
@@ -869,27 +844,28 @@
 	/* Set up the RPC argument and reply structs
 	 * NB: take care not to mess about with data->commit et al. */
 
-	pages = data->args.pages;
+	pages = data->pagevec;
 	count = 0;
 	while (!list_empty(head)) {
-		struct nfs_page *req = nfs_list_entry(head->next);
+		req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
 		*pages++ = req->wb_page;
 		count += req->wb_bytes;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->inode = req->wb_inode;
+	data->inode = inode = req->wb_inode;
 	data->cred = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_inode);
-	data->args.offset = req_offset(req) + req->wb_offset;
-	data->args.pgbase = req->wb_offset;
-	data->args.count  = count;
-	data->res.fattr   = &data->fattr;
-	data->res.count   = count;
-	data->res.verf    = &data->verf;
-}
 
+	NFS_PROTO(inode)->write_setup(data, count, how);
+
+	dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
+		task->tk_pid,
+		inode->i_sb->s_id,
+		(long long)NFS_FILEID(inode),
+		count,
+		(unsigned long long)req_offset(req) + req->wb_offset);
+}
 
 /*
  * Create an RPC task for the given write request and kick it.
@@ -902,64 +878,20 @@
 static int
 nfs_flush_one(struct list_head *head, struct inode *inode, int how)
 {
-	struct nfs_inode *nfsi = NFS_I(inode);
 	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
 	struct nfs_write_data	*data;
-	struct rpc_task		*task;
-	struct rpc_message	msg;
-	int                     flags,
-				nfsvers = NFS_PROTO(inode)->version,
-				async = !(how & FLUSH_SYNC),
-				stable = (how & FLUSH_STABLE);
 	sigset_t		oldset;
 
-
 	data = nfs_writedata_alloc();
 	if (!data)
 		goto out_bad;
-	task = &data->task;
-
-	/* Set the initial flags for the task.  */
-	flags = (async) ? RPC_TASK_ASYNC : 0;
 
 	/* Set up the argument struct */
-	nfs_write_rpcsetup(head, data);
-	if (nfsvers < 3)
-		data->args.stable = NFS_FILE_SYNC;
-	else if (stable) {
-		if (!nfsi->ncommit)
-			data->args.stable = NFS_FILE_SYNC;
-		else
-			data->args.stable = NFS_DATA_SYNC;
-	} else
-		data->args.stable = NFS_UNSTABLE;
-
-	/* Finalize the task. */
-	rpc_init_task(task, clnt, nfs_writeback_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_writedata_release;
-
-#ifdef CONFIG_NFS_V3
-	msg.rpc_proc = (nfsvers == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE;
-#else
-	msg.rpc_proc = NFSPROC_WRITE;
-#endif
-	msg.rpc_argp = &data->args;
-	msg.rpc_resp = &data->res;
-	msg.rpc_cred = data->cred;
-
-	dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
-		task->tk_pid,
-		inode->i_sb->s_id,
-		(long long)NFS_FILEID(inode),
-		(unsigned int)data->args.count,
-		(unsigned long long)data->args.offset);
+	nfs_write_rpcsetup(head, data, how);
 
 	rpc_clnt_sigmask(clnt, &oldset);
-	rpc_call_setup(task, &msg, 0);
 	lock_kernel();
-	rpc_execute(task);
+	rpc_execute(&data->task);
 	unlock_kernel();
 	rpc_clnt_sigunmask(clnt, &oldset);
 	return 0;
@@ -1004,12 +936,11 @@
 /*
  * This function is called when the WRITE call is complete.
  */
-static void
-nfs_writeback_done(struct rpc_task *task)
+void
+nfs_writeback_done(struct rpc_task *task, int stable,
+		   unsigned int arg_count, unsigned int res_count)
 {
 	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
-	struct nfs_writeargs	*argp = &data->args;
-	struct nfs_writeres	*resp = &data->res;
 	struct inode		*inode = data->inode;
 	struct nfs_page		*req;
 	struct page		*page;
@@ -1017,11 +948,8 @@
 	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
 		task->tk_pid, task->tk_status);
 
-	if (nfs_async_handle_jukebox(task))
-		return;
-
 	/* We can't handle that yet but we check for it nevertheless */
-	if (resp->count < argp->count && task->tk_status >= 0) {
+	if (res_count < arg_count && task->tk_status >= 0) {
 		static unsigned long    complain;
 		if (time_before(complain, jiffies)) {
 			printk(KERN_WARNING
@@ -1032,8 +960,8 @@
 		 * an error. */
 		task->tk_status = -EIO;
 	}
-#ifdef CONFIG_NFS_V3
-	if (resp->verf->committed < argp->stable && task->tk_status >= 0) {
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+	if (data->verf.committed < stable && task->tk_status >= 0) {
 		/* We tried a write call, but the server did not
 		 * commit data to stable storage even though we
 		 * requested it.
@@ -1045,10 +973,10 @@
 		static unsigned long    complain;
 
 		if (time_before(complain, jiffies)) {
-			dprintk("NFS: faulty NFSv3 server %s:"
+			dprintk("NFS: faulty NFS server %s:"
 				" (committed = %d) != (stable = %d)\n",
 				NFS_SERVER(inode)->hostname,
-				resp->verf->committed, argp->stable);
+				data->verf.committed, stable);
 			complain = jiffies + 300 * HZ;
 		}
 	}
@@ -1060,7 +988,7 @@
 	 *	  writebacks since the page->count is kept > 1 for as long
 	 *	  as the page has a write request pending.
 	 */
-	nfs_write_attributes(inode, resp->fattr);
+	nfs_write_attributes(inode, &data->fattr);
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
@@ -1082,13 +1010,13 @@
 			goto next;
 		}
 
-#ifdef CONFIG_NFS_V3
-		if (argp->stable != NFS_UNSTABLE || resp->verf->committed == NFS_FILE_SYNC) {
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+		if (stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
 			nfs_inode_remove_request(req);
 			dprintk(" OK\n");
 			goto next;
 		}
-		memcpy(&req->wb_verf, resp->verf, sizeof(req->wb_verf));
+		memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
 		req->wb_timeout = jiffies + NFS_COMMIT_DELAY;
 		nfs_mark_request_commit(req);
 		dprintk(" marked for commit\n");
@@ -1101,13 +1029,14 @@
 }
 
 
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 /*
  * Set up the argument/result storage required for the RPC call.
  */
 static void
-nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
+nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data, int how)
 {
+	struct rpc_task		*task = &data->task;
 	struct nfs_page		*first, *last;
 	struct inode		*inode;
 	loff_t			start, end, len;
@@ -1133,11 +1062,10 @@
 
 	data->inode	  = inode;
 	data->cred	  = first->wb_cred;
-	data->args.fh     = NFS_FH(inode);
-	data->args.offset = start;
-	data->res.count   = data->args.count = (u32)len;
-	data->res.fattr   = &data->fattr;
-	data->res.verf    = &data->verf;
+
+	NFS_PROTO(inode)->commit_setup(data, start, len, how);
+	
+	dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
 }
 
 /*
@@ -1146,43 +1074,23 @@
 int
 nfs_commit_list(struct list_head *head, int how)
 {
-	struct rpc_message	msg;
 	struct rpc_clnt		*clnt;
 	struct nfs_write_data	*data;
-	struct rpc_task         *task;
 	struct nfs_page         *req;
-	int                     flags,
-				async = !(how & FLUSH_SYNC);
 	sigset_t		oldset;
 
 	data = nfs_writedata_alloc();
 
 	if (!data)
 		goto out_bad;
-	task = &data->task;
-
-	flags = (async) ? RPC_TASK_ASYNC : 0;
 
 	/* Set up the argument struct */
-	nfs_commit_rpcsetup(head, data);
-	req = nfs_list_entry(data->pages.next);
-	clnt = NFS_CLIENT(req->wb_inode);
+	nfs_commit_rpcsetup(head, data, how);
+	clnt = NFS_CLIENT(data->inode);
 
-	rpc_init_task(task, clnt, nfs_commit_done, flags);
-	task->tk_calldata = data;
-	/* Release requests */
-	task->tk_release = nfs_writedata_release;
-
-	msg.rpc_proc = NFS3PROC_COMMIT;
-	msg.rpc_argp = &data->args;
-	msg.rpc_resp = &data->res;
-	msg.rpc_cred = data->cred;
-
-	dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
 	rpc_clnt_sigmask(clnt, &oldset);
-	rpc_call_setup(task, &msg, 0);
 	lock_kernel();
-	rpc_execute(task);
+	rpc_execute(&data->task);
 	unlock_kernel();
 	rpc_clnt_sigunmask(clnt, &oldset);
 	return 0;
@@ -1199,21 +1107,17 @@
 /*
  * COMMIT call returned
  */
-static void
+void
 nfs_commit_done(struct rpc_task *task)
 {
 	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;
-	struct nfs_writeres	*resp = &data->res;
 	struct nfs_page		*req;
 	struct inode		*inode = data->inode;
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
                                 task->tk_pid, task->tk_status);
 
-	if (nfs_async_handle_jukebox(task))
-		return;
-
-	nfs_write_attributes(inode, resp->fattr);
+	nfs_write_attributes(inode, &data->fattr);
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
@@ -1265,7 +1169,7 @@
 	return res;
 }
 
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,
 		    unsigned int npages, int how)
 {
@@ -1302,7 +1206,7 @@
 			error = nfs_wait_on_requests(inode, file, idx_start, npages);
 		if (error == 0)
 			error = nfs_flush_file(inode, file, idx_start, npages, how);
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 		if (error == 0)
 			error = nfs_commit_file(inode, file, idx_start, npages, how);
 #endif
diff -Nru a/fs/nfsd/Makefile b/fs/nfsd/Makefile
--- a/fs/nfsd/Makefile	Fri Oct 11 21:22:55 2002
+++ b/fs/nfsd/Makefile	Fri Oct 11 21:22:55 2002
@@ -7,6 +7,7 @@
 nfsd-y 			:= nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
 			   export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
 nfsd-$(CONFIG_NFSD_V3)	+= nfs3proc.o nfs3xdr.o
+nfsd-$(CONFIG_NFSD_V4)	+= nfs4proc.o nfs4xdr.o
 nfsd-objs		:= $(nfsd-y)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/fs/nfsd/export.c b/fs/nfsd/export.c
--- a/fs/nfsd/export.c	Fri Oct 11 21:23:00 2002
+++ b/fs/nfsd/export.c	Fri Oct 11 21:23:00 2002
@@ -32,63 +32,215 @@
 #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
 #define NFSD_PARANOIA 1
 
-typedef struct svc_client	svc_client;
+typedef struct auth_domain	svc_client;
 typedef struct svc_export	svc_export;
 
-static void		exp_unexport_all(svc_client *clp);
 static void		exp_do_unexport(svc_export *unexp);
-static svc_client *	exp_getclientbyname(char *name);
-static void		exp_freeclient(svc_client *clp);
-static void		exp_unhashclient(svc_client *clp);
 static int		exp_verify_string(char *cp, int max);
 
-#define CLIENT_HASHBITS		6
-#define CLIENT_HASHMAX		(1 << CLIENT_HASHBITS)
-#define CLIENT_HASHMASK		(CLIENT_HASHMAX - 1)
-#define CLIENT_HASH(a) \
-		((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
+/*
+ * We have two caches.
+ * One maps client+vfsmnt+dentry to export options - the export map
+ * The other maps client+filehandle-fragment to export options. - the expkey map
+ *
+ * The export options are actually stored in the first map, and the
+ * second map contains a reference to the entry in the first map.
+ */
 
 #define	EXPKEY_HASHBITS		8
 #define	EXPKEY_HASHMAX		(1 << EXPKEY_HASHBITS)
 #define	EXPKEY_HASHMASK		(EXPKEY_HASHMAX -1)
-static struct list_head expkey_table[EXPKEY_HASHMAX];
+static struct cache_head *expkey_table[EXPKEY_HASHMAX];
 
-static inline int expkey_hash(struct svc_client *clp, int type, u32 *fsidv)
+static inline int svc_expkey_hash(struct svc_expkey *item)
 {
-	int hash = type;
-	char * cp = (char*)fsidv;
-	int len = (type==0)?8:4;
+	int hash = item->ek_fsidtype;
+	char * cp = (char*)item->ek_fsid;
+	int len = (item->ek_fsidtype==0)?8:4;
 	while (len--)
 		hash += *cp++;
-	cp = (char*)&clp;
-	len = sizeof(clp);
+	cp = (char*)&item->ek_client;
+	len = sizeof(item->ek_client);
 	while (len--)
 		hash += *cp++;
 	return hash & EXPKEY_HASHMASK;
 }
 
-struct svc_clnthash {
-	struct svc_clnthash *	h_next;
-	struct in_addr		h_addr;
-	struct svc_client *	h_client;
+void expkey_put(struct cache_head *item, struct cache_detail *cd)
+{
+	if (cache_put(item, cd)) {
+		struct svc_expkey *key = container_of(item, struct svc_expkey, h);
+		if (key->ek_export)
+			exp_put(key->ek_export);
+		auth_domain_put(key->ek_client);
+		kfree(key);
+	}
+}
+
+void expkey_request(struct cache_detail *cd,
+		    struct cache_head *h,
+		    char **bpp, int *blen)
+{
+	/* client fsidtype \xfsid */
+	struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
+	char type[5];
+
+	add_word(bpp, blen, ek->ek_client->name);
+	snprintf(type, 5, "%d", ek->ek_fsidtype);
+	add_word(bpp, blen, type);
+	add_hex(bpp, blen, (char*)ek->ek_fsid, ek->ek_fsidtype==0?8:4);
+	(*bpp)[-1] = '\n';
+}
+
+static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int);
+int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
+{
+	/* client fsidtype fsid [path] */
+	char *buf;
+	int len;
+	struct auth_domain *dom = NULL;
+	int err;
+	int fsidtype;
+	char *ep;
+	struct svc_expkey key;
+
+	if (mesg[mlen-1] != '\n')
+		return -EINVAL;
+	mesg[mlen-1] = 0;
+
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	err = -ENOMEM;
+	if (!buf) goto out;
+
+	err = -EINVAL;
+	if ((len=get_word(&mesg, buf, PAGE_SIZE)) <= 0)
+		goto out;
+
+	err = -ENOENT;
+	dom = auth_domain_find(buf);
+	if (!dom)
+		goto out;
+	dprintk("found domain %s\n", buf);
+
+	err = -EINVAL;
+	if ((len=get_word(&mesg, buf, PAGE_SIZE)) <= 0)
+		goto out;
+	fsidtype = simple_strtoul(buf, &ep, 10);
+	if (*ep)
+		goto out;
+	dprintk("found fsidtype %d\n", fsidtype);
+	if (fsidtype > 1)
+		goto out;
+	if ((len=get_word(&mesg, buf, PAGE_SIZE)) <= 0)
+		goto out;
+	dprintk("found fsid length %d\n", len);
+	if (len != ((fsidtype==0)?8:4))
+		goto out;
+
+	/* OK, we seem to have a valid key */
+	key.h.flags = 0;
+	key.h.expiry_time = get_expiry(&mesg);
+	if (key.h.expiry_time == 0)
+		goto out;
+
+	key.ek_client = dom;	
+	key.ek_fsidtype = fsidtype;
+	memcpy(key.ek_fsid, buf, len);
+
+	/* now we want a pathname, or empty meaning NEGATIVE  */
+	if ((len=get_word(&mesg, buf, PAGE_SIZE)) < 0)
+		goto out;
+	dprintk("Path seems to be <%s>\n", buf);
+	err = 0;
+	if (len == 0)
+		set_bit(CACHE_NEGATIVE, &key.h.flags);
+	else {
+		struct nameidata nd;
+		struct svc_expkey *ek;
+		struct svc_export *exp;
+		err = path_lookup(buf, 0, &nd);
+		if (err)
+			goto out;
+
+		dprintk("Found the path %s\n", buf);
+		exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
+
+		err = -ENOENT;
+		if (!exp)
+			goto out_nd;
+		key.ek_export = exp;
+		dprintk("And found export\n");
+		
+		ek = svc_expkey_lookup(&key, 2);
+		if (ek)
+			expkey_put(&ek->h, &svc_expkey_cache);
+		svc_export_put(&exp->h, &svc_export_cache);
+		err = 0;
+	out_nd:
+		path_release(&nd);
+	}
+
+ out:
+	if (dom)
+		auth_domain_put(dom);
+	if (buf)
+		kfree(buf);
+	return err;
+}
+
+struct cache_detail svc_expkey_cache = {
+	.hash_size	= EXPKEY_HASHMAX,
+	.hash_table	= expkey_table,
+	.name		= "nfsd.fh",
+	.cache_put	= expkey_put,
+	.cache_request	= expkey_request,
+	.cache_parse	= expkey_parse,
 };
-static struct svc_clnthash *	clnt_hash[CLIENT_HASHMAX];
-static svc_client *		clients;
 
-/* hash table of exports indexed by dentry+client */
+static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
+{
+	if (a->ek_fsidtype != b->ek_fsidtype ||
+	    a->ek_client != b->ek_client)
+		return 0;
+	if (a->ek_fsid[0] != b->ek_fsid[0])
+		return 0;
+	if (a->ek_fsidtype == 1)
+		return 1;
+	if (a->ek_fsid[1] != b->ek_fsid[1])
+		return 0;
+	return 1;
+}
+
+static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
+{
+	cache_get(&item->ek_client->h);
+	new->ek_client = item->ek_client;
+	new->ek_fsidtype = item->ek_fsidtype;
+	new->ek_fsid[0] = item->ek_fsid[0];
+	new->ek_fsid[1] = item->ek_fsid[1];
+}
+
+static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
+{
+	cache_get(&item->ek_export->h);
+	new->ek_export = item->ek_export;
+}
+
+static DefineSimpleCacheLookup(svc_expkey)
+
 #define	EXPORT_HASHBITS		8
 #define	EXPORT_HASHMAX		(1<< EXPORT_HASHBITS)
 #define	EXPORT_HASHMASK		(EXPORT_HASHMAX -1)
 
-struct list_head	export_table[EXPORT_HASHMAX];
+static struct cache_head *export_table[EXPORT_HASHMAX];
 
-static int export_hash(svc_client *clp, struct dentry *dentry)
+static inline int svc_export_hash(struct svc_export *item)
 {
 	void *k[2];
 	unsigned char *cp;
 	int rv, i;
-	k[0] = clp;
-	k[1] = dentry;
+	k[0] = item->ex_client;
+	k[1] = item->ex_dentry;
 
 	cp = (char*)k;
 	rv = 0;
@@ -97,24 +249,192 @@
 	return rv & EXPORT_HASHMASK;
 }
 
+void svc_export_put(struct cache_head *item, struct cache_detail *cd)
+{
+	if (cache_put(item, cd)) {
+		struct svc_export *exp = container_of(item, struct svc_export, h);
+		dput(exp->ex_dentry);
+		mntput(exp->ex_mnt);
+		auth_domain_put(exp->ex_client);
+		kfree(exp);
+	}
+}
+
+void svc_export_request(struct cache_detail *cd,
+			struct cache_head *h,
+			char **bpp, int *blen)
+{
+	/*  client path */
+	struct svc_export *exp = container_of(h, struct svc_export, h);
+	char *pth;
+
+	add_word(bpp, blen, exp->ex_client->name);
+	pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen);
+	add_word(bpp, blen, pth);
+	(*bpp)[-1] = '\n';
+}
+
+static struct svc_export *svc_export_lookup(struct svc_export *, int);
+int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
+{
+	/* client path expiry [flags anonuid anongid fsid] */
+	char *buf;
+	int len;
+	int err;
+	struct auth_domain *dom = NULL;
+	struct nameidata nd;
+	struct svc_export exp, *expp;
+	int an_int;
+
+	nd.dentry = NULL;
+
+	if (mesg[mlen-1] != '\n')
+		return -EINVAL;
+	mesg[mlen-1] = 0;
+
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	err = -ENOMEM;
+	if (!buf) goto out;
+
+	/* client */
+	len = get_word(&mesg, buf, PAGE_SIZE);
+	if (len <= 0) return -EINVAL;
+	err = -ENOENT;
+	dom = auth_domain_find(buf);
+	if (!dom)
+		goto out;
+
+	/* path */
+	err = -EINVAL;
+	if ((len=get_word(&mesg, buf, PAGE_SIZE)) <= 0)
+		goto out;
+	err = path_lookup(buf, 0, &nd);
+	if (err) goto out;
+
+	exp.h.flags = 0;
+	exp.ex_client = dom;
+	exp.ex_mnt = nd.mnt;
+	exp.ex_dentry = nd.dentry;
+
+	/* expiry */
+	err = -EINVAL;
+	exp.h.expiry_time = get_expiry(&mesg);
+	if (exp.h.expiry_time == 0)
+		goto out;
+
+	/* flags */
+	err = get_int(&mesg, &an_int);
+	if (err == -ENOENT)
+		set_bit(CACHE_NEGATIVE, &exp.h.flags);
+	else {
+		if (err || an_int < 0) goto out;	
+		exp.ex_flags= an_int;
+	
+		/* anon uid */
+		err = get_int(&mesg, &an_int);
+		if (err) goto out;
+		exp.ex_anon_uid= an_int;
+
+		/* anon gid */
+		err = get_int(&mesg, &an_int);
+		if (err) goto out;
+		exp.ex_anon_gid= an_int;
+
+		/* fsid */
+		err = get_int(&mesg, &an_int);
+		if (err) goto out;
+		exp.ex_fsid = an_int;
+	}
+
+	expp = svc_export_lookup(&exp, 1);
+	if (expp)
+		exp_put(expp);
+	err = 0;
+
+ out:
+	if (nd.dentry)
+		path_release(&nd);
+	if (dom)
+		auth_domain_put(dom);
+	if (buf)
+		kfree(buf);
+	return err;
+}
+
+struct cache_detail svc_export_cache = {
+	.hash_size	= EXPORT_HASHMAX,
+	.hash_table	= export_table,
+	.name		= "nfsd.export",
+	.cache_put	= svc_export_put,
+	.cache_request	= svc_export_request,
+	.cache_parse	= svc_export_parse,
+};
+
+static inline int svc_export_match(struct svc_export *a, struct svc_export *b)
+{
+	return a->ex_client == b->ex_client &&
+		a->ex_dentry == b->ex_dentry &&
+		a->ex_mnt == b->ex_mnt;
+}
+static inline void svc_export_init(struct svc_export *new, struct svc_export *item)
+{
+	cache_get(&item->ex_client->h);
+	new->ex_client = item->ex_client;
+	new->ex_dentry = dget(item->ex_dentry);
+	new->ex_mnt = mntget(item->ex_mnt);
+}
+
+static inline void svc_export_update(struct svc_export *new, struct svc_export *item)
+{
+	new->ex_flags = item->ex_flags;
+	new->ex_anon_uid = item->ex_anon_uid;
+	new->ex_anon_gid = item->ex_anon_gid;
+	new->ex_fsid = item->ex_fsid;
+}
+
+static DefineSimpleCacheLookup(svc_export)
+
+
 struct svc_expkey *
-exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv)
+exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
 {
-	struct list_head *head;
-	struct svc_expkey *ek;
+	struct svc_expkey key, *ek;
+	int err;
 	
 	if (!clp)
 		return NULL;
 
-	head = &expkey_table[expkey_hash(clp, fsid_type, fsidv)];
-	list_for_each_entry(ek, head, ek_hash)
-		if (ek->ek_fsidtype == fsid_type &&
-		    fsidv[0] == ek->ek_fsid[0] &&
-		    (fsid_type == 1 || fsidv[1] == ek->ek_fsid[1]) &&
-		    clp      == ek->ek_client)
-			return ek;
+	key.ek_client = clp;
+	key.ek_fsidtype = fsid_type;
+	key.ek_fsid[0] = fsidv[0];
+	key.ek_fsid[1] = fsidv[1];
+
+	ek = svc_expkey_lookup(&key, 0);
+	if (ek != NULL)
+		if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
+			ek = ERR_PTR(err);
+	return ek;
+}
+
+int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, 
+		struct svc_export *exp)
+{
+	struct svc_expkey key, *ek;
+
+	key.ek_client = clp;
+	key.ek_fsidtype = fsid_type;
+	key.ek_fsid[0] = fsidv[0];
+	key.ek_fsid[1] = fsidv[1];
+	key.ek_export = exp;
+	key.h.expiry_time = NEVER;
+	key.h.flags = 0;
 
-	return NULL;
+	ek = svc_expkey_lookup(&key, 1);
+	if (ek) {
+		expkey_put(&ek->h, &svc_expkey_cache);
+		return 0;
+	}
+	return -ENOMEM;
 }
 
 /*
@@ -126,19 +446,7 @@
 	u32 fsidv[2];
 	
 	mk_fsid_v0(fsidv, dev, ino);
-	return exp_find_key(clp, 0, fsidv);
-}
-
-static inline svc_export *
-exp_get(svc_client *clp, dev_t dev, ino_t ino)
-{
-	struct svc_expkey *ek;
-
-	ek = exp_get_key(clp, dev, ino);
-	if (ek)
-		return ek->ek_export;
-	else
-		return NULL;
+	return exp_find_key(clp, 0, fsidv, NULL);
 }
 
 /*
@@ -151,52 +459,44 @@
 
 	mk_fsid_v1(fsidv, fsid);
 
-	return exp_find_key(clp, 1, fsidv);
-}
-
-static inline svc_export *
-exp_get_fsid(svc_client *clp, int fsid)
-{
-	struct svc_expkey *ek;
-
-	ek = exp_get_fsid_key(clp, fsid);
-	if (ek)
-		return ek->ek_export;
-	else
-		return NULL;
+	return exp_find_key(clp, 1, fsidv, NULL);
 }
 
 svc_export *
-exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
+exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
+		struct cache_req *reqp)
 {
-	svc_export *exp;
-	struct list_head *head = &export_table[export_hash(clp, dentry)];
-
+	struct svc_export *exp, key;
+	
 	if (!clp)
 		return NULL;
 
-	list_for_each_entry(exp, head, ex_hash) {
-		if (exp->ex_dentry == dentry && 
-		    exp->ex_mnt    == mnt &&
-		    exp->ex_client == clp)
-			return exp;
-	}
-	return NULL;
+	key.ex_client = clp;
+	key.ex_mnt = mnt;
+	key.ex_dentry = dentry;
+
+	exp = svc_export_lookup(&key, 0);
+	if (exp != NULL) 
+		if (cache_check(&svc_export_cache, &exp->h, reqp))
+			exp = NULL;
+
+	return exp;
 }
 
 /*
  * Find the export entry for a given dentry.
  */
 struct svc_export *
-exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
+exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
+	   struct cache_req *reqp)
 {
 	svc_export *exp;
 
 	read_lock(&dparent_lock);
-	exp = exp_get_by_name(clp, mnt, dentry);
+	exp = exp_get_by_name(clp, mnt, dentry, reqp);
 	while (exp == NULL && dentry != dentry->d_parent) {
 		dentry = dentry->d_parent;
-		exp = exp_get_by_name(clp, mnt, dentry);
+		exp = exp_get_by_name(clp, mnt, dentry, reqp);
 	}
 	read_unlock(&dparent_lock);
 	return exp;
@@ -243,55 +543,32 @@
 		return;
 
 	ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
-	if (ek) {
-		list_del(&ek->ek_hash);
-		kfree(ek);
+	if (ek && !IS_ERR(ek)) {
+		ek->h.expiry_time = CURRENT_TIME-1;
+		expkey_put(&ek->h, &svc_expkey_cache);
 	}
+	svc_expkey_cache.nextcheck = CURRENT_TIME;
 }
 
-static int exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
+static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
 {
-	struct list_head *head;
-	struct svc_expkey *ek;
+	u32 fsid[2];
  
 	if ((exp->ex_flags & NFSEXP_FSID) == 0)
 		return 0;
 
-	ek = kmalloc(sizeof(*ek), GFP_KERNEL);
-	if (ek == NULL)
-		return -ENOMEM;
-
-	ek->ek_fsidtype = 1;
-	ek->ek_export = exp;
-	ek->ek_client = clp;
-
-	mk_fsid_v1(ek->ek_fsid, exp->ex_fsid);
-	
-	head = &expkey_table[expkey_hash(clp, 1, ek->ek_fsid)];
-	list_add(&ek->ek_hash, head);
-	return 0;
+	mk_fsid_v1(fsid, exp->ex_fsid);
+	return exp_set_key(clp, 1, fsid, exp);
 }
 
-static int exp_hash(struct svc_client *clp, struct svc_export *exp)
+static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
 {
-	struct list_head *head;
-	struct svc_expkey *ek;
+	u32 fsid[2];
 	struct inode *inode;
- 
-	ek = kmalloc(sizeof(*ek), GFP_KERNEL);
-	if (ek == NULL)
-		return -ENOMEM;
-
-	ek->ek_fsidtype = 0;
-	ek->ek_export = exp;
-	ek->ek_client = clp;
 
 	inode = exp->ex_dentry->d_inode;
-	mk_fsid_v0(ek->ek_fsid, inode->i_sb->s_dev, inode->i_ino);
-	
-	head = &expkey_table[expkey_hash(clp, 0, ek->ek_fsid)];
-	list_add(&ek->ek_hash, head);
-	return 0;
+	mk_fsid_v0(fsid,  inode->i_sb->s_dev, inode->i_ino);
+	return exp_set_key(clp, 0, fsid, exp);
 }
 
 static void exp_unhash(struct svc_export *exp)
@@ -300,10 +577,11 @@
 	struct inode *inode = exp->ex_dentry->d_inode;
 
 	ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
-	if (ek) {
-		list_del(&ek->ek_hash);
-		kfree(ek);
+	if (ek && !IS_ERR(ek)) {
+		ek->h.expiry_time = CURRENT_TIME-1;
+		expkey_put(&ek->h, &svc_expkey_cache);
 	}
+	svc_expkey_cache.nextcheck = CURRENT_TIME;
 }
 	
 extern struct dentry *
@@ -317,8 +595,9 @@
 exp_export(struct nfsctl_export *nxp)
 {
 	svc_client	*clp;
-	svc_export	*exp = NULL;
-	svc_export	*fsid_exp;
+	struct svc_export	*exp = NULL;
+	struct svc_export	new;
+	struct svc_expkey	*fsid_key = NULL;
 	struct nameidata nd;
 	struct inode	*inode = NULL;
 	int		err;
@@ -337,7 +616,7 @@
 	exp_writelock();
 
 	/* Look up client info */
-	if (!(clp = exp_getclientbyname(nxp->ex_client)))
+	if (!(clp = auth_domain_find(nxp->ex_client)))
 		goto out_unlock;
 
 
@@ -348,12 +627,14 @@
 	inode = nd.dentry->d_inode;
 	err = -EINVAL;
 
-	exp = exp_get_by_name(clp, nd.mnt, nd.dentry);
+	exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL);
 
 	/* must make sure there wont be an ex_fsid clash */
 	if ((nxp->ex_flags & NFSEXP_FSID) &&
-	    (fsid_exp = exp_get_fsid(clp, nxp->ex_dev)) &&
-	    fsid_exp != exp)
+	    (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
+	    !IS_ERR(fsid_key) &&
+	    fsid_key->ek_export &&
+	    fsid_key->ek_export != exp)
 		goto finish;
 
 	if (exp != NULL) {
@@ -401,30 +682,41 @@
 			find_exported_dentry;
 
 	err = -ENOMEM;
-	if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
-		goto finish;
-	dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
 
-	exp->ex_client = clp;
-	exp->ex_mnt = mntget(nd.mnt);
-	exp->ex_dentry = dget(nd.dentry);
-	exp->ex_flags = nxp->ex_flags;
-	exp->ex_anon_uid = nxp->ex_anon_uid;
-	exp->ex_anon_gid = nxp->ex_anon_gid;
-	exp->ex_fsid = nxp->ex_dev;
+	dprintk("nfsd: creating export entry %p for client %p\n", exp, clp);
+
+	new.h.expiry_time = NEVER;
+	new.h.flags = 0;
+	new.ex_client = clp;
+	new.ex_mnt = nd.mnt;
+	new.ex_dentry = nd.dentry;
+	new.ex_flags = nxp->ex_flags;
+	new.ex_anon_uid = nxp->ex_anon_uid;
+	new.ex_anon_gid = nxp->ex_anon_gid;
+	new.ex_fsid = nxp->ex_dev;
+
+	exp = svc_export_lookup(&new, 2);
+
+	if (exp == NULL)
+		goto finish;
 
-	list_add_tail(&exp->ex_hash,
-		      &export_table[export_hash(clp, nd.dentry)]);
 	err = 0;
 
 	if (exp_hash(clp, exp) ||
 	    exp_fsid_hash(clp, exp)) {
 		/* failed to create at least one index */
 		exp_do_unexport(exp);
+		cache_flush();
 		err = -ENOMEM;
 	}
 
 finish:
+	if (exp)
+		exp_put(exp);
+	if (fsid_key && !IS_ERR(fsid_key))
+		expkey_put(&fsid_key->h, &svc_expkey_cache);
+	if (clp)
+		auth_domain_put(clp);
 	path_release(&nd);
 out_unlock:
 	exp_writeunlock();
@@ -439,20 +731,10 @@
 static void
 exp_do_unexport(svc_export *unexp)
 {
-	struct dentry	*dentry;
-	struct vfsmount *mnt;
-	struct inode	*inode;
-
-	list_del(&unexp->ex_hash);
+	unexp->h.expiry_time = CURRENT_TIME-1;
+	svc_export_cache.nextcheck = CURRENT_TIME;
 	exp_unhash(unexp);
 	exp_fsid_unhash(unexp);
-	dentry = unexp->ex_dentry;
-	mnt = unexp->ex_mnt;
-	inode = dentry->d_inode;
-	dput(dentry);
-	mntput(mnt);
-
-	kfree(unexp);
 }
 
 /*
@@ -461,17 +743,16 @@
 static void
 exp_unexport_all(svc_client *clp)
 {
-	struct list_head *lp, *tmp;
+	struct svc_export *exp;
 	int index;
 
 	dprintk("unexporting all fs's for clnt %p\n", clp);
 
-	for (index=0; index<EXPORT_HASHMAX; index++)
-		list_for_each_safe(lp, tmp, &export_table[index]) {
-			svc_export *exp = list_entry(lp, struct svc_export, ex_hash);
-			if (exp->ex_client == clp)
-				exp_do_unexport(exp);
-		}
+	cache_for_each(exp, &svc_export_cache, index, h)
+		if (exp->ex_client == clp)
+			exp_do_unexport(exp);
+	cache_flush();
+
 }
 
 /*
@@ -480,7 +761,7 @@
 int
 exp_unexport(struct nfsctl_export *nxp)
 {
-	svc_client	*clp;
+	struct auth_domain *dom;
 	int		err;
 
 	/* Consistency check */
@@ -490,14 +771,21 @@
 	exp_writelock();
 
 	err = -EINVAL;
-	clp = exp_getclientbyname(nxp->ex_client);
-	if (clp) {
-		svc_export *exp = exp_get(clp, nxp->ex_dev, nxp->ex_ino);
-		if (exp) {
-			exp_do_unexport(exp);
+	dom = auth_domain_find(nxp->ex_client);
+
+	if (dom) {
+		struct svc_expkey *key = exp_get_key(dom, nxp->ex_dev, nxp->ex_ino);
+		if (key && !IS_ERR(key) && key->ek_export) {
+			exp_do_unexport(key->ek_export);
 			err = 0;
-		}
-	}
+			expkey_put(&key->h, &svc_expkey_cache);
+		} else
+			dprintk("nfsd: no export %x/%lx for %s\n",
+				nxp->ex_dev, nxp->ex_ino, nxp->ex_client);
+		auth_domain_put(dom);
+		cache_flush();
+	} else
+		dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client);
 
 	exp_writeunlock();
 	return err;
@@ -509,7 +797,7 @@
  * since its harder to fool a kernel module than a user space program.
  */
 int
-exp_rootfh(struct svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
+exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
 {
 	struct svc_export	*exp;
 	struct nameidata	nd;
@@ -526,9 +814,9 @@
 	inode = nd.dentry->d_inode;
 
 	dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
-		 path, nd.dentry, clp->cl_ident,
+		 path, nd.dentry, clp->name,
 		 inode->i_sb->s_id, inode->i_ino);
-	exp = exp_parent(clp, nd.mnt, nd.dentry);
+	exp = exp_parent(clp, nd.mnt, nd.dentry, NULL);
 	if (!exp) {
 		dprintk("nfsd: exp_rootfh export not found.\n");
 		goto out;
@@ -550,56 +838,26 @@
 	return err;
 }
 
-
-/*
- * Find a valid client given an inet address. We always move the most
- * recently used client to the front of the hash chain to speed up
- * future lookups.
- * Locking against other processes is the responsibility of the caller.
- */
-struct svc_client *
-exp_getclient(struct sockaddr_in *sin)
-{
-	struct svc_clnthash	**hp, **head, *tmp;
-	unsigned long		addr = sin->sin_addr.s_addr;
-
-	head = &clnt_hash[CLIENT_HASH(addr)];
-
-	for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
-		if (tmp->h_addr.s_addr == addr) {
-#if 0
-/* If we really want to do this, we need a spin
-lock to protect against multiple access (as we only
-have an exp_readlock) and need to protect
-the code in e_show() that walks this list too.
-*/
-			/* Move client to the front */
-			if (head != hp) {
-				*hp = tmp->h_next;
-				tmp->h_next = *head;
-				*head = tmp;
-			}
-#endif
-			return tmp->h_client;
-		}
-	}
-
-	return NULL;
-}
-
 /*
- * Find a client given its identifier.
+ * Called when we need the filehandle for the root of the pseudofs,
+ * for a given NFSv4 client.   The root is defined to be the
+ * export point with fsid==0
  */
-static svc_client *
-exp_getclientbyname(char *ident)
+int
+exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp)
 {
-	svc_client *	clp;
+	struct svc_expkey *fsid_key;
+	int rv;
 
-	for (clp = clients; clp; clp = clp->cl_next) {
-		if (!strcmp(clp->cl_ident, ident))
-			return clp;
-	}
-	return NULL;
+	fsid_key = exp_get_fsid_key(clp, 0);
+	if (!fsid_key || IS_ERR(fsid_key))
+		return nfserr_perm;
+
+	dget(fsid_key->ek_export->ex_dentry);
+	rv = fh_compose(fhp, fsid_key->ek_export, 
+			  fsid_key->ek_export->ex_dentry, NULL);
+	expkey_put(&fsid_key->h, &svc_expkey_cache);
+	return rv;
 }
 
 /* Iterator */
@@ -608,55 +866,58 @@
 {
 	loff_t n = *pos;
 	unsigned hash, export;
-	svc_export  *exp;
+	struct cache_head *ch;
 	
 	exp_readlock();
+	read_lock(&svc_export_cache.hash_lock);
 	if (!n--)
 		return (void *)1;
 	hash = n >> 32;
 	export = n & ((1LL<<32) - 1);
 
-	list_for_each_entry(exp, &export_table[hash], ex_hash)
+	
+	for (ch=export_table[hash]; ch; ch=ch->next)
 		if (!export--)
-			return exp;
+			return ch;
 	n &= ~((1LL<<32) - 1);
 	do {
 		hash++;
 		n += 1LL<<32;
-	} while(hash < EXPORT_HASHMAX && list_empty(&export_table[hash]));
+	} while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);
 	if (hash >= EXPORT_HASHMAX)
 		return NULL;
 	*pos = n+1;
-	return list_entry(export_table[hash].next, svc_export, ex_hash);
+	return export_table[hash];
 }
 
 static void *e_next(struct seq_file *m, void *p, loff_t *pos)
 {
-	svc_export *exp = p;
+	struct cache_head *ch = p;
 	int hash = (*pos >> 32);
 
 	if (p == (void *)1)
 		hash = 0;
-	else if (exp->ex_hash.next == &export_table[hash]) {
+	else if (ch->next == NULL) {
 		hash++;
 		*pos += 1LL<<32;
 	} else {
 		++*pos;
-		return list_entry(exp->ex_hash.next, svc_export, ex_hash);
+		return ch->next;
 	}
 	*pos &= ~((1LL<<32) - 1);
-	while (hash < EXPORT_HASHMAX && list_empty(&export_table[hash])) {
+	while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {
 		hash++;
 		*pos += 1LL<<32;
 	}
 	if (hash >= EXPORT_HASHMAX)
 		return NULL;
 	++*pos;
-	return list_entry(export_table[hash].next, svc_export, ex_hash);
+	return export_table[hash];
 }
 
 static void e_stop(struct seq_file *m, void *p)
 {
+	read_unlock(&svc_export_cache.hash_lock);
 	exp_readunlock();
 }
 
@@ -707,8 +968,9 @@
 
 static int e_show(struct seq_file *m, void *p)
 {
-	struct svc_export *exp = p;
-	struct svc_client *clp;
+	struct cache_head *cp = p;
+	struct svc_export *exp = container_of(cp, struct svc_export, h);
+	svc_client *clp;
 	char *pbuf;
 
 	if (p == (void *)1) {
@@ -718,13 +980,16 @@
 	}
 
 	clp = exp->ex_client;
-
+	cache_get(&exp->h);
+	if (cache_check(&svc_export_cache, &exp->h, NULL))
+		return 0;
+	if (cache_put(&exp->h, &svc_export_cache)) BUG();
 	pbuf = m->private;
 	mangle(m, d_path(exp->ex_dentry, exp->ex_mnt,
 			 pbuf, PAGE_SIZE));
 
 	seq_putc(m, '\t');
-	mangle(m, clp->cl_ident);
+	mangle(m, clp->name);
 	seq_putc(m, '(');
 	exp_flags(m, exp->ex_flags, exp->ex_fsid, 
 		  exp->ex_anon_uid, exp->ex_anon_gid);
@@ -747,13 +1012,12 @@
 int
 exp_addclient(struct nfsctl_client *ncp)
 {
-	struct svc_clnthash *	ch[NFSCLNT_ADDRMAX];
-	svc_client *		clp;
-	int			i, err, change = 0, ilen;
+	struct auth_domain	*dom;
+	int			i, err;
 
 	/* First, consistency check. */
 	err = -EINVAL;
-	if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)))
+	if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
 		goto out;
 	if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
 		goto out;
@@ -761,56 +1025,19 @@
 	/* Lock the hashtable */
 	exp_writelock();
 
-	/* First check if this is a change request for a client. */
-	for (clp = clients; clp; clp = clp->cl_next)
-		if (!strcmp(clp->cl_ident, ncp->cl_ident))
-			break;
+	dom = unix_domain_find(ncp->cl_ident);
 
 	err = -ENOMEM;
-	if (clp) {
-		change = 1;
-	} else {
-		if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
-			goto out_unlock;
-		memset(clp, 0, sizeof(*clp));
-
-		dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
-
-		strcpy(clp->cl_ident, ncp->cl_ident);
-	}
-
-	/* Allocate hash buckets */
-	for (i = 0; i < ncp->cl_naddr; i++) {
-		ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL);
-		if (!ch[i]) {
-			while (i--)
-				kfree(ch[i]);
-			if (!change)
-				kfree(clp);
-			goto out_unlock;
-		}
-	}
-
-	/* Remove old client hash entries. */
-	if (change)
-		exp_unhashclient(clp);
+	if (!dom)
+		goto out_unlock;
 
 	/* Insert client into hashtable. */
-	for (i = 0; i < ncp->cl_naddr; i++) {
-		struct in_addr	addr = ncp->cl_addrlist[i];
-		int		hash;
-
-		hash = CLIENT_HASH(addr.s_addr);
-		ch[i]->h_client = clp;
-		ch[i]->h_addr = addr;
-		ch[i]->h_next = clnt_hash[hash];
-		clnt_hash[hash] = ch[i];
-	}
+	for (i = 0; i < ncp->cl_naddr; i++)
+		auth_unix_add_addr(ncp->cl_addrlist[i], dom);
+
+	auth_unix_forget_old(dom);
+	auth_domain_put(dom);
 
-	if (!change) {
-		clp->cl_next = clients;
-		clients = clp;
-	}
 	err = 0;
 
 out_unlock:
@@ -825,8 +1052,8 @@
 int
 exp_delclient(struct nfsctl_client *ncp)
 {
-	svc_client	**clpp, *clp;
 	int		err;
+	struct auth_domain *dom;
 
 	err = -EINVAL;
 	if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
@@ -835,14 +1062,14 @@
 	/* Lock the hashtable */
 	exp_writelock();
 
-	for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next))
-		if (!strcmp(ncp->cl_ident, clp->cl_ident))
-			break;
-
-	if (clp) {
-		*clpp = clp->cl_next;
-		exp_freeclient(clp);
-		err = 0;
+	dom = auth_domain_find(ncp->cl_ident);
+	/* just make sure that no addresses work 
+	 * and that it will expire soon 
+	 */
+	if (dom) {
+		err = auth_unix_forget_old(dom);
+		dom->h.expiry_time = CURRENT_TIME;
+		auth_domain_put(dom);
 	}
 
 	exp_writeunlock();
@@ -851,49 +1078,6 @@
 }
 
 /*
- * Free a client. The caller has already removed it from the client list.
- */
-static void
-exp_freeclient(svc_client *clp)
-{
-	exp_unhashclient(clp);
-
-	exp_unexport_all(clp);
-	kfree (clp);
-}
-
-/*
- * Remove client from hashtable. We first collect all hashtable
- * entries and free them in one go.
- * The hash table must be writelocked by the caller.
- */
-static void
-exp_unhashclient(svc_client *clp)
-{
-	struct svc_clnthash	**hpp, *hp, *ch[NFSCLNT_ADDRMAX];
-	int			i, count, err;
-
-again:
-	err = 0;
-	for (i = 0, count = 0; i < CLIENT_HASHMAX && !err; i++) {
-		hpp = clnt_hash + i;
-		while ((hp = *hpp) && !err) {
-			if (hp->h_client == clp) {
-				*hpp = hp->h_next;
-				ch[count++] = hp;
-				err = (count >= NFSCLNT_ADDRMAX);
-			} else {
-				hpp = &(hp->h_next);
-			}
-		}
-	}
-	if (err)
-		goto again;
-	for (i = 0; i < count; i++)
-		kfree (ch[i]);
-}
-
-/*
  * Verify that string is non-empty and does not exceed max length.
  */
 static int
@@ -915,19 +1099,10 @@
 void
 nfsd_export_init(void)
 {
-	int		i;
-
 	dprintk("nfsd: initializing export module.\n");
 
-	for (i = 0; i < CLIENT_HASHMAX; i++)
-		clnt_hash[i] = NULL;
-	clients = NULL;
-
-	for (i = 0; i < EXPORT_HASHMAX ; i++)
-		INIT_LIST_HEAD(&export_table[i]);
-
-	for (i = 0; i < EXPKEY_HASHMAX; i++)
-		INIT_LIST_HEAD(&expkey_table[i]);
+	cache_register(&svc_export_cache);
+	cache_register(&svc_expkey_cache);
 
 }
 
@@ -937,18 +1112,17 @@
 void
 nfsd_export_shutdown(void)
 {
-	int	i;
 
 	dprintk("nfsd: shutting down export module.\n");
 
 	exp_writelock();
 
-	for (i = 0; i < CLIENT_HASHMAX; i++) {
-		while (clnt_hash[i])
-			exp_freeclient(clnt_hash[i]->h_client);
-	}
-	clients = NULL; /* we may be restarted before the module unloads */
-	
+	exp_unexport_all(NULL);
+	svcauth_unix_purge();
+
+	cache_unregister(&svc_export_cache);
+	cache_unregister(&svc_expkey_cache);
+
 	exp_writeunlock();
 	dprintk("nfsd: export shutdown complete.\n");
 }
diff -Nru a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
--- a/fs/nfsd/lockd.c	Fri Oct 11 21:23:03 2002
+++ b/fs/nfsd/lockd.c	Fri Oct 11 21:23:03 2002
@@ -32,11 +32,7 @@
 	fh.fh_export = NULL;
 
 	exp_readlock();
-	rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
-	if (rqstp->rq_client == NULL)
-		nfserr = nfserr_stale;
-	else
-		nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
+	nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
 	if (!nfserr) {
 		dget(filp->f_dentry);
 		mntget(filp->f_vfsmnt);
diff -Nru a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
--- a/fs/nfsd/nfs3proc.c	Fri Oct 11 21:22:55 2002
+++ b/fs/nfsd/nfs3proc.c	Fri Oct 11 21:22:55 2002
@@ -670,7 +670,7 @@
   PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
   PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
   PROC(access,	 access,	access,		fhandle,  RC_NOCACHE, ST+pAT+1),
-  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+256),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4),
   PROC(read,	 read,		read,		fhandle,  RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE),
   PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF, ST+WC+4),
   PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
diff -Nru a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
--- a/fs/nfsd/nfs3xdr.c	Fri Oct 11 21:22:50 2002
+++ b/fs/nfsd/nfs3xdr.c	Fri Oct 11 21:22:50 2002
@@ -103,7 +103,7 @@
 	char		*name;
 	int		i;
 
-	if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
+	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
 			if (*name == '\0')
 				return NULL;
diff -Nru a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/nfsd/nfs4proc.c	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,744 @@
+/*
+ *  fs/nfsd/nfs4proc.c
+ *
+ *  Server-side procedures for NFSv4.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Note: some routines in this file are just trivial wrappers
+ * (e.g. nfsd4_lookup()) defined solely for the sake of consistent
+ * naming.  Since all such routines have been declared "inline",
+ * there shouldn't be any associated overhead.  At some point in
+ * the future, I might inline these "by hand" to clean up a
+ * little.
+ */
+
+#include <linux/param.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/nfs4.h>
+#include <linux/nfsd/xdr4.h>
+
+#define NFSDDBG_FACILITY		NFSDDBG_PROC
+
+static inline int
+nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
+{
+	return nfs_ok;
+}
+
+/* Note: The organization of the OPEN code seems a little strange; it
+ * has been superfluously split into three routines, one of which is named
+ * nfsd4_process_open2() even though there is no nfsd4_process_open1()!
+ * This is because the code has been organized in anticipation of a
+ * subsequent patch which will implement more of the NFSv4 state model.
+ */
+static int
+do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+	struct svc_fh resfh;
+	int accmode, status;
+
+	fh_init(&resfh, NFS4_FHSIZE);
+	open->op_truncate = 0;
+
+	if (open->op_create) {
+		/*
+		 * Note: create modes (UNCHECKED,GUARDED...) are the same
+		 * in NFSv4 as in v3.
+		 */
+		status = nfsd_create_v3(rqstp, current_fh, open->op_name,
+					open->op_namelen, &open->op_iattr,
+					&resfh, open->op_createmode,
+					(u32 *)open->op_verf, &open->op_truncate);
+	}
+	else {
+		status = nfsd_lookup(rqstp, current_fh,
+				     open->op_name, open->op_namelen, &resfh);
+		fh_unlock(current_fh);
+	}
+
+	if (!status) {
+		set_change_info(&open->op_cinfo, current_fh);
+		fh_dup2(current_fh, &resfh);
+
+		accmode = MAY_NOP;
+		if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
+			accmode = MAY_READ;
+		if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
+			accmode |= (MAY_WRITE | MAY_TRUNC);
+		status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
+	}
+
+	fh_put(&resfh);
+	return status;
+}
+
+static int
+nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+	struct iattr iattr;
+	int status;
+
+	if (open->op_truncate) {
+		iattr.ia_valid = ATTR_SIZE;
+		iattr.ia_size = 0;
+		status = nfsd_setattr(rqstp, current_fh, &iattr, 0, (time_t)0);
+		if (status)
+			return status;
+	}
+
+	memset(&open->op_stateid, 0xff, sizeof(stateid_t));
+	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
+	return 0;
+}
+
+static inline int
+nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+	int status;
+
+	/* This check required by spec. */
+	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
+		return nfserr_inval;
+
+	/*
+	 * For now, we have no state, so we may as well implement an
+	 * even stronger check...
+	 */
+	if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
+		return nfserr_notsupp;
+
+	/*
+	 * This block of code will (1) set CURRENT_FH to the file being opened,
+	 * creating it if necessary, (2) set open->op_cinfo, (3) set open->op_truncate
+	 * if the file is to be truncated after opening, (4) do permission checking.
+	 */
+	status = do_open_lookup(rqstp, current_fh, open);
+	if (status)
+		return status;
+
+	/*
+	 * nfsd4_process_open2() does the actual opening of the file.  If
+	 * successful, it (1) truncates the file if open->op_truncate was
+	 * set, (2) sets open->op_stateid, (3) sets open->op_delegation.
+	 */
+	status = nfsd4_process_open2(rqstp, current_fh, open);
+	if (status)
+		return status;
+
+	/*
+	 * To finish the open response, we just need to set the rflags.
+	 */
+	open->op_rflags = 0;
+	return 0;
+}
+
+static inline int
+nfsd4_renew(clientid_t *clientid)
+{
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclientid)
+{
+	memset(&setclientid->se_clientid, 0, sizeof(clientid_t));
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_setclientid_confirm(struct svc_rqst *rqstp, clientid_t *clientid)
+{
+	return nfs_ok;
+}
+
+/*
+ * filehandle-manipulating ops.
+ */
+static inline int
+nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh)
+{
+	if (!current_fh->fh_dentry)
+		return nfserr_nofilehandle;
+
+	*getfh = current_fh;
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh)
+{
+	fh_put(current_fh);
+	current_fh->fh_handle.fh_size = putfh->pf_fhlen;
+	memcpy(&current_fh->fh_handle.fh_base, putfh->pf_fhval, putfh->pf_fhlen);
+	return fh_verify(rqstp, current_fh, 0, MAY_NOP);
+}
+
+static inline int
+nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
+{
+	fh_put(current_fh);
+	return exp_pseudoroot(rqstp->rq_client, current_fh);
+}
+
+static inline int
+nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
+{
+	if (!save_fh->fh_dentry)
+		return nfserr_nofilehandle;
+
+	fh_dup2(current_fh, save_fh);
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
+{
+	if (!current_fh->fh_dentry)
+		return nfserr_nofilehandle;
+
+	fh_dup2(save_fh, current_fh);
+	return nfs_ok;
+}
+
+/*
+ * misc nfsv4 ops
+ */
+static inline int
+nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access)
+{
+	if (access->ac_req_access & ~NFS3_ACCESS_FULL)
+		return nfserr_inval;
+
+	access->ac_resp_access = access->ac_req_access;
+	return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported);
+}
+
+static inline int
+nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
+{
+	u32 *p = (u32 *)commit->co_verf;
+	*p++ = nfssvc_boot.tv_sec;
+	*p++ = nfssvc_boot.tv_usec;
+
+	return nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count);
+}
+
+static inline int
+nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
+{
+	struct svc_fh resfh;
+	int status;
+
+	fh_init(&resfh, NFS4_FHSIZE);
+
+	status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE);
+	if (status)
+		return status;
+
+	switch (create->cr_type) {
+	case NF4LNK:
+		/* ugh! we have to null-terminate the linktext, or
+		 * vfs_symlink() will choke.  it is always safe to
+		 * null-terminate by brute force, since at worst we
+		 * will overwrite the first byte of the create namelen
+		 * in the XDR buffer, which has already been extracted
+		 * during XDR decode.
+		 */
+		create->cr_linkname[create->cr_linklen] = 0;
+
+		status = nfsd_symlink(rqstp, current_fh, create->cr_name,
+				      create->cr_namelen, create->cr_linkname,
+				      create->cr_linklen, &resfh, &create->cr_iattr);
+		break;
+
+	case NF4BLK:
+		if (create->cr_specdata1 >= MAX_BLKDEV || create->cr_specdata2 > 0xFF)
+			return nfserr_inval;
+		status = nfsd_create(rqstp, current_fh, create->cr_name,
+				     create->cr_namelen, &create->cr_iattr, S_IFBLK,
+				     MKDEV(create->cr_specdata1, create->cr_specdata2),
+				     &resfh);
+		break;
+
+	case NF4CHR:
+		if (create->cr_specdata1 >= MAX_CHRDEV || create->cr_specdata2 > 0xFF)
+			return nfserr_inval;
+		status = nfsd_create(rqstp, current_fh, create->cr_name,
+				     create->cr_namelen, &create->cr_iattr, S_IFCHR,
+				     MKDEV(create->cr_specdata1, create->cr_specdata2),
+				     &resfh);
+		break;
+
+	case NF4SOCK:
+		status = nfsd_create(rqstp, current_fh, create->cr_name,
+				     create->cr_namelen, &create->cr_iattr,
+				     S_IFSOCK, 0, &resfh);
+		break;
+
+	case NF4FIFO:
+		status = nfsd_create(rqstp, current_fh, create->cr_name,
+				     create->cr_namelen, &create->cr_iattr,
+				     S_IFIFO, 0, &resfh);
+		break;
+
+	case NF4DIR:
+		create->cr_iattr.ia_valid &= ~ATTR_SIZE;
+		status = nfsd_create(rqstp, current_fh, create->cr_name,
+				     create->cr_namelen, &create->cr_iattr,
+				     S_IFDIR, 0, &resfh);
+		break;
+
+	default:
+		BUG();
+	}
+
+	if (!status) {
+		fh_unlock(current_fh);
+		set_change_info(&create->cr_cinfo, current_fh);
+		fh_dup2(current_fh, &resfh);
+	}
+
+	fh_put(&resfh);
+	return status;
+}
+
+static inline int
+nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr)
+{
+	int status;
+
+	status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+	if (status)
+		return status;
+
+	if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
+		return nfserr_inval;
+
+	getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
+	getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
+
+	getattr->ga_fhp = current_fh;
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+	   struct svc_fh *save_fh, struct nfsd4_link *link)
+{
+	int status;
+
+	status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh);
+	if (!status)
+		set_change_info(&link->li_cinfo, current_fh);
+	return status;
+}
+
+static inline int
+nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
+{
+	/*
+	 * XXX: We currently violate the spec in one small respect
+	 * here.  If LOOKUPP is done at the root of the pseudofs,
+	 * the spec requires us to return NFSERR_NOENT.  Personally,
+	 * I think that leaving the filehandle unchanged is more
+	 * logical, but this is an academic question anyway, since
+	 * no clients actually use LOOKUPP.
+	 */
+	return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);
+}
+
+static inline int
+nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup)
+{
+	return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh);
+}
+
+static inline int
+nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
+{
+	/* no need to check permission - this will be done in nfsd_read() */
+
+	if (read->rd_offset >= OFFSET_MAX)
+		return nfserr_inval;
+
+	read->rd_rqstp = rqstp;
+	read->rd_fhp = current_fh;
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
+{
+	/* no need to check permission - this will be done in nfsd_readdir() */
+
+	if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
+		return nfserr_inval;
+
+	readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
+	readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
+
+	if (readdir->rd_cookie > ~(u32)0)
+		return nfserr_bad_cookie;
+
+	readdir->rd_rqstp = rqstp;
+	readdir->rd_fhp = current_fh;
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink)
+{
+	readlink->rl_rqstp = rqstp;
+	readlink->rl_fhp = current_fh;
+	return nfs_ok;
+}
+
+static inline int
+nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove)
+{
+	int status;
+
+	status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen);
+	if (!status) {
+		fh_unlock(current_fh);
+		set_change_info(&remove->rm_cinfo, current_fh);
+	}
+	return status;
+}
+
+static inline int
+nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+	     struct svc_fh *save_fh, struct nfsd4_rename *rename)
+{
+	int status;
+
+	status = nfsd_rename(rqstp, save_fh, rename->rn_sname,
+			     rename->rn_snamelen, current_fh,
+			     rename->rn_tname, rename->rn_tnamelen);
+	if (!status) {
+		set_change_info(&rename->rn_sinfo, current_fh);
+		set_change_info(&rename->rn_tinfo, save_fh);
+	}
+	return status;
+}
+
+static inline int
+nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
+{
+	return nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0);
+}
+
+static inline int
+nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
+{
+	u32 *p;
+
+	/* no need to check permission - this will be done in nfsd_write() */
+
+	if (write->wr_offset >= OFFSET_MAX)
+		return nfserr_inval;
+
+	write->wr_bytes_written = write->wr_buflen;
+	write->wr_how_written = write->wr_stable_how;
+	p = (u32 *)write->wr_verifier;
+	*p++ = nfssvc_boot.tv_sec;
+	*p++ = nfssvc_boot.tv_usec;
+
+	return nfsd_write(rqstp, current_fh, write->wr_offset,
+			  write->wr_buf, write->wr_buflen, &write->wr_how_written);
+}
+
+/* This routine never returns NFS_OK!  If there are no other errors, it
+ * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the
+ * attributes matched.  VERIFY is implemented by mapping NFSERR_SAME
+ * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
+ */
+static int
+nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify)
+{
+	u32 *buf, *p;
+	int count;
+	int status;
+
+	status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
+	if (status)
+		return status;
+
+	if ((verify->ve_bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0)
+	    || (verify->ve_bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
+		return nfserr_notsupp;
+	if (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
+		return nfserr_inval;
+	if (verify->ve_attrlen & 3)
+		return nfserr_inval;
+
+	/* count in words:
+	 *   bitmap_len(1) + bitmap(2) + attr_len(1) = 4
+	 */
+	count = 4 + (verify->ve_attrlen >> 2);
+	buf = kmalloc(count << 2, GFP_KERNEL);
+	if (!buf)
+		return nfserr_resource;
+
+	status = nfsd4_encode_fattr(current_fh, current_fh->fh_export,
+				    current_fh->fh_dentry, buf,
+				    &count, verify->ve_bmval);
+
+	/* this means that nfsd4_encode_fattr() ran out of space */
+	if (status == nfserr_resource && count == 0)
+		status = nfserr_not_same;
+	if (status)
+		goto out_kfree;
+
+	p = buf + 3;
+	status = nfserr_not_same;
+	if (ntohl(*p++) != verify->ve_attrlen)
+		goto out_kfree;
+	if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen))
+		status = nfserr_same;
+
+out_kfree:
+	kfree(buf);
+	return status;
+}
+
+/*
+ * NULL call.
+ */
+static int
+nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+	return nfs_ok;
+}
+
+
+/*
+ * COMPOUND call.
+ */
+static int
+nfsd4_proc_compound(struct svc_rqst *rqstp,
+		    struct nfsd4_compoundargs *args,
+		    struct nfsd4_compoundres *resp)
+{
+	struct nfsd4_op	*op;
+	struct svc_fh	current_fh;
+	struct svc_fh	save_fh;
+	int		slack_space;    /* in words, not bytes! */
+	int		status;
+
+	fh_init(&current_fh, NFS4_FHSIZE);
+	fh_init(&save_fh, NFS4_FHSIZE);
+
+	resp->p = rqstp->rq_resbuf.buf + 3 + XDR_QUADLEN(args->taglen);
+	resp->end = rqstp->rq_resbuf.base + rqstp->rq_resbuf.buflen;
+	resp->taglen = args->taglen;
+	resp->tag = args->tag;
+	resp->opcnt = 0;
+
+	/*
+	 * According to RFC3010, this takes precedence over all other errors.
+	 */
+	status = nfserr_minor_vers_mismatch;
+	if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
+		goto out;
+
+	status = nfs_ok;
+	while (!status && resp->opcnt < args->opcnt) {
+		op = &args->ops[resp->opcnt++];
+
+		/*
+		 * The XDR decode routines may have pre-set op->status;
+		 * for example, if there is a miscellaneous XDR error
+		 * it will be set to nfserr_bad_xdr.
+		 */
+		if (op->status)
+			goto encode_op;
+
+		/* We must be able to encode a successful response to
+		 * this operation, with enough room left over to encode a
+		 * failed response to the next operation.  If we don't
+		 * have enough room, fail with ERR_RESOURCE.
+		 */
+		slack_space = (char *)resp->end - (char *)resp->p;
+		if (slack_space < COMPOUND_SLACK_SPACE + COMPOUND_ERR_SLACK_SPACE) {
+			BUG_ON(slack_space < COMPOUND_ERR_SLACK_SPACE);
+			op->status = nfserr_resource;
+			goto encode_op;
+		}
+
+		switch (op->opnum) {
+		case OP_ACCESS:
+			op->status = nfsd4_access(rqstp, &current_fh, &op->u.access);
+			break;
+		case OP_CLOSE:
+			op->status = nfsd4_close(rqstp, &current_fh, &op->u.close);
+			break;
+		case OP_COMMIT:
+			op->status = nfsd4_commit(rqstp, &current_fh, &op->u.commit);
+			break;
+		case OP_CREATE:
+			op->status = nfsd4_create(rqstp, &current_fh, &op->u.create);
+			break;
+		case OP_GETATTR:
+			op->status = nfsd4_getattr(rqstp, &current_fh, &op->u.getattr);
+			break;
+		case OP_GETFH:
+			op->status = nfsd4_getfh(&current_fh, &op->u.getfh);
+			break;
+		case OP_LINK:
+			op->status = nfsd4_link(rqstp, &current_fh, &save_fh, &op->u.link);
+			break;
+		case OP_LOOKUP:
+			op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);
+			break;
+		case OP_LOOKUPP:
+			op->status = nfsd4_lookupp(rqstp, &current_fh);
+			break;
+		case OP_NVERIFY:
+			op->status = nfsd4_verify(rqstp, &current_fh, &op->u.nverify);
+			if (op->status == nfserr_not_same)
+				op->status = nfs_ok;
+			break;
+		case OP_OPEN:
+			op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
+			break;
+		case OP_PUTFH:
+			op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
+			break;
+		case OP_PUTROOTFH:
+			op->status = nfsd4_putrootfh(rqstp, &current_fh);
+			break;
+		case OP_READ:
+			op->status = nfsd4_read(rqstp, &current_fh, &op->u.read);
+			break;
+		case OP_READDIR:
+			op->status = nfsd4_readdir(rqstp, &current_fh, &op->u.readdir);
+			break;
+		case OP_READLINK:
+			op->status = nfsd4_readlink(rqstp, &current_fh, &op->u.readlink);
+			break;
+		case OP_REMOVE:
+			op->status = nfsd4_remove(rqstp, &current_fh, &op->u.remove);
+			break;
+		case OP_RENAME:
+			op->status = nfsd4_rename(rqstp, &current_fh, &save_fh, &op->u.rename);
+			break;
+		case OP_RENEW:
+			op->status = nfsd4_renew(&op->u.renew);
+			break;
+		case OP_RESTOREFH:
+			op->status = nfsd4_restorefh(&current_fh, &save_fh);
+			break;
+		case OP_SAVEFH:
+			op->status = nfsd4_savefh(&current_fh, &save_fh);
+			break;
+		case OP_SETATTR:
+			op->status = nfsd4_setattr(rqstp, &current_fh, &op->u.setattr);
+			break;
+		case OP_SETCLIENTID:
+			op->status = nfsd4_setclientid(rqstp, &op->u.setclientid);
+			break;
+		case OP_SETCLIENTID_CONFIRM:
+			op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm);
+			break;
+		case OP_VERIFY:
+			op->status = nfsd4_verify(rqstp, &current_fh, &op->u.verify);
+			if (op->status == nfserr_same)
+				op->status = nfs_ok;
+			break;
+		case OP_WRITE:
+			op->status = nfsd4_write(rqstp, &current_fh, &op->u.write);
+			break;
+		default:
+			BUG_ON(op->status == nfs_ok);
+			break;
+		}
+
+encode_op:
+		nfsd4_encode_operation(resp, op);
+		status = op->status;
+	}
+
+out:
+	if (args->ops != args->iops) {
+		kfree(args->ops);
+		args->ops = args->iops;
+	}
+	fh_put(&current_fh);
+	fh_put(&save_fh);
+	return status;
+}
+
+#define nfs4svc_decode_voidargs		NULL
+#define nfs4svc_release_void		NULL
+#define nfsd4_voidres			nfsd4_voidargs
+#define nfs4svc_release_compound	NULL
+struct nfsd4_voidargs { int dummy; };
+
+#define PROC(name, argt, rest, relt, cache, respsize)	\
+ { (svc_procfunc) nfsd4_proc_##name,		\
+   (kxdrproc_t) nfs4svc_decode_##argt##args,	\
+   (kxdrproc_t) nfs4svc_encode_##rest##res,	\
+   (kxdrproc_t) nfs4svc_release_##relt,		\
+   sizeof(struct nfsd4_##argt##args),		\
+   sizeof(struct nfsd4_##rest##res),		\
+   0,						\
+   cache,					\
+   respsize,					\
+ }
+
+/*
+ * TODO: At the present time, the NFSv4 server does not do XID caching
+ * of requests.  Implementing XID caching would not be a serious problem,
+ * although it would require a mild change in interfaces since one
+ * doesn't know whether an NFSv4 request is idempotent until after the
+ * XDR decode.  However, XID caching totally confuses pynfs (Peter
+ * Astrand's regression testsuite for NFSv4 servers), which reuses
+ * XID's liberally, so I've left it unimplemented until pynfs generates
+ * better XID's.
+ */
+struct svc_procedure		nfsd_procedures4[2] = {
+  PROC(null,	 void,		void,		void,	  RC_NOCACHE, 1),
+  PROC(compound, compound,	compound,	compound, RC_NOCACHE, NFSD_BUFSIZE)
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff -Nru a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/nfsd/nfs4xdr.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,1913 @@
+/*
+ *  fs/nfs/nfs4xdr.c
+ *
+ *  Server-side XDR for NFSv4
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * TODO: Neil Brown made the following observation:  We currently
+ * initially reserve NFSD_BUFSIZE space on the transmit queue and
+ * never release any of that until the request is complete.
+ * It would be good to calculate a new maximum response size while
+ * decoding the COMPOUND, and call svc_reserve with this number
+ * at the end of nfs4svc_decode_compoundargs.
+ */
+
+#include <linux/param.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/compatmac.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/name_lookup.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/xdr4.h>
+
+#define NFSDDBG_FACILITY		NFSDDBG_XDR
+
+/*
+ * From Peter Astrand <peter@cendio.se>: The following routines check
+ * whether a filename supplied by the client is valid.
+ */
+static const char trailing_bytes_for_utf8[256] = {
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+	2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+static inline int
+is_legal_iso_utf8_sequence(unsigned char *source, int length)
+{
+	unsigned char a;
+	unsigned char *srcptr;
+
+	srcptr = source + length;
+
+	switch (length) {
+		/* Everything else falls through when "1"... */
+	default:
+		/* Sequences with more than 6 bytes are invalid */
+		return 0;
+
+		/*
+		   Byte 3-6 must be 80..BF
+		*/
+	case 6:
+		if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+	case 5:
+		if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+	case 4:
+		if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+	case 3:
+		if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+
+	case 2:
+		a = *--srcptr;
+
+		/* Upper limit */
+		if (a > 0xBF)
+			/* 2nd byte may never be > 0xBF */
+			return 0;
+
+		/*
+		   Lower limits checks, to detect non-shortest forms.
+		   No fall-through in this inner switch.
+		*/
+		switch (*source) {
+		case 0xE0: /* 3 bytes */
+			if (a < 0xA0) return 0;
+			break;
+		case 0xF0: /* 4 bytes */
+			if (a < 0x90) return 0;
+			break;
+		case 0xF8: /* 5 bytes */
+			if (a < 0xC8) return 0;
+			break;
+		case 0xFC: /* 6 bytes */
+			if (a < 0x84) return 0;
+			break;
+		default:
+			/* In all cases, 2nd byte must be >= 0x80 (because leading
+			   10...) */
+			if (a < 0x80) return 0;
+		}
+
+	case 1:
+		/* Invalid ranges */
+		if (*source >= 0x80 && *source < 0xC2)
+			/* Multibyte char with value < 0xC2, non-shortest */
+			return 0;
+		if (*source > 0xFD)
+			/* Leading byte starting with 11111110 is illegal */
+			return 0;
+		if (!*source)
+			return 0;
+	}
+
+	return 1;
+}
+
+static int
+check_utf8(char *str, int len)
+{
+	unsigned char *chunk, *sourceend;
+	int chunklen;
+
+	chunk = str;
+	sourceend = str + len;
+
+	while (chunk < sourceend) {
+		chunklen = trailing_bytes_for_utf8[*chunk]+1;
+		if (chunk + chunklen > sourceend)
+			return nfserr_inval;
+		if (!is_legal_iso_utf8_sequence(chunk, chunklen))
+			return nfserr_inval;
+		chunk += chunklen;
+	}
+
+	return 0;
+}
+
+static int
+check_filename(char *str, int len, int err)
+{
+	int i;
+
+	if (len == 0)
+		return nfserr_inval;
+	if (isdotent(str, len))
+		return err;
+	for (i = 0; i < len; i++)
+		if (str[i] == '/')
+			return err;
+	return check_utf8(str, len);
+}
+
+/*
+ * START OF "GENERIC" DECODE ROUTINES.
+ *   These may look a little ugly since they are imported from a "generic"
+ * set of XDR encode/decode routines which are intended to be shared by
+ * all of our NFSv4 implementations (OpenBSD, MacOS X...).
+ *
+ * If the pain of reading these is too great, it should be a straightforward
+ * task to translate them into Linux-specific versions which are more
+ * consistent with the style used in NFSv2/v3...
+ */
+#define DECODE_HEAD				\
+	u32 *p;					\
+	int status
+#define DECODE_TAIL				\
+	status = 0;				\
+out:						\
+	return status;				\
+xdr_error:					\
+	printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__);	\
+	status = nfserr_bad_xdr;		\
+	goto out
+
+#define READ32(x)         (x) = ntohl(*p++)
+#define READ64(x)         do {			\
+	(x) = (u64)ntohl(*p++) << 32;		\
+	(x) |= ntohl(*p++);			\
+} while (0)
+#define READTIME(x)       do {			\
+	p++;					\
+	(x) = ntohl(*p++);			\
+	p++;					\
+} while (0)
+#define READMEM(x,nbytes) do {			\
+	x = (char *)p;				\
+	p += XDR_QUADLEN(nbytes);		\
+} while (0)
+#define COPYMEM(x,nbytes) do {			\
+	memcpy((x), p, nbytes);			\
+	p += XDR_QUADLEN(nbytes);		\
+} while (0)
+
+#define READ_BUF(nbytes)  do {			\
+	if (nbytes > (u32)((char *)argp->end - (char *)argp->p)) {	\
+		printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+		goto xdr_error;			\
+	}					\
+	p = argp->p;				\
+	argp->p += XDR_QUADLEN(nbytes);		\
+} while (0)
+
+static int
+nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
+{
+	u32 bmlen;
+	DECODE_HEAD;
+
+	bmval[0] = 0;
+	bmval[1] = 0;
+
+	READ_BUF(4);
+	READ32(bmlen);
+	if (bmlen > 1000)
+		goto xdr_error;
+
+	READ_BUF(bmlen << 2);
+	if (bmlen > 0)
+		READ32(bmval[0]);
+	if (bmlen > 1)
+		READ32(bmval[1]);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr)
+{
+	int expected_len, len = 0;
+	u32 dummy32;
+	char *buf;
+
+	DECODE_HEAD;
+	iattr->ia_valid = 0;
+	if ((status = nfsd4_decode_bitmap(argp, bmval)))
+		return status;
+
+	/*
+	 * According to spec, unsupported attributes return ERR_NOTSUPP;
+	 * read-only attributes return ERR_INVAL.
+	 */
+	if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
+		return nfserr_notsupp;
+	if ((bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0) || (bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1))
+		return nfserr_inval;
+
+	READ_BUF(4);
+	READ32(expected_len);
+
+	if (bmval[0] & FATTR4_WORD0_SIZE) {
+		READ_BUF(8);
+		len += 8;
+		READ64(iattr->ia_size);
+		iattr->ia_valid |= ATTR_SIZE;
+	}
+	if (bmval[1] & FATTR4_WORD1_MODE) {
+		READ_BUF(4);
+		len += 4;
+		READ32(iattr->ia_mode);
+		iattr->ia_mode &= (S_IFMT | S_IALLUGO);
+		iattr->ia_valid |= ATTR_MODE;
+	}
+	if (bmval[1] & FATTR4_WORD1_OWNER) {
+		READ_BUF(4);
+		len += 4;
+		READ32(dummy32);
+		READ_BUF(dummy32);
+		len += (XDR_QUADLEN(dummy32) << 2);
+		READMEM(buf, dummy32);
+		if (check_utf8(buf, dummy32))
+			return nfserr_inval;
+		if ((status = name_get_uid(buf, dummy32, &iattr->ia_uid)))
+			goto out_nfserr;
+		iattr->ia_valid |= ATTR_UID;
+	}
+	if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
+		READ_BUF(4);
+		len += 4;
+		READ32(dummy32);
+		READ_BUF(dummy32);
+		len += (XDR_QUADLEN(dummy32) << 2);
+		READMEM(buf, dummy32);
+		if (check_utf8(buf, dummy32))
+			return nfserr_inval;
+		if ((status = name_get_gid(buf, dummy32, &iattr->ia_gid)))
+			goto out_nfserr;
+		iattr->ia_valid |= ATTR_GID;
+	}
+	if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
+		READ_BUF(4);
+		len += 4;
+		READ32(dummy32);
+		switch (dummy32) {
+		case NFS4_SET_TO_CLIENT_TIME:
+			/* We require the high 32 bits of 'seconds' to be 0, and we ignore
+			   all 32 bits of 'nseconds'. */
+			READ_BUF(12);
+			len += 12;
+			READ32(dummy32);
+			if (dummy32)
+				return nfserr_inval;
+			READ32(iattr->ia_atime);
+			READ32(dummy32);
+			if (dummy32 >= (u32)1000000000)
+				return nfserr_inval;
+			iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
+			break;
+		case NFS4_SET_TO_SERVER_TIME:
+			iattr->ia_valid |= ATTR_ATIME;
+			break;
+		default:
+			goto xdr_error;
+		}
+	}
+	if (bmval[1] & FATTR4_WORD1_TIME_METADATA) {
+		/* We require the high 32 bits of 'seconds' to be 0, and we ignore
+		   all 32 bits of 'nseconds'. */
+		READ_BUF(12);
+		len += 12;
+		READ32(dummy32);
+		if (dummy32)
+			return nfserr_inval;
+		READ32(iattr->ia_ctime);
+		READ32(dummy32);
+		if (dummy32 >= (u32)1000000000)
+			return nfserr_inval;
+		iattr->ia_valid |= ATTR_CTIME;
+	}
+	if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
+		READ_BUF(4);
+		len += 4;
+		READ32(dummy32);
+		switch (dummy32) {
+		case NFS4_SET_TO_CLIENT_TIME:
+			/* We require the high 32 bits of 'seconds' to be 0, and we ignore
+			   all 32 bits of 'nseconds'. */
+			READ_BUF(12);
+			len += 12;
+			READ32(dummy32);
+			if (dummy32)
+				return nfserr_inval;
+			READ32(iattr->ia_mtime);
+			READ32(dummy32);
+			if (dummy32 >= (u32)1000000000)
+				return nfserr_inval;
+			iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
+			break;
+		case NFS4_SET_TO_SERVER_TIME:
+			iattr->ia_valid |= ATTR_MTIME;
+			break;
+		default:
+			goto xdr_error;
+		}
+	}
+	if (len != expected_len)
+		goto xdr_error;
+
+	DECODE_TAIL;
+
+out_nfserr:
+	status = nfserrno(status);
+	goto out;
+}
+
+static int
+nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4);
+	READ32(access->ac_req_access);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4 + sizeof(stateid_t));
+	READ32(close->cl_seqid);
+	READ32(close->cl_stateid.st_generation);
+	COPYMEM(&close->cl_stateid.st_other, sizeof(stateid_other_t));
+
+	DECODE_TAIL;
+}
+
+
+static int
+nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
+{
+	DECODE_HEAD;
+
+	READ_BUF(12);
+	READ64(commit->co_offset);
+	READ32(commit->co_count);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4);
+	READ32(create->cr_type);
+	switch (create->cr_type) {
+	case NF4LNK:
+		READ_BUF(4);
+		READ32(create->cr_linklen);
+		READ_BUF(create->cr_linklen);
+		READMEM(create->cr_linkname, create->cr_linklen);
+		if (check_utf8(create->cr_linkname, create->cr_linklen))
+			return nfserr_inval;
+		break;
+	case NF4BLK:
+	case NF4CHR:
+		READ_BUF(8);
+		READ32(create->cr_specdata1);
+		READ32(create->cr_specdata2);
+		break;
+	case NF4SOCK:
+	case NF4FIFO:
+	case NF4DIR:
+		break;
+	default:
+		goto xdr_error;
+	}
+
+	READ_BUF(4);
+	READ32(create->cr_namelen);
+	READ_BUF(create->cr_namelen);
+	READMEM(create->cr_name, create->cr_namelen);
+	if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
+		return status;
+
+	if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr)))
+		goto out;
+
+	DECODE_TAIL;
+}
+
+static inline int
+nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
+{
+	return nfsd4_decode_bitmap(argp, getattr->ga_bmval);
+}
+
+static int
+nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4);
+	READ32(link->li_namelen);
+	READ_BUF(link->li_namelen);
+	READMEM(link->li_name, link->li_namelen);
+	if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval)))
+		return status;
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4);
+	READ32(lookup->lo_len);
+	READ_BUF(lookup->lo_len);
+	READMEM(lookup->lo_name, lookup->lo_len);
+	if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent)))
+		return status;
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
+{
+	DECODE_HEAD;
+
+	memset(open->op_bmval, 0, sizeof(open->op_bmval));
+	open->op_iattr.ia_valid = 0;
+
+	/* seqid, share_access, share_deny, clientid, ownerlen */
+	READ_BUF(16 + sizeof(clientid_t));
+	READ32(open->op_seqid);
+	READ32(open->op_share_access);
+	READ32(open->op_share_deny);
+	COPYMEM(&open->op_clientid, sizeof(clientid_t));
+	READ32(open->op_ownerlen);
+
+	/* owner, open_flag */
+	READ_BUF(open->op_ownerlen + 4);
+	READMEM(open->op_owner, open->op_ownerlen);
+	READ32(open->op_create);
+	switch (open->op_create) {
+	case NFS4_OPEN_NOCREATE:
+		break;
+	case NFS4_OPEN_CREATE:
+		READ_BUF(4);
+		READ32(open->op_createmode);
+		switch (open->op_createmode) {
+		case NFS4_CREATE_UNCHECKED:
+		case NFS4_CREATE_GUARDED:
+			if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr)))
+				goto out;
+			break;
+		case NFS4_CREATE_EXCLUSIVE:
+			READ_BUF(8);
+			COPYMEM(open->op_verf, 8);
+			break;
+		default:
+			goto xdr_error;
+		}
+		break;
+	default:
+		goto xdr_error;
+	}
+
+	/* open_claim */
+	READ_BUF(4);
+	READ32(open->op_claim_type);
+	switch (open->op_claim_type) {
+	case NFS4_OPEN_CLAIM_NULL:
+	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
+		READ_BUF(4);
+		READ32(open->op_namelen);
+		READ_BUF(open->op_namelen);
+		READMEM(open->op_name, open->op_namelen);
+		if ((status = check_filename(open->op_name, open->op_namelen, nfserr_inval)))
+			return status;
+		break;
+	case NFS4_OPEN_CLAIM_PREVIOUS:
+		READ_BUF(4);
+		READ32(open->op_delegate_type);
+		break;
+	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+		READ_BUF(sizeof(delegation_stateid_t) + 4);
+		COPYMEM(&open->op_delegate_stateid, sizeof(delegation_stateid_t));
+		READ32(open->op_namelen);
+		READ_BUF(open->op_namelen);
+		READMEM(open->op_name, open->op_namelen);
+		if ((status = check_filename(open->op_name, open->op_namelen, nfserr_inval)))
+			return status;
+		break;
+	default:
+		goto xdr_error;
+	}
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4);
+	READ32(putfh->pf_fhlen);
+	if (putfh->pf_fhlen > NFS4_FHSIZE)
+		goto xdr_error;
+	READ_BUF(putfh->pf_fhlen);
+	READMEM(putfh->pf_fhval, putfh->pf_fhlen);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
+{
+	DECODE_HEAD;
+
+	READ_BUF(sizeof(stateid_t) + 12);
+	READ32(read->rd_stateid.st_generation);
+	COPYMEM(&read->rd_stateid.st_other, sizeof(stateid_other_t));
+	READ64(read->rd_offset);
+	READ32(read->rd_length);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
+{
+	DECODE_HEAD;
+
+	READ_BUF(24);
+	READ64(readdir->rd_cookie);
+	COPYMEM(readdir->rd_verf, sizeof(nfs4_verifier));
+	READ32(readdir->rd_dircount);    /* just in case you needed a useless field... */
+	READ32(readdir->rd_maxcount);
+	if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval)))
+		goto out;
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4);
+	READ32(remove->rm_namelen);
+	READ_BUF(remove->rm_namelen);
+	READMEM(remove->rm_name, remove->rm_namelen);
+	if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent)))
+		return status;
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
+{
+	DECODE_HEAD;
+
+	READ_BUF(4);
+	READ32(rename->rn_snamelen);
+	READ_BUF(rename->rn_snamelen + 4);
+	READMEM(rename->rn_sname, rename->rn_snamelen);
+	READ32(rename->rn_tnamelen);
+	READ_BUF(rename->rn_tnamelen);
+	READMEM(rename->rn_tname, rename->rn_tnamelen);
+	if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent)))
+		return status;
+	if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval)))
+		return status;
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
+{
+	DECODE_HEAD;
+
+	READ_BUF(sizeof(clientid_t));
+	COPYMEM(clientid, sizeof(clientid_t));
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
+{
+	DECODE_HEAD;
+
+	READ_BUF(sizeof(stateid_t));
+	READ32(setattr->sa_stateid.st_generation);
+	COPYMEM(&setattr->sa_stateid.st_other, sizeof(stateid_other_t));
+	if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr)))
+		goto out;
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
+{
+	DECODE_HEAD;
+
+	READ_BUF(12);
+	COPYMEM(setclientid->se_verf, 8);
+	READ32(setclientid->se_namelen);
+
+	READ_BUF(setclientid->se_namelen + 8);
+	READMEM(setclientid->se_name, setclientid->se_namelen);
+	READ32(setclientid->se_callback_prog);
+	READ32(setclientid->se_callback_netid_len);
+
+	READ_BUF(setclientid->se_callback_netid_len + 4);
+	READMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
+	READ32(setclientid->se_callback_addr_len);
+
+	READ_BUF(setclientid->se_callback_addr_len + 4);
+	READMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
+	READ32(setclientid->se_callback_ident);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, clientid_t *clientid)
+{
+	DECODE_HEAD;
+
+	READ_BUF(8);
+	COPYMEM(clientid, 8);
+
+	DECODE_TAIL;
+}
+
+/* Also used for NVERIFY */
+static int
+nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
+{
+	DECODE_HEAD;
+
+	if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval)))
+		goto out;
+	READ_BUF(4);
+	READ32(verify->ve_attrlen);
+	READ_BUF(verify->ve_attrlen);
+	READMEM(verify->ve_attrval, verify->ve_attrlen);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
+{
+	DECODE_HEAD;
+
+	READ_BUF(sizeof(stateid_t) + 16);
+	READ32(write->wr_stateid.st_generation);
+	COPYMEM(&write->wr_stateid.st_other, sizeof(stateid_other_t));
+	READ64(write->wr_offset);
+	READ32(write->wr_stable_how);
+	if (write->wr_stable_how > 2)
+		goto xdr_error;
+	READ32(write->wr_buflen);
+
+	READ_BUF(write->wr_buflen);
+	READMEM(write->wr_buf, write->wr_buflen);
+
+	DECODE_TAIL;
+}
+
+static int
+nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
+{
+	DECODE_HEAD;
+	struct nfsd4_op *op;
+	int i;
+
+	/*
+	 * XXX: According to spec, we should check the tag
+	 * for UTF-8 compliance.  I'm postponing this for
+	 * now because it seems that some clients do use
+	 * binary tags.
+	 */
+	READ_BUF(4);
+	READ32(argp->taglen);
+	READ_BUF(argp->taglen + 8);
+	READMEM(argp->tag, argp->taglen);
+	READ32(argp->minorversion);
+	READ32(argp->opcnt);
+
+	if (argp->taglen > NFSD4_MAX_TAGLEN)
+		goto xdr_error;
+	if (argp->opcnt > 100)
+		goto xdr_error;
+
+	if (argp->opcnt > sizeof(argp->iops)/sizeof(argp->iops[0])) {
+		argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
+		if (!argp->ops) {
+			argp->ops = argp->iops;
+			printk(KERN_INFO "nfsd: couldn't allocate room for COMPOUND\n");
+			goto xdr_error;
+		}
+	}
+
+	for (i = 0; i < argp->opcnt; i++) {
+		op = &argp->ops[i];
+
+		/*
+		 * Before reading the opcode, we test for the 4-byte buffer
+		 * overrun explicitly, instead of using READ_BUF().  This is
+		 * because we want a missing opcode to be treated as opcode
+		 * OP_WRITE+1, instead of a failed XDR.
+		 */
+		if (argp->p == argp->end) {
+			op->opnum = OP_WRITE + 1;
+			op->status = nfserr_bad_xdr;
+			argp->opcnt = i+1;
+			break;
+		}
+		op->opnum = ntohl(*argp->p++);
+
+		switch (op->opnum) {
+		case OP_ACCESS:
+			op->status = nfsd4_decode_access(argp, &op->u.access);
+			break;
+		case OP_CLOSE:
+			op->status = nfsd4_decode_close(argp, &op->u.close);
+			break;
+		case OP_COMMIT:
+			op->status = nfsd4_decode_commit(argp, &op->u.commit);
+			break;
+		case OP_CREATE:
+			op->status = nfsd4_decode_create(argp, &op->u.create);
+			break;
+		case OP_GETATTR:
+			op->status = nfsd4_decode_getattr(argp, &op->u.getattr);
+			break;
+		case OP_GETFH:
+			op->status = nfs_ok;
+			break;
+		case OP_LINK:
+			op->status = nfsd4_decode_link(argp, &op->u.link);
+			break;
+		case OP_LOOKUP:
+			op->status = nfsd4_decode_lookup(argp, &op->u.lookup);
+			break;
+		case OP_LOOKUPP:
+			op->status = nfs_ok;
+			break;
+		case OP_NVERIFY:
+			op->status = nfsd4_decode_verify(argp, &op->u.nverify);
+			break;
+		case OP_OPEN:
+			op->status = nfsd4_decode_open(argp, &op->u.open);
+			break;
+		case OP_PUTFH:
+			op->status = nfsd4_decode_putfh(argp, &op->u.putfh);
+			break;
+		case OP_PUTROOTFH:
+			op->status = nfs_ok;
+			break;
+		case OP_READ:
+			op->status = nfsd4_decode_read(argp, &op->u.read);
+			break;
+		case OP_READDIR:
+			op->status = nfsd4_decode_readdir(argp, &op->u.readdir);
+			break;
+		case OP_READLINK:
+			op->status = nfs_ok;
+			break;
+		case OP_REMOVE:
+			op->status = nfsd4_decode_remove(argp, &op->u.remove);
+			break;
+		case OP_RENAME:
+			op->status = nfsd4_decode_rename(argp, &op->u.rename);
+			break;
+		case OP_RESTOREFH:
+			op->status = nfs_ok;
+			break;
+		case OP_RENEW:
+			op->status = nfsd4_decode_renew(argp, &op->u.renew);
+			break;
+		case OP_SAVEFH:
+			op->status = nfs_ok;
+			break;
+		case OP_SETATTR:
+			op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
+			break;
+		case OP_SETCLIENTID:
+			op->status = nfsd4_decode_setclientid(argp, &op->u.setclientid);
+			break;
+		case OP_SETCLIENTID_CONFIRM:
+			op->status = nfsd4_decode_setclientid_confirm(argp, &op->u.setclientid_confirm);
+			break;
+		case OP_VERIFY:
+			op->status = nfsd4_decode_verify(argp, &op->u.verify);
+			break;
+		case OP_WRITE:
+			op->status = nfsd4_decode_write(argp, &op->u.write);
+			break;
+		default:
+			/*
+			 * According to spec, anything greater than OP_WRITE
+			 * is treated as OP_WRITE+1 in the response.
+			 */
+			if (op->opnum > OP_WRITE)
+			op->opnum = OP_WRITE + 1;
+			op->status = nfserr_notsupp;
+			break;
+		}
+
+		if (op->status) {
+			argp->opcnt = i+1;
+			break;
+		}
+	}
+
+	DECODE_TAIL;
+}
+/*
+ * END OF "GENERIC" DECODE ROUTINES.
+ */
+
+/*
+ * START OF "GENERIC" ENCODE ROUTINES.
+ *   These may look a little ugly since they are imported from a "generic"
+ * set of XDR encode/decode routines which are intended to be shared by
+ * all of our NFSv4 implementations (OpenBSD, MacOS X...).
+ *
+ * If the pain of reading these is too great, it should be a straightforward
+ * task to translate them into Linux-specific versions which are more
+ * consistent with the style used in NFSv2/v3...
+ */
+#define ENCODE_HEAD              u32 *p
+
+#define WRITE32(n)               *p++ = htonl(n)
+#define WRITE64(n)               do {				\
+	*p++ = htonl((u32)((n) >> 32));				\
+	*p++ = htonl((u32)(n));					\
+} while (0)
+#define WRITEMEM(ptr,nbytes)     do {				\
+	memcpy(p, ptr, nbytes);					\
+	p += XDR_QUADLEN(nbytes);				\
+} while (0)
+#define WRITECINFO(c)		do {				\
+	*p++ = htonl(c.atomic);					\
+	*p++ = htonl(c.before_size);				\
+	*p++ = htonl(c.before_ctime);				\
+	*p++ = htonl(c.after_size);				\
+	*p++ = htonl(c.after_ctime);				\
+} while (0)
+
+#define RESERVE_SPACE(nbytes)	do {				\
+	p = resp->p;						\
+	BUG_ON(p + XDR_QUADLEN(nbytes) > resp->end);		\
+} while (0)
+#define ADJUST_ARGS()		resp->p = p
+
+static u32 nfs4_ftypes[16] = {
+        NF4BAD,  NF4FIFO, NF4CHR, NF4BAD,
+        NF4DIR,  NF4BAD,  NF4BLK, NF4BAD,
+        NF4REG,  NF4BAD,  NF4LNK, NF4BAD,
+        NF4SOCK, NF4BAD,  NF4LNK, NF4BAD,
+};
+
+/*
+ * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
+ * ourselves.
+ *
+ * @countp is the buffer size in _words_; upon successful return this becomes
+ * replaced with the number of words written.
+ */
+int
+nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+		   struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval)
+{
+	u32 bmval0 = bmval[0];
+	u32 bmval1 = bmval[1];
+	struct kstat stat;
+	struct name_ent *owner = NULL;
+	struct name_ent *group = NULL;
+	struct svc_fh tempfh;
+	struct statfs statfs;
+	int buflen = *countp << 2;
+	u32 *attrlenp;
+	u32 dummy;
+	u64 dummy64;
+	u32 *p = buffer;
+	int status;
+
+	BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
+	BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
+	BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
+
+	status = vfs_getattr(exp->ex_mnt, dentry, &stat);
+	if (status)
+		goto out_nfserr;
+	if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
+	    (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
+		       FATTR4_WORD1_SPACE_TOTAL))) {
+		status = vfs_statfs(dentry->d_inode->i_sb, &statfs);
+		if (status)
+			goto out_nfserr;
+	}
+	if ((bmval0 & FATTR4_WORD0_FILEHANDLE) && !fhp) {
+		fh_init(&tempfh, NFS4_FHSIZE);
+		status = fh_compose(&tempfh, exp, dentry, NULL);
+		if (status)
+			goto out;
+		fhp = &tempfh;
+	}
+	if (bmval1 & FATTR4_WORD1_OWNER) {
+		status = name_get_user(stat.uid, &owner);
+		if (status)
+			goto out_nfserr;
+	}
+	if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
+		status = name_get_group(stat.gid, &group);
+		if (status)
+			goto out_nfserr;
+	}
+
+	if ((buflen -= 16) < 0)
+		goto out_resource;
+
+	WRITE32(2);
+	WRITE32(bmval0);
+	WRITE32(bmval1);
+	attrlenp = p++;                /* to be backfilled later */
+
+	if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
+		if ((buflen -= 12) < 0)
+			goto out_resource;
+		WRITE32(2);
+		WRITE32(NFSD_SUPPORTED_ATTRS_WORD0);
+		WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
+	}
+	if (bmval0 & FATTR4_WORD0_TYPE) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		dummy = nfs4_ftypes[(stat.mode & S_IFMT) >> 12];
+		if (dummy == NF4BAD)
+			goto out_serverfault;
+		WRITE32(dummy);
+	}
+	if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32( NFS4_FH_NOEXPIRE_WITH_OPEN | NFS4_FH_VOL_RENAME );
+	}
+	if (bmval0 & FATTR4_WORD0_CHANGE) {
+		/*
+		 * XXX: We currently use the inode ctime as the nfsv4 "changeid"
+		 * attribute.  This violates the spec, which says
+		 *
+		 *    The server may return the object's time_modify attribute
+		 *    for this attribute, but only if the file system object
+		 *    can not be updated more frequently than the resolution
+		 *    of time_modify.
+		 *
+		 * Since we only have 1-second ctime resolution, this is a pretty
+		 * serious violation.  Indeed, 1-second ctime resolution is known
+		 * to be a problem in practice in the NFSv3 world.
+		 *
+		 * The real solution to this problem is probably to work on
+		 * adding high-resolution mtimes to the VFS layer.
+		 *
+		 * Note: Started using i_size for the high 32 bits of the changeid.
+		 *
+		 * Note 2: This _must_ be consistent with the scheme for writing
+		 * change_info, so any changes made here must be reflected there
+		 * as well.  (See xdr4.h:set_change_info() and the WRITECINFO()
+		 * macro above.)
+		 */
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE32(stat.size);
+		WRITE32(stat.mtime);
+	}
+	if (bmval0 & FATTR4_WORD0_SIZE) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64(stat.size);
+	}
+	if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval0 & FATTR4_WORD0_NAMED_ATTR) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(0);
+	}
+	if (bmval0 & FATTR4_WORD0_FSID) {
+		if ((buflen -= 16) < 0)
+			goto out_resource;
+		WRITE32(0);
+		WRITE32(MAJOR(stat.dev));
+		WRITE32(0);
+		WRITE32(MINOR(stat.dev));
+	}
+	if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(0);
+	}
+	if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(NFSD_LEASE_TIME);
+	}
+	if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(0);
+	}
+	if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(0);
+	}
+	if (bmval0 & FATTR4_WORD0_CANSETTIME) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval0 & FATTR4_WORD0_FILEHANDLE) {
+		buflen -= (XDR_QUADLEN(fhp->fh_handle.fh_size) << 2) + 4;
+		if (buflen < 0)
+			goto out_resource;
+		WRITE32(fhp->fh_handle.fh_size);
+		WRITEMEM(&fhp->fh_handle.fh_base, fhp->fh_handle.fh_size);
+	}
+	if (bmval0 & FATTR4_WORD0_FILEID) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64((u64) stat.ino);
+	}
+	if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64((u64) statfs.f_ffree);
+	}
+	if (bmval0 & FATTR4_WORD0_FILES_FREE) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64((u64) statfs.f_ffree);
+	}
+	if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64((u64) statfs.f_files);
+	}
+	if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64(~(u64)0);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXLINK) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(255);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXNAME) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(~(u32) 0);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXREAD) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64((u64) NFSSVC_MAXBLKSIZE);
+	}
+	if (bmval0 & FATTR4_WORD0_MAXWRITE) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE64((u64) NFSSVC_MAXBLKSIZE);
+	}
+	if (bmval1 & FATTR4_WORD1_MODE) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(stat.mode & S_IALLUGO);
+	}
+	if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(1);
+	}
+	if (bmval1 & FATTR4_WORD1_NUMLINKS) {
+		if ((buflen -= 4) < 0)
+			goto out_resource;
+		WRITE32(stat.nlink);
+	}
+	if (bmval1 & FATTR4_WORD1_OWNER) {
+		int namelen  = strlen(owner->name);
+		buflen -= (XDR_QUADLEN(namelen) << 2) + 4;
+		if (buflen < 0)
+			goto out_resource;
+		WRITE32(namelen);
+		WRITEMEM(owner->name, namelen);
+	}
+	if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
+		int namelen = strlen(group->name);
+		buflen -= (XDR_QUADLEN(namelen) << 2) + 4;
+		if (buflen < 0)
+			goto out_resource;
+		WRITE32(namelen);
+		WRITEMEM(group->name, namelen);
+	}
+	if (bmval1 & FATTR4_WORD1_RAWDEV) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		WRITE32((u32) MAJOR(stat.rdev));
+		WRITE32((u32) MINOR(stat.rdev));
+	}
+	if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize;
+		WRITE64(dummy64);
+	}
+	if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize;
+		WRITE64(dummy64);
+	}
+	if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize;
+		WRITE64(dummy64);
+	}
+	if (bmval1 & FATTR4_WORD1_SPACE_USED) {
+		if ((buflen -= 8) < 0)
+			goto out_resource;
+		dummy64 = (u64)stat.blocks << 9;
+		WRITE64(dummy64);
+	}
+	if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
+		if ((buflen -= 12) < 0)
+			goto out_resource;
+		WRITE32(0);
+		WRITE32(stat.atime);
+		WRITE32(0);
+	}
+	if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
+		if ((buflen -= 12) < 0)
+			goto out_resource;
+		WRITE32(0);
+		WRITE32(1);
+		WRITE32(0);
+	}
+	if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
+		if ((buflen -= 12) < 0)
+			goto out_resource;
+		WRITE32(0);
+		WRITE32(stat.ctime);
+		WRITE32(0);
+	}
+	if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
+		if ((buflen -= 12) < 0)
+			goto out_resource;
+		WRITE32(0);
+		WRITE32(stat.mtime);
+		WRITE32(0);
+	}
+
+	*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
+	*countp = p - buffer;
+	status = nfs_ok;
+
+out:
+	if (fhp == &tempfh)
+		fh_put(&tempfh);
+	if (owner)
+		name_put(owner);
+	if (group)
+		name_put(group);
+	return status;
+out_nfserr:
+	status = nfserrno(status);
+	goto out;
+out_resource:
+	*countp = 0;
+	status = nfserr_resource;
+	goto out;
+out_serverfault:
+	status = nfserr_serverfault;
+	goto out;
+}
+
+static int
+nfsd4_encode_dirent(struct readdir_cd *cd, const char *name, int namlen,
+		    loff_t offset, ino_t ino, unsigned int d_type)
+{
+	int buflen;
+	u32 *p = cd->buffer;
+	u32 *attrlenp;
+	struct dentry *dentry;
+	u32 bmval0, bmval1;
+	int nfserr = 0;
+
+	/* In nfsv4, "." and ".." never make it onto the wire.. */
+	if (name && isdotent(name, namlen))
+		return 0;
+
+	if (cd->offset)
+		xdr_encode_hyper(cd->offset, (u64) offset);
+
+	/* nfsd_readdir calls us with name == 0 when it wants us to
+	 * set the last offset entry. */
+	if (name == 0)
+		return 0;
+
+	buflen = cd->buflen - 4 - XDR_QUADLEN(namlen);
+	if (buflen < 0)
+		goto nospc;
+
+	*p++ = xdr_one;                             /* mark entry present */
+	cd->offset = p;                             /* remember pointer */
+	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
+	p = xdr_encode_array(p, name, namlen);      /* name length & name */
+
+	/*
+	 * Now we come to the ugly part: writing the fattr for this entry.
+	 */
+	bmval0 = cd->bmval[0];
+	bmval1 = cd->bmval[1];
+	if ((bmval0 & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_FILEID)) || bmval1)  {
+		/*
+		 * "Heavyweight" case: we have no choice except to
+		 * call nfsd4_encode_fattr().  As far as I know,
+		 * only Windows clients will trigger this code
+		 * path.
+		 */
+		dentry = lookup_one_len(name, cd->dirfh->fh_dentry, namlen);
+		if (IS_ERR(dentry)) {
+			nfserr = nfserrno(PTR_ERR(dentry));
+			goto error;
+		}
+
+		nfserr = nfsd4_encode_fattr(NULL, cd->dirfh->fh_export,
+					    dentry, p, &buflen, cd->bmval);
+		dput(dentry);
+
+		if (!nfserr) {
+			p += buflen;
+			goto out;
+		}
+		if (nfserr == nfserr_resource)
+			goto nospc;
+
+error:
+		/*
+		 * If we get here, we experienced a miscellaneous
+		 * failure while writing the attributes.  If the
+		 * client requested the RDATTR_ERROR attribute,
+		 * we stuff the error code into this attribute
+		 * and continue.  If this attribute was not requested,
+		 * then in accordance with the spec, we fail the
+		 * entire READDIR operation(!)
+		 */
+		if (!(bmval0 & FATTR4_WORD0_RDATTR_ERROR)) {
+			cd->nfserr = nfserr;
+			return -EINVAL;
+		}
+
+		bmval0 = FATTR4_WORD0_RDATTR_ERROR;
+		bmval1 = 0;
+		/* falling through here will do the right thing... */
+	}
+
+	/*
+	 * In the common "lightweight" case, we avoid
+	 * the overhead of nfsd4_encode_fattr() by assembling
+	 * a small fattr by hand.
+	 */
+	if (buflen < 6)
+		goto nospc;
+	*p++ = htonl(2);
+	*p++ = htonl(bmval0);
+	*p++ = htonl(bmval1);
+
+	attrlenp = p++;
+	if (bmval0 & FATTR4_WORD0_RDATTR_ERROR)
+		*p++ = nfserr;       /* no htonl */
+	if (bmval0 & FATTR4_WORD0_FILEID)
+		p = xdr_encode_hyper(p, (u64)ino);
+	*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
+
+out:
+	cd->buflen -= (p - cd->buffer);
+	cd->buffer = p;
+	return 0;
+
+nospc:
+	cd->eob = 1;
+	return -EINVAL;
+}
+
+static void
+nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_access *access)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(8);
+		WRITE32(access->ac_supported);
+		WRITE32(access->ac_resp_access);
+		ADJUST_ARGS();
+	}
+}
+
+static void
+nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_close *close)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(sizeof(stateid_t));
+		WRITE32(close->cl_stateid.st_generation);
+		WRITEMEM(&close->cl_stateid.st_other, sizeof(stateid_other_t));
+		ADJUST_ARGS();
+	}
+}
+
+
+static void
+nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_commit *commit)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(8);
+		WRITEMEM(commit->co_verf, 8);
+		ADJUST_ARGS();
+	}
+}
+
+static void
+nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_create *create)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(32);
+		WRITECINFO(create->cr_cinfo);
+		WRITE32(2);
+		WRITE32(create->cr_bmval[0]);
+		WRITE32(create->cr_bmval[1]);
+		ADJUST_ARGS();
+	}
+}
+
+static int
+nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_getattr *getattr)
+{
+	struct svc_fh *fhp = getattr->ga_fhp;
+	int buflen;
+
+	if (nfserr)
+		return nfserr;
+
+	buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
+	nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
+				    resp->p, &buflen, getattr->ga_bmval);
+
+	if (!nfserr)
+		resp->p += buflen;
+	return nfserr;
+}
+
+static void
+nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fhp)
+{
+	unsigned int len;
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		len = fhp->fh_handle.fh_size;
+		RESERVE_SPACE(len + 4);
+		WRITE32(len);
+		WRITEMEM(&fhp->fh_handle.fh_base, len);
+		ADJUST_ARGS();
+	}
+}
+
+static void
+nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(20);
+		WRITECINFO(link->li_cinfo);
+		ADJUST_ARGS();
+	}
+}
+
+
+static void
+nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open *open)
+{
+	ENCODE_HEAD;
+
+	if (nfserr)
+		return;
+
+	RESERVE_SPACE(36 + sizeof(stateid_t));
+	WRITE32(open->op_stateid.st_generation);
+	WRITEMEM(&open->op_stateid.st_other, sizeof(stateid_other_t));
+	WRITECINFO(open->op_cinfo);
+	WRITE32(open->op_rflags);
+	WRITE32(2);
+	WRITE32(open->op_bmval[0]);
+	WRITE32(open->op_bmval[1]);
+	WRITE32(open->op_delegate_type);
+	ADJUST_ARGS();
+
+	switch (open->op_delegate_type) {
+	case NFS4_OPEN_DELEGATE_NONE:
+		break;
+	case NFS4_OPEN_DELEGATE_READ:
+		RESERVE_SPACE(20 + sizeof(delegation_stateid_t));
+		WRITEMEM(&open->op_delegate_stateid, sizeof(delegation_stateid_t));
+		WRITE32(0);
+
+		/*
+		 * TODO: ACE's in delegations
+		 */
+		WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
+		WRITE32(0);
+		WRITE32(0);
+		WRITE32(0);   /* XXX: is NULL principal ok? */
+		ADJUST_ARGS();
+		break;
+	case NFS4_OPEN_DELEGATE_WRITE:
+		RESERVE_SPACE(32 + sizeof(delegation_stateid_t));
+		WRITEMEM(&open->op_delegate_stateid, sizeof(delegation_stateid_t));
+		WRITE32(0);
+
+		/*
+		 * TODO: space_limit's in delegations
+		 */
+		WRITE32(NFS4_LIMIT_SIZE);
+		WRITE32(~(u32)0);
+		WRITE32(~(u32)0);
+
+		/*
+		 * TODO: ACE's in delegations
+		 */
+		WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
+		WRITE32(0);
+		WRITE32(0);
+		WRITE32(0);   /* XXX: is NULL principal ok? */
+		ADJUST_ARGS();
+		break;
+	default:
+		BUG();
+	}
+}
+
+static int
+nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
+{
+	u32 eof;
+	unsigned long maxcount;
+	ENCODE_HEAD;
+
+	if (nfserr)
+		return nfserr;
+
+	maxcount = (char *)resp->end - (char *)resp->p - COMPOUND_ERR_SLACK_SPACE - 8;
+	if (maxcount > read->rd_length)
+		maxcount = read->rd_length;
+	RESERVE_SPACE(maxcount + 8);
+
+	nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp,
+			   read->rd_offset, (char *)p + 8, &maxcount);
+	if (nfserr)
+		return nfserr;
+	eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);
+
+	WRITE32(eof);
+	WRITE32(maxcount);
+	p += XDR_QUADLEN(maxcount);
+	ADJUST_ARGS();
+	return 0;
+}
+
+static int
+nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readlink *readlink)
+{
+	int maxcount;
+	ENCODE_HEAD;
+
+	if (nfserr)
+		return nfserr;
+
+	maxcount = (char *)resp->end - (char *)resp->p - COMPOUND_ERR_SLACK_SPACE - 4;
+	RESERVE_SPACE(maxcount + 4);
+
+	/*
+	 * XXX: By default, the ->readlink() VFS op will truncate symlinks
+	 * if they would overflow the buffer.  Is this kosher in NFSv4?  If
+	 * not, one easy fix is: if ->readlink() precisely fills the buffer,
+	 * assume that truncation occured, and return NFS4ERR_RESOURCE.
+	 */
+	nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, (char *)p + 4, &maxcount);
+	if (nfserr)
+		return nfserr;
+
+	WRITE32(maxcount);
+	p += XDR_QUADLEN(maxcount);
+	ADJUST_ARGS();
+	return 0;
+}
+
+static int
+nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir)
+{
+	int maxcount;
+	ENCODE_HEAD;
+
+	if (nfserr)
+		return nfserr;
+
+	RESERVE_SPACE(16);
+
+	maxcount = (char *)resp->end - (char *)p - COMPOUND_ERR_SLACK_SPACE;
+	if (maxcount > readdir->rd_maxcount)
+		maxcount = readdir->rd_maxcount;
+
+	/*
+	 * Convert from bytes to words, account for the two words already
+	 * written, make sure to leave two words at the end for the next
+	 * pointer and eof field.
+	 */
+	maxcount = (maxcount >> 2) - 4;
+	if (maxcount < 0)
+		return nfserr_readdir_nospc;
+
+	/* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
+	WRITE32(0);
+	WRITE32(0);
+
+	nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
+			      readdir->rd_cookie, nfsd4_encode_dirent,
+			      p, &maxcount, NULL, readdir->rd_bmval);
+	if (!nfserr) {
+		/*
+		 * nfsd_readdir() expects 'maxcount' to be a count of
+		 * words, but fills it in with a count of bytes at the
+		 * end!
+		 */
+		BUG_ON(maxcount & 3);
+		p += (maxcount >> 2);
+		ADJUST_ARGS();
+	}
+	return nfserr;
+}
+
+static void
+nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_remove *remove)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(20);
+		WRITECINFO(remove->rm_cinfo);
+		ADJUST_ARGS();
+	}
+}
+
+static void
+nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rename *rename)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(40);
+		WRITECINFO(rename->rn_sinfo);
+		WRITECINFO(rename->rn_tinfo);
+		ADJUST_ARGS();
+	}
+}
+
+/*
+ * The SETATTR encode routine is special -- it always encodes a bitmap,
+ * regardless of the error status.
+ */
+static void
+nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setattr *setattr)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(12);
+	if (nfserr) {
+		WRITE32(2);
+		WRITE32(0);
+		WRITE32(0);
+	}
+	else {
+		WRITE32(2);
+		WRITE32(setattr->sa_bmval[0]);
+		WRITE32(setattr->sa_bmval[1]);
+	}
+	ADJUST_ARGS();
+}
+
+static void
+nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setclientid *scd)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(8);
+		WRITEMEM(&scd->se_clientid, 8);
+		ADJUST_ARGS();
+	}
+	else if (nfserr == nfserr_clid_inuse) {
+		RESERVE_SPACE(8);
+		WRITE32(0);
+		WRITE32(0);
+		ADJUST_ARGS();
+	}
+}
+
+static void
+nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_write *write)
+{
+	ENCODE_HEAD;
+
+	if (!nfserr) {
+		RESERVE_SPACE(16);
+		WRITE32(write->wr_bytes_written);
+		WRITE32(write->wr_how_written);
+		WRITEMEM(write->wr_verifier, 8);
+		ADJUST_ARGS();
+	}
+}
+
+void
+nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
+{
+	u32 *statp;
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(8);
+	WRITE32(op->opnum);
+	statp = p++;                  /* to be backfilled at the end */
+	ADJUST_ARGS();
+
+	switch (op->opnum) {
+	case OP_ACCESS:
+		nfsd4_encode_access(resp, op->status, &op->u.access);
+		break;
+	case OP_CLOSE:
+		nfsd4_encode_close(resp, op->status, &op->u.close);
+		break;
+	case OP_COMMIT:
+		nfsd4_encode_commit(resp, op->status, &op->u.commit);
+		break;
+	case OP_CREATE:
+		nfsd4_encode_create(resp, op->status, &op->u.create);
+		break;
+	case OP_GETATTR:
+		op->status = nfsd4_encode_getattr(resp, op->status, &op->u.getattr);
+		break;
+	case OP_GETFH:
+		nfsd4_encode_getfh(resp, op->status, op->u.getfh);
+		break;
+	case OP_LINK:
+		nfsd4_encode_link(resp, op->status, &op->u.link);
+		break;
+	case OP_LOOKUP:
+		break;
+	case OP_LOOKUPP:
+		break;
+	case OP_NVERIFY:
+		break;
+	case OP_OPEN:
+		nfsd4_encode_open(resp, op->status, &op->u.open);
+		break;
+	case OP_PUTFH:
+		break;
+	case OP_PUTROOTFH:
+		break;
+	case OP_READ:
+		op->status = nfsd4_encode_read(resp, op->status, &op->u.read);
+		break;
+	case OP_READDIR:
+		op->status = nfsd4_encode_readdir(resp, op->status, &op->u.readdir);
+		break;
+	case OP_READLINK:
+		op->status = nfsd4_encode_readlink(resp, op->status, &op->u.readlink);
+		break;
+	case OP_REMOVE:
+		nfsd4_encode_remove(resp, op->status, &op->u.remove);
+		break;
+	case OP_RENAME:
+		nfsd4_encode_rename(resp, op->status, &op->u.rename);
+		break;
+	case OP_RENEW:
+		break;
+	case OP_RESTOREFH:
+		break;
+	case OP_SAVEFH:
+		break;
+	case OP_SETATTR:
+		nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
+		break;
+	case OP_SETCLIENTID:
+		nfsd4_encode_setclientid(resp, op->status, &op->u.setclientid);
+		break;
+	case OP_SETCLIENTID_CONFIRM:
+		break;
+	case OP_VERIFY:
+		break;
+	case OP_WRITE:
+		nfsd4_encode_write(resp, op->status, &op->u.write);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 * Note: We write the status directly, instead of using WRITE32(),
+	 * since it is already in network byte order.
+	 */
+	*statp = op->status;
+}
+
+/*
+ * END OF "GENERIC" ENCODE ROUTINES.
+ */
+
+static inline int
+xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
+{
+	struct svc_buf	*buf = &rqstp->rq_resbuf;
+
+	buf->len = p - buf->base;
+	dprintk("nfsd: ressize_check p %p base %p len %d\n",
+			p, buf->base, buf->buflen);
+	return (buf->len <= buf->buflen);
+}
+
+int
+nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+        return xdr_ressize_check(rqstp, p);
+}
+
+int
+nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
+{
+	int status;
+
+	args->p = p;
+	args->end = rqstp->rq_argbuf.base + rqstp->rq_argbuf.buflen;
+	args->ops = args->iops;
+
+	status = nfsd4_decode_compound(args);
+	if (status && args->ops != args->iops) {
+		kfree(args->ops);
+		args->ops = args->iops;
+	}
+	return !status;
+}
+
+int
+nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundres *resp)
+{
+	/*
+	 * All that remains is to write the tag and operation count...
+	 */
+	*p++ = htonl(resp->taglen);
+	memcpy(p, resp->tag, resp->taglen);
+	p += XDR_QUADLEN(resp->taglen);
+	*p++ = htonl(resp->opcnt);
+
+	BUG_ON(!xdr_ressize_check(rqstp, resp->p));
+	return 1;
+}
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff -Nru a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
--- a/fs/nfsd/nfsctl.c	Fri Oct 11 21:22:54 2002
+++ b/fs/nfsd/nfsctl.c	Fri Oct 11 21:22:54 2002
@@ -226,7 +226,7 @@
 {
 	struct nfsctl_fsparm data;
 	struct sockaddr_in *sin;
-	struct svc_client *clp;
+	struct auth_domain *clp;
 	int err = 0;
 	struct knfsd_fh *res;
 
@@ -246,10 +246,12 @@
 		return -ENOMEM;
 	memset(res, 0, sizeof(struct knfsd_fh));
 	exp_readlock();
-	if (!(clp = exp_getclient(sin)))
+	if (!(clp = auth_unix_lookup(sin->sin_addr)))
 		err = -EPERM;
-	else
+	else {
 		err = exp_rootfh(clp, data.gd_path, res, data.gd_maxlen);
+		auth_domain_put(clp);
+	}
 	exp_readunlock();
 
 	down(&file->f_dentry->d_inode->i_sem);
@@ -271,7 +273,7 @@
 {
 	struct nfsctl_fdparm data;
 	struct sockaddr_in *sin;
-	struct svc_client *clp;
+	struct auth_domain *clp;
 	int err = 0;
 	struct knfsd_fh fh;
 	char *res;
@@ -291,10 +293,12 @@
 		return -ENOMEM;
 	sin = (struct sockaddr_in *)&data.gd_addr;
 	exp_readlock();
-	if (!(clp = exp_getclient(sin)))
+	if (!(clp = auth_unix_lookup(sin->sin_addr)))
 		err = -EPERM;
-	else
+	else {
 		err = exp_rootfh(clp, data.gd_path, &fh, NFS_FHSIZE);
+		auth_domain_put(clp);
+	}
 	exp_readunlock();
 
 	down(&file->f_dentry->d_inode->i_sem);
diff -Nru a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
--- a/fs/nfsd/nfsfh.c	Fri Oct 11 21:22:55 2002
+++ b/fs/nfsd/nfsfh.c	Fri Oct 11 21:22:55 2002
@@ -86,7 +86,7 @@
 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 {
 	struct knfsd_fh	*fh = &fhp->fh_handle;
-	struct svc_export *exp;
+	struct svc_export *exp = NULL;
 	struct dentry	*dentry;
 	struct inode	*inode;
 	u32		error = 0;
@@ -103,6 +103,8 @@
 		int data_left = fh->fh_size/4;
 
 		error = nfserr_stale;
+		if (rqstp->rq_client == NULL)
+			goto out;
 		if (rqstp->rq_vers > 2)
 			error = nfserr_badhandle;
 		if (rqstp->rq_vers == 4 && fh->fh_size == 0)
@@ -128,7 +130,7 @@
 				goto out;
 			}
 			if ((data_left -= len)<0) goto out;
-			exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap);
+			exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle);
 			datap += len;
 		} else {
 			dev_t xdev;
@@ -139,16 +141,15 @@
 			xdev = u32_to_dev_t(fh->ofh_xdev);
 			xino = u32_to_ino_t(fh->ofh_xino);
 			mk_fsid_v0(tfh, xdev, xino);
-			exp = exp_find(rqstp->rq_client, 0, tfh);
+			exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle);
 		}
 
-		/*
-		 * Look up the export entry.
-		 */
-		error = nfserr_stale; 
+		error = nfserr_dropit;
+		if (IS_ERR(exp))
+			goto out;
 
+		error = nfserr_stale; 
 		if (!exp)
-			/* export entry revoked */
 			goto out;
 
 		/* Check if the request originated from a secure port. */
@@ -219,6 +220,7 @@
 		dentry = fhp->fh_dentry;
 		exp = fhp->fh_export;
 	}
+	cache_get(&exp->h);
 
 	inode = dentry->d_inode;
 
@@ -261,6 +263,8 @@
 	}
 #endif
 out:
+	if (exp && !IS_ERR(exp))
+		exp_put(exp);
 	if (error == nfserr_stale)
 		nfsdstats.fh_stale++;
 	return error;
@@ -342,6 +346,7 @@
 
 	fhp->fh_dentry = dentry; /* our internal copy */
 	fhp->fh_export = exp;
+	cache_get(&exp->h);
 
 	if (ref_fh_version == 0xca) {
 		/* old style filehandle please */
@@ -440,6 +445,7 @@
 fh_put(struct svc_fh *fhp)
 {
 	struct dentry * dentry = fhp->fh_dentry;
+	struct svc_export * exp = fhp->fh_export;
 	if (dentry) {
 		fh_unlock(fhp);
 		fhp->fh_dentry = NULL;
@@ -449,6 +455,10 @@
 		fhp->fh_post_saved = 0;
 #endif
 		nfsd_nr_put++;
+	}
+	if (exp) {
+		svc_export_put(&exp->h, &svc_export_cache);
+		fhp->fh_export = NULL;
 	}
 	return;
 }
diff -Nru a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
--- a/fs/nfsd/nfsproc.c	Fri Oct 11 21:22:55 2002
+++ b/fs/nfsd/nfsproc.c	Fri Oct 11 21:22:55 2002
@@ -545,7 +545,7 @@
   PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, ST+FH+AT),
-  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+256),
+  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
   PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
--- a/fs/nfsd/nfssvc.c	Fri Oct 11 21:22:51 2002
+++ b/fs/nfsd/nfssvc.c	Fri Oct 11 21:22:51 2002
@@ -27,14 +27,16 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/cache.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/stats.h>
 #include <linux/nfsd/cache.h>
 #include <linux/nfsd/xdr.h>
+#include <linux/nfsd/xdr3.h>
+#include <linux/nfsd/xdr4.h>
 #include <linux/lockd/bind.h>
 
 #define NFSDDBG_FACILITY	NFSDDBG_SVC
-#define NFSD_BUFSIZE		(1024 + NFSSVC_MAXBLKSIZE)
 
 /* these signals will be delivered to an nfsd thread 
  * when handling a request
@@ -172,8 +174,6 @@
 	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 
 	nfsdstats.th_cnt++;
-	/* Let svc_process check client's authentication. */
-	rqstp->rq_auth = 1;
 
 	lockd_up();				/* start lockd */
 
@@ -197,7 +197,7 @@
 		 */
 		while ((err = svc_recv(serv, rqstp,
 				       5*60*HZ)) == -EAGAIN)
-		    ;
+			cache_clean();
 		if (err < 0)
 			break;
 		update_thread_usage(atomic_read(&nfsd_busy));
@@ -206,10 +206,6 @@
 		/* Lock the export hash tables for reading. */
 		exp_readlock();
 
-		/* Validate the client's address. This will also defeat
-		 * port probes on port 2049 by unauthorized clients.
-		 */
-		rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
 		/* Process request with signals blocked.  */
 		spin_lock_irq(&current->sig->siglock);
 		siginitsetinv(&current->blocked, ALLOWED_SIGS);
@@ -337,10 +333,23 @@
 		.vs_dispatch	= nfsd_dispatch
 };
 #endif
+#ifdef CONFIG_NFSD_V4
+static struct svc_version	nfsd_version4 = {
+		.vs_vers	= 4,
+		.vs_nproc	= 2,
+		.vs_proc	= nfsd_procedures4,
+		.vs_dispatch	= nfsd_dispatch
+};
+#endif
 static struct svc_version *	nfsd_version[] = {
 	[2] = &nfsd_version2,
-#ifdef CONFIG_NFSD_V3
+#if defined(CONFIG_NFSD_V3)
 	[3] = &nfsd_version3,
+#elif defined(CONFIG_NFSD_V4)
+	[3] = NULL,
+#endif
+#if defined(CONFIG_NFSD_V4)
+	[4] = &nfsd_version4,
 #endif
 };
 
@@ -352,5 +361,6 @@
 	.pg_nvers		= NFSD_NRVERS,		/* nr of entries in nfsd_version */
 	.pg_vers		= nfsd_version,		/* version table */
 	.pg_name		= "nfsd",		/* program name */
+	.pg_class		= "nfsd",		/* authentication class */
 	.pg_stats		= &nfsd_svcstats,	/* version table */
 };
diff -Nru a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
--- a/fs/nfsd/nfsxdr.c	Fri Oct 11 21:22:51 2002
+++ b/fs/nfsd/nfsxdr.c	Fri Oct 11 21:22:51 2002
@@ -81,7 +81,7 @@
 	char		*name;
 	int		i;
 
-	if ((p = xdr_decode_string(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
+	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
 			if (*name == '\0')
 				return NULL;
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Fri Oct 11 21:22:55 2002
+++ b/fs/nfsd/vfs.c	Fri Oct 11 21:22:55 2002
@@ -130,11 +130,13 @@
 			dput(dentry);
 			dentry = dp;
 
-			exp2 = exp_parent(exp->ex_client, mnt, dentry);
+			exp2 = exp_parent(exp->ex_client, mnt, dentry,
+					  &rqstp->rq_chandle);
 			if (!exp2) {
 				dput(dentry);
 				dentry = dget(dparent);
 			} else {
+				exp_put(exp);
 				exp = exp2;
 			}
 			mntput(mnt);
@@ -154,14 +156,18 @@
 			struct dentry *mounts = dget(dentry);
 			while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts))
 				;
-			exp2 = exp_get_by_name(rqstp->rq_client, mnt, mounts);
+			exp2 = exp_get_by_name(exp->ex_client, mnt, 
+					       mounts, &rqstp->rq_chandle);
 			if (exp2 && EX_CROSSMNT(exp2)) {
 				/* successfully crossed mount point */
+				exp_put(exp);
 				exp = exp2;
 				dput(dentry);
 				dentry = mounts;
-			} else
+			} else {
+				if (exp2) exp_put(exp2);
 				dput(mounts);
+			}
 			mntput(mnt);
 		}
 	}
@@ -1124,7 +1130,19 @@
 	if (IS_ERR(dnew))
 		goto out_nfserr;
 
-	err = vfs_symlink(dentry->d_inode, dnew, path);
+	if (unlikely(path[plen] != 0)) {
+		char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
+		if (path_alloced == NULL)
+			err = -ENOMEM;
+		else {
+			strncpy(path_alloced, path, plen);
+			path_alloced[plen] = 0;
+			err = vfs_symlink(dentry->d_inode, dnew, path_alloced);
+			kfree(path_alloced);
+		}
+	} else
+		err = vfs_symlink(dentry->d_inode, dnew, path);
+
 	if (!err) {
 		if (EX_ISSYNC(fhp->fh_export))
 			nfsd_sync_dir(dentry);
diff -Nru a/fs/nls/Config.in b/fs/nls/Config.in
--- a/fs/nls/Config.in	Fri Oct 11 21:22:55 2002
+++ b/fs/nls/Config.in	Fri Oct 11 21:22:55 2002
@@ -12,7 +12,7 @@
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
 	-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
-	-o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" ]; then
+	-o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" -o "$CONFIG_CIFS" != "n" ]; then
   define_bool CONFIG_NLS y
 else
   define_bool CONFIG_NLS n
diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
--- a/fs/ntfs/ntfs.h	Fri Oct 11 21:22:56 2002
+++ b/fs/ntfs/ntfs.h	Fri Oct 11 21:22:56 2002
@@ -90,7 +90,7 @@
  */
 static inline ntfs_volume *NTFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 /**
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Fri Oct 11 21:22:54 2002
+++ b/fs/ntfs/super.c	Fri Oct 11 21:22:54 2002
@@ -1051,7 +1051,7 @@
 		unload_nls(vol->nls_map);
 		vol->nls_map = NULL;
 	}
-	vfs_sb->u.generic_sbp = NULL;
+	vfs_sb->s_fs_info = NULL;
 	kfree(vol);
 	return;
 }
@@ -1336,8 +1336,8 @@
 #ifndef NTFS_RW
 	sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
 #endif
-	/* Allocate a new ntfs_volume and place it in sb->u.generic_sbp. */
-	sb->u.generic_sbp = kmalloc(sizeof(ntfs_volume), GFP_NOFS);
+	/* Allocate a new ntfs_volume and place it in sb->s_fs_info. */
+	sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS);
 	vol = NTFS_SB(sb);
 	if (!vol) {
 		if (!silent)
@@ -1580,7 +1580,7 @@
 	}
 	/* Errors at this stage are irrelevant. */
 err_out_now:
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	kfree(vol);
 	ntfs_debug("Failed, returning -EINVAL.");
 	return -EINVAL;
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Fri Oct 11 21:22:55 2002
+++ b/fs/partitions/check.c	Fri Oct 11 21:22:55 2002
@@ -471,13 +471,12 @@
 	return res;
 }
 
-unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p)
+unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
 {
 	struct address_space *mapping = bdev->bd_inode->i_mapping;
-	int sect = PAGE_CACHE_SIZE / 512;
 	struct page *page;
 
-	page = read_cache_page(mapping, n/sect,
+	page = read_cache_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
 			(filler_t *)mapping->a_ops->readpage, NULL);
 	if (!IS_ERR(page)) {
 		wait_on_page_locked(page);
@@ -486,7 +485,7 @@
 		if (PageError(page))
 			goto fail;
 		p->v = page;
-		return (unsigned char *)page_address(page) + 512 * (n % sect);
+		return (unsigned char *)page_address(page) +  ((n & ((1 << (PAGE_CACHE_SHIFT - 9)) - 1)) << 9);
 fail:
 		page_cache_release(page);
 	}
diff -Nru a/fs/partitions/check.h b/fs/partitions/check.h
--- a/fs/partitions/check.h	Fri Oct 11 21:22:55 2002
+++ b/fs/partitions/check.h	Fri Oct 11 21:22:55 2002
@@ -5,14 +5,13 @@
  * add_gd_partition adds a partitions details to the devices partition
  * description.
  */
-
 enum { MAX_PART = 256 };
 
 struct parsed_partitions {
 	char name[40];
 	struct {
-		unsigned long from;
-		unsigned long size;
+		sector_t from;
+		sector_t size;
 		int flags;
 	} parts[MAX_PART];
 	int next;
@@ -20,7 +19,7 @@
 };
 
 static inline void
-put_partition(struct parsed_partitions *p, int n, int from, int size)
+put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
 {
 	if (n < p->limit) {
 		p->parts[n].from = from;
diff -Nru a/fs/partitions/ldm.c b/fs/partitions/ldm.c
--- a/fs/partitions/ldm.c	Fri Oct 11 21:22:55 2002
+++ b/fs/partitions/ldm.c	Fri Oct 11 21:22:55 2002
@@ -24,6 +24,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/pagemap.h>
 #include <linux/stringify.h>
 #include "ldm.h"
 #include "check.h"
diff -Nru a/fs/pipe.c b/fs/pipe.c
--- a/fs/pipe.c	Fri Oct 11 21:22:59 2002
+++ b/fs/pipe.c	Fri Oct 11 21:22:59 2002
@@ -412,7 +412,7 @@
 	.ioctl		= pipe_ioctl,
 	.open		= pipe_read_open,
 	.release	= pipe_read_release,
-	.fasync         = pipe_read_fasync,
+	.fasync		= pipe_read_fasync,
 };
 
 struct file_operations write_fifo_fops = {
@@ -423,7 +423,7 @@
 	.ioctl		= pipe_ioctl,
 	.open		= pipe_write_open,
 	.release	= pipe_write_release,
-	.fasync         = pipe_write_fasync,
+	.fasync		= pipe_write_fasync,
 };
 
 struct file_operations rdwr_fifo_fops = {
@@ -434,7 +434,7 @@
 	.ioctl		= pipe_ioctl,
 	.open		= pipe_rdwr_open,
 	.release	= pipe_rdwr_release,
-	.fasync         = pipe_rdwr_fasync,
+	.fasync		= pipe_rdwr_fasync,
 };
 
 struct file_operations read_pipe_fops = {
@@ -445,7 +445,7 @@
 	.ioctl		= pipe_ioctl,
 	.open		= pipe_read_open,
 	.release	= pipe_read_release,
-	.fasync         = pipe_read_fasync,
+	.fasync		= pipe_read_fasync,
 };
 
 struct file_operations write_pipe_fops = {
@@ -456,7 +456,7 @@
 	.ioctl		= pipe_ioctl,
 	.open		= pipe_write_open,
 	.release	= pipe_write_release,
-	.fasync         = pipe_write_fasync,
+	.fasync		= pipe_write_fasync,
 };
 
 struct file_operations rdwr_pipe_fops = {
@@ -467,7 +467,7 @@
 	.ioctl		= pipe_ioctl,
 	.open		= pipe_rdwr_open,
 	.release	= pipe_rdwr_release,
-	.fasync         = pipe_rdwr_fasync,
+	.fasync		= pipe_rdwr_fasync,
 };
 
 struct inode* pipe_new(struct inode* inode)
diff -Nru a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c	Fri Oct 11 21:23:00 2002
+++ b/fs/proc/array.c	Fri Oct 11 21:23:00 2002
@@ -352,7 +352,7 @@
 		ppid,
 		task->pgrp,
 		task->session,
-	        tty_nr,
+		tty_nr,
 		tty_pgrp,
 		task->flags,
 		task->min_flt,
diff -Nru a/fs/proc/generic.c b/fs/proc/generic.c
--- a/fs/proc/generic.c	Fri Oct 11 21:23:05 2002
+++ b/fs/proc/generic.c	Fri Oct 11 21:23:05 2002
@@ -165,6 +165,24 @@
     return -EINVAL;
 }
 
+static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
+{
+	struct inode *inode = dentry->d_inode;
+	int error = inode_setattr(inode, iattr);
+	if (!error) {
+		struct proc_dir_entry *de = PDE(inode);
+		de->uid = inode->i_uid;
+		de->gid = inode->i_gid;
+		de->mode = inode->i_mode;
+	}
+
+	return error;
+}
+
+static struct inode_operations proc_file_inode_operations = {
+	.setattr	= proc_notify_change,
+};
+
 /*
  * This function parses a name such as "tty/driver/serial", and
  * returns the struct proc_dir_entry for "/proc/tty/driver", and
@@ -368,6 +386,7 @@
  */
 static struct inode_operations proc_dir_inode_operations = {
 	.lookup		= proc_lookup,
+	.setattr	= proc_notify_change,
 };
 
 static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
@@ -393,6 +412,8 @@
 	} else if (S_ISREG(dp->mode)) {
 		if (dp->proc_fops == NULL)
 			dp->proc_fops = &proc_file_operations;
+		if (dp->proc_iops == NULL)
+			dp->proc_iops = &proc_file_inode_operations;
 	}
 	return 0;
 }
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Fri Oct 11 21:22:54 2002
+++ b/fs/proc/proc_misc.c	Fri Oct 11 21:22:54 2002
@@ -223,10 +223,10 @@
 }
 
 static struct file_operations fragmentation_file_operations = {
-	open:		fragmentation_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= fragmentation_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 static int version_read_proc(char *page, char **start, off_t off,
@@ -258,10 +258,10 @@
 	return seq_open(file, &vmstat_op);
 }
 static struct file_operations proc_vmstat_file_operations = {
-	open:		vmstat_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= vmstat_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 #ifdef CONFIG_PROC_HARDWARE
diff -Nru a/fs/qnx4/inode.c b/fs/qnx4/inode.c
--- a/fs/qnx4/inode.c	Fri Oct 11 21:22:55 2002
+++ b/fs/qnx4/inode.c	Fri Oct 11 21:22:55 2002
@@ -353,7 +353,7 @@
 	qs = kmalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
 	if (!qs)
 		return -ENOMEM;
-	s->u.generic_sbp = qs;
+	s->s_fs_info = qs;
 	memset(qs, 0, sizeof(struct qnx4_sb_info));
 
 	sb_set_blocksize(s, QNX4_BLOCK_SIZE);
@@ -416,7 +416,7 @@
 	brelse(bh);
       outnobh:
 	kfree(qs);
-	s->u.generic_sbp = NULL;
+	s->s_fs_info = NULL;
 	return -EINVAL;
 }
 
@@ -425,7 +425,7 @@
 	struct qnx4_sb_info *qs = qnx4_sb(sb);
 	kfree( qs->BitMap );
 	kfree( qs );
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	return;
 }
 
@@ -444,7 +444,7 @@
 	return cont_prepare_write(page, from, to, qnx4_get_block,
 				  &qnx4_inode->mmu_private);
 }
-static int qnx4_bmap(struct address_space *mapping, long block)
+static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,qnx4_get_block);
 }
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Fri Oct 11 21:22:55 2002
+++ b/fs/ramfs/inode.c	Fri Oct 11 21:22:55 2002
@@ -155,102 +155,6 @@
 	return ramfs_mknod(dir, dentry, mode | S_IFREG, 0);
 }
 
-/*
- * Link a file..
- */
-static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
-{
-	struct inode *inode = old_dentry->d_inode;
-
-	inode->i_nlink++;
-	atomic_inc(&inode->i_count);	/* New dentry reference */
-	dget(dentry);		/* Extra pinning count for the created dentry */
-	d_instantiate(dentry, inode);
-	return 0;
-}
-
-static inline int ramfs_positive(struct dentry *dentry)
-{
-	return dentry->d_inode && !d_unhashed(dentry);
-}
-
-/*
- * Check that a directory is empty (this works
- * for regular files too, they'll just always be
- * considered empty..).
- *
- * Note that an empty directory can still have
- * children, they just all have to be negative..
- */
-static int ramfs_empty(struct dentry *dentry)
-{
-	struct list_head *list;
-
-	spin_lock(&dcache_lock);
-	list = dentry->d_subdirs.next;
-
-	while (list != &dentry->d_subdirs) {
-		struct dentry *de = list_entry(list, struct dentry, d_child);
-
-		if (ramfs_positive(de)) {
-			spin_unlock(&dcache_lock);
-			return 0;
-		}
-		list = list->next;
-	}
-	spin_unlock(&dcache_lock);
-	return 1;
-}
-
-/*
- * Unlink a ramfs entry
- */
-static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
-{
-	struct inode *inode = dentry->d_inode;
-
-	inode->i_nlink--;
-	dput(dentry);			/* Undo the count from "create" - this does all the work */
-	return 0;
-}
-
-static int ramfs_rmdir(struct inode * dir, struct dentry *dentry)
-{
-	int retval = -ENOTEMPTY;
-
-	if (ramfs_empty(dentry)) {
-		dentry->d_inode->i_nlink--;
-		ramfs_unlink(dir, dentry);
-		dir->i_nlink--;
-		retval = 0;
-	}
-	return retval;
-}
-
-/*
- * The VFS layer already does all the dentry stuff for rename,
- * we just have to decrement the usage count for the target if
- * it exists so that the VFS layer correctly free's it when it
- * gets overwritten.
- */
-static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
-{
-	int error = -ENOTEMPTY;
-
-	if (ramfs_empty(new_dentry)) {
-		struct inode *inode = new_dentry->d_inode;
-		if (inode) {
-			inode->i_nlink--;
-			dput(new_dentry);
-		}
-		if (S_ISDIR(old_dentry->d_inode->i_mode)) {
-			old_dir->i_nlink--;
-			new_dir->i_nlink++;
-		}
-		error = 0;
-	}
-	return error;
-}
 
 static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
 {
@@ -270,11 +174,6 @@
 	return error;
 }
 
-static int ramfs_sync_file(struct file * file, struct dentry *dentry, int datasync)
-{
-	return 0;
-}
-
 static struct address_space_operations ramfs_aops = {
 	.readpage	= ramfs_readpage,
 	.writepage	= fail_writepage,
@@ -286,20 +185,20 @@
 	.read		= generic_file_read,
 	.write		= generic_file_write,
 	.mmap		= generic_file_mmap,
-	.fsync		= ramfs_sync_file,
+	.fsync		= simple_sync_file,
 	.sendfile	= generic_file_sendfile,
 };
 
 static struct inode_operations ramfs_dir_inode_operations = {
 	.create		= ramfs_create,
 	.lookup		= simple_lookup,
-	.link		= ramfs_link,
-	.unlink		= ramfs_unlink,
+	.link		= simple_link,
+	.unlink		= simple_unlink,
 	.symlink	= ramfs_symlink,
 	.mkdir		= ramfs_mkdir,
-	.rmdir		= ramfs_rmdir,
+	.rmdir		= simple_rmdir,
 	.mknod		= ramfs_mknod,
-	.rename		= ramfs_rename,
+	.rename		= simple_rename,
 };
 
 static struct super_operations ramfs_ops = {
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	Fri Oct 11 21:23:00 2002
+++ b/fs/read_write.c	Fri Oct 11 21:23:00 2002
@@ -12,6 +12,7 @@
 #include <linux/smp_lock.h>
 #include <linux/dnotify.h>
 #include <linux/security.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 
@@ -176,6 +177,20 @@
 }
 #endif
 
+ssize_t do_sync_read(struct file *filp, char *buf, size_t len, loff_t *ppos)
+{
+	struct kiocb kiocb;
+	ssize_t ret;
+
+	init_sync_kiocb(&kiocb, filp);
+	kiocb.ki_pos = *ppos;
+	ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos);
+	if (-EIOCBQUEUED == ret)
+		ret = wait_on_sync_kiocb(&kiocb);
+	*ppos = kiocb.ki_pos;
+	return ret;
+}
+
 ssize_t vfs_read(struct file *file, char *buf, size_t count, loff_t *pos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
@@ -183,14 +198,17 @@
 
 	if (!(file->f_mode & FMODE_READ))
 		return -EBADF;
-	if (!file->f_op || !file->f_op->read)
+	if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
 		return -EINVAL;
 
 	ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
 	if (!ret) {
 		ret = security_ops->file_permission (file, MAY_READ);
 		if (!ret) {
-			ret = file->f_op->read(file, buf, count, pos);
+			if (file->f_op->read)
+				ret = file->f_op->read(file, buf, count, pos);
+			else
+				ret = do_sync_read(file, buf, count, pos);
 			if (ret > 0)
 				dnotify_parent(file->f_dentry, DN_ACCESS);
 		}
@@ -199,6 +217,20 @@
 	return ret;
 }
 
+ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *ppos)
+{
+	struct kiocb kiocb;
+	ssize_t ret;
+
+	init_sync_kiocb(&kiocb, filp);
+	kiocb.ki_pos = *ppos;
+	ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos);
+	if (-EIOCBQUEUED == ret)
+		ret = wait_on_sync_kiocb(&kiocb);
+	*ppos = kiocb.ki_pos;
+	return ret;
+}
+
 ssize_t vfs_write(struct file *file, const char *buf, size_t count, loff_t *pos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
@@ -206,14 +238,17 @@
 
 	if (!(file->f_mode & FMODE_WRITE))
 		return -EBADF;
-	if (!file->f_op || !file->f_op->write)
+	if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
 		return -EINVAL;
 
 	ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
 	if (!ret) {
 		ret = security_ops->file_permission (file, MAY_WRITE);
 		if (!ret) {
-			ret = file->f_op->write(file, buf, count, pos);
+			if (file->f_op->write)
+				ret = file->f_op->write(file, buf, count, pos);
+			else
+				ret = do_sync_write(file, buf, count, pos);
 			if (ret > 0)
 				dnotify_parent(file->f_dentry, DN_MODIFY);
 		}
@@ -316,7 +351,7 @@
 	size_t tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
-	ssize_t ret = -EINVAL;
+	ssize_t ret;
 	int seg;
 	io_fn_t fn;
 	iov_fn_t fnv;
@@ -325,8 +360,9 @@
 	/*
 	 * SuS says "The readv() function *may* fail if the iovcnt argument
 	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-	 * traditionally returned -EINVAL for zero segments, so...
+	 * traditionally returned zero for zero segments, so...
 	 */
+	ret = 0;
 	if (nr_segs == 0)
 		goto out;
 
@@ -334,6 +370,7 @@
 	 * First get the "struct iovec" from user memory and
 	 * verify all the pointers
 	 */
+	ret = -EINVAL;
 	if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
 		goto out;
 	if (!file->f_op)
@@ -580,3 +617,6 @@
 
 	return do_sendfile(out_fd, in_fd, NULL, count, 0);
 }
+
+EXPORT_SYMBOL(do_sync_read);
+EXPORT_SYMBOL(do_sync_write);
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c	Fri Oct 11 21:22:55 2002
+++ b/fs/reiserfs/inode.c	Fri Oct 11 21:22:55 2002
@@ -2029,7 +2029,7 @@
 }
 
 
-static int reiserfs_aop_bmap(struct address_space *as, long block) {
+static sector_t reiserfs_aop_bmap(struct address_space *as, sector_t block) {
   return generic_block_bmap(as, block, reiserfs_bmap) ;
 }
 
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c	Fri Oct 11 21:23:00 2002
+++ b/fs/reiserfs/journal.c	Fri Oct 11 21:23:00 2002
@@ -1011,15 +1011,15 @@
     ** is not marked JDirty_wait
     */
     if ((!was_jwait) && !buffer_locked(saved_bh)) {
-printk("journal-813: BAD! buffer %lu %cdirty %cjwait, not in a newer tranasction\n", saved_bh->b_blocknr,
+printk("journal-813: BAD! buffer %llu %cdirty %cjwait, not in a newer tranasction\n", (unsigned long long)saved_bh->b_blocknr,
         was_dirty ? ' ' : '!', was_jwait ? ' ' : '!') ;
     }
     /* kupdate_one_transaction waits on the buffers it is writing, so we
     ** should never see locked buffers here
     */
     if (buffer_locked(saved_bh)) {
-      printk("clm-2083: locked buffer %lu in flush_journal_list\n", 
-              saved_bh->b_blocknr) ;
+      printk("clm-2083: locked buffer %llu in flush_journal_list\n", 
+              (unsigned long long)saved_bh->b_blocknr) ;
       wait_on_buffer(saved_bh) ;
       if (!buffer_uptodate(saved_bh)) {
         reiserfs_panic(s, "journal-923: buffer write failed\n") ;
@@ -1032,8 +1032,8 @@
       submit_logged_buffer(saved_bh) ;
       count++ ;
     } else {
-      printk("clm-2082: Unable to flush buffer %lu in flush_journal_list\n",
-              saved_bh->b_blocknr) ;
+      printk("clm-2082: Unable to flush buffer %llu in flush_journal_list\n",
+              (unsigned long long)saved_bh->b_blocknr) ;
     }
 free_cnode:
     last = cn ;
@@ -2315,7 +2315,7 @@
   ** could get to disk too early.  NOT GOOD.
   */
   if (!prepared || buffer_locked(bh)) {
-    printk("journal-1777: buffer %lu bad state %cPREPARED %cLOCKED %cDIRTY %cJDIRTY_WAIT\n", bh->b_blocknr, prepared ? ' ' : '!', 
+    printk("journal-1777: buffer %llu bad state %cPREPARED %cLOCKED %cDIRTY %cJDIRTY_WAIT\n", (unsigned long long)bh->b_blocknr, prepared ? ' ' : '!', 
                             buffer_locked(bh) ? ' ' : '!',
 			    buffer_dirty(bh) ? ' ' : '!',
 			    buffer_journal_dirty(bh) ? ' ' : '!') ;
diff -Nru a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
--- a/fs/reiserfs/prints.c	Fri Oct 11 21:23:00 2002
+++ b/fs/reiserfs/prints.c	Fri Oct 11 21:23:00 2002
@@ -139,8 +139,8 @@
 
 static void sprintf_buffer_head (char * buf, struct buffer_head * bh) 
 {
-  sprintf (buf, "dev %s, size %d, blocknr %ld, count %d, state 0x%lx, page %p, (%s, %s, %s)",
-	   bdevname (bh->b_bdev), bh->b_size, bh->b_blocknr,
+  sprintf (buf, "dev %s, size %d, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
+	   bdevname (bh->b_bdev), bh->b_size, (unsigned long long)bh->b_blocknr,
 	   atomic_read (&(bh->b_count)),
 	   bh->b_state, bh->b_page,
 	   buffer_uptodate (bh) ? "UPTODATE" : "!UPTODATE",
@@ -367,7 +367,7 @@
     if (tb) {
 	while (tb->insert_size[h]) {
 	    bh = PATH_H_PBUFFER (path, h);
-	    printk ("block %lu (level=%d), position %d\n", bh ? bh->b_blocknr : 0,
+	    printk ("block %llu (level=%d), position %d\n", bh ? (unsigned long long)bh->b_blocknr : 0LL,
 		    bh ? B_LEVEL (bh) : 0, PATH_H_POSITION (path, h));
 	    h ++;
 	}
@@ -377,8 +377,8 @@
       printk ("Offset    Bh     (b_blocknr, b_count) Position Nr_item\n");
       while ( offset > ILLEGAL_PATH_ELEMENT_OFFSET ) {
 	  bh = PATH_OFFSET_PBUFFER (path, offset);
-	  printk ("%6d %10p (%9lu, %7d) %8d %7d\n", offset, 
-		  bh, bh ? bh->b_blocknr : 0, bh ? atomic_read (&(bh->b_count)) : 0,
+	  printk ("%6d %10p (%9llu, %7d) %8d %7d\n", offset, 
+		  bh, bh ? (unsigned long long)bh->b_blocknr : 0LL, bh ? atomic_read (&(bh->b_count)) : 0,
 		  PATH_OFFSET_POSITION (path, offset), bh ? B_NR_ITEMS (bh) : -1);
 	  
 	  offset --;
@@ -510,8 +510,8 @@
 	return 1;
     }
 
-    printk ("%s\'s super block is in block %ld\n", bdevname (bh->b_bdev), 
-            bh->b_blocknr);
+    printk ("%s\'s super block is in block %llu\n", bdevname (bh->b_bdev), 
+            (unsigned long long)bh->b_blocknr);
     printk ("Reiserfs version %s\n", version );
     printk ("Block count %u\n", sb_block_count(rs));
     printk ("Blocksize %d\n", sb_blocksize(rs));
@@ -547,8 +547,8 @@
     if (memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8))
 	return 1;
 
-    printk ("Desc block %lu (j_trans_id %d, j_mount_id %d, j_len %d)",
-	    bh->b_blocknr, desc->j_trans_id, desc->j_mount_id, desc->j_len);
+    printk ("Desc block %llu (j_trans_id %d, j_mount_id %d, j_len %d)",
+	    (unsigned long long)bh->b_blocknr, desc->j_trans_id, desc->j_mount_id, desc->j_len);
 
     return 0;
 }
@@ -573,7 +573,7 @@
 	if (print_internal (bh, first, last))
 	    if (print_super_block (bh))
 		if (print_desc_block (bh))
-		    printk ("Block %ld contains unformatted data\n", bh->b_blocknr);
+		    printk ("Block %llu contains unformatted data\n", (unsigned long long)bh->b_blocknr);
 }
 
 
@@ -608,19 +608,19 @@
 	    tbFh = 0;
 	}
 	sprintf (print_tb_buf + strlen (print_tb_buf),
-		 "* %d * %3ld(%2d) * %3ld(%2d) * %3ld(%2d) * %5ld * %5ld * %5ld * %5ld * %5ld *\n",
+		 "* %d * %3lld(%2d) * %3lld(%2d) * %3lld(%2d) * %5lld * %5lld * %5lld * %5lld * %5lld *\n",
 		 h, 
-		 (tbSh) ? (tbSh->b_blocknr):(-1),
+		 (tbSh) ? (long long)(tbSh->b_blocknr):(-1LL),
 		 (tbSh) ? atomic_read (&(tbSh->b_count)) : -1,
-		 (tb->L[h]) ? (tb->L[h]->b_blocknr):(-1),
+		 (tb->L[h]) ? (long long)(tb->L[h]->b_blocknr):(-1LL),
 		 (tb->L[h]) ? atomic_read (&(tb->L[h]->b_count)) : -1,
-		 (tb->R[h]) ? (tb->R[h]->b_blocknr):(-1),
+		 (tb->R[h]) ? (long long)(tb->R[h]->b_blocknr):(-1LL),
 		 (tb->R[h]) ? atomic_read (&(tb->R[h]->b_count)) : -1,
-		 (tbFh) ? (tbFh->b_blocknr):(-1),
-		 (tb->FL[h]) ? (tb->FL[h]->b_blocknr):(-1),
-		 (tb->FR[h]) ? (tb->FR[h]->b_blocknr):(-1),
-		 (tb->CFL[h]) ? (tb->CFL[h]->b_blocknr):(-1),
-		 (tb->CFR[h]) ? (tb->CFR[h]->b_blocknr):(-1));
+		 (tbFh) ? (long long)(tbFh->b_blocknr):(-1LL),
+		 (tb->FL[h]) ? (long long)(tb->FL[h]->b_blocknr):(-1LL),
+		 (tb->FR[h]) ? (long long)(tb->FR[h]->b_blocknr):(-1LL),
+		 (tb->CFL[h]) ? (long long)(tb->CFL[h]->b_blocknr):(-1LL),
+		 (tb->CFR[h]) ? (long long)(tb->CFR[h]->b_blocknr):(-1LL));
     }
 
     sprintf (print_tb_buf + strlen (print_tb_buf), 
@@ -647,7 +647,7 @@
     h = 0;
     for (i = 0; i < sizeof (tb->FEB) / sizeof (tb->FEB[0]); i ++)
 	sprintf (print_tb_buf + strlen (print_tb_buf),
-		 "%p (%lu %d)%s", tb->FEB[i], tb->FEB[i] ? tb->FEB[i]->b_blocknr : 0,
+		 "%p (%llu %d)%s", tb->FEB[i], tb->FEB[i] ? (unsigned long long)tb->FEB[i]->b_blocknr : 0ULL,
 		 tb->FEB[i] ? atomic_read (&(tb->FEB[i]->b_count)) : 0, 
 		 (i == sizeof (tb->FEB) / sizeof (tb->FEB[0]) - 1) ? "\n" : ", ");
 
diff -Nru a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
--- a/fs/reiserfs/resize.c	Fri Oct 11 21:22:55 2002
+++ b/fs/reiserfs/resize.c	Fri Oct 11 21:22:55 2002
@@ -9,6 +9,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/errno.h>
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c	Fri Oct 11 21:22:57 2002
+++ b/fs/reiserfs/super.c	Fri Oct 11 21:22:57 2002
@@ -402,8 +402,8 @@
   reiserfs_proc_unregister( s, "version" );
   reiserfs_proc_info_done( s );
 
-  kfree(s->u.generic_sbp);
-  s->u.generic_sbp = NULL;
+  kfree(s->s_fs_info);
+  s->s_fs_info = NULL;
 
   return;
 }
@@ -916,8 +916,8 @@
     rs = (struct reiserfs_super_block *)bh->b_data;
     if (sb_blocksize(rs) != s->s_blocksize) {
 	printk ("sh-2011: read_super_block: "
-		"can't find a reiserfs filesystem on (dev %s, block %lu, size %lu)\n",
-		reiserfs_bdevname (s), bh->b_blocknr, s->s_blocksize);
+		"can't find a reiserfs filesystem on (dev %s, block %Lu, size %lu)\n",
+		reiserfs_bdevname (s), (unsigned long long)bh->b_blocknr, s->s_blocksize);
 	brelse (bh);
 	return 1;
     }
@@ -980,8 +980,8 @@
     ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)) ;
     wait_on_buffer(SB_AP_BITMAP(s)[i].bh) ;
     if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
-      printk("reread_meta_blocks, error reading bitmap block number %d at
-      %ld\n", i, SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
+      printk("reread_meta_blocks, error reading bitmap block number %d at %llu\n", 
+        i, (unsigned long long)SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
       return 1 ;
     }
   }
@@ -1164,7 +1164,7 @@
 	errval = -ENOMEM;
 	goto error;
     }
-    s->u.generic_sbp = sbi;
+    s->s_fs_info = sbi;
     memset (sbi, 0, sizeof (struct reiserfs_sb_info));
     /* Set default values for options: non-aggressive tails */
     REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
@@ -1335,7 +1335,7 @@
 	kfree(sbi);
     }
 
-    s->u.generic_sbp = NULL;
+    s->s_fs_info = NULL;
     return errval;
 }
 
diff -Nru a/fs/romfs/inode.c b/fs/romfs/inode.c
--- a/fs/romfs/inode.c	Fri Oct 11 21:23:00 2002
+++ b/fs/romfs/inode.c	Fri Oct 11 21:23:00 2002
@@ -86,7 +86,7 @@
 /* instead of private superblock data */
 static inline unsigned long romfs_maxsize(struct super_block *sb)
 {
-	return (unsigned long)sb->u.generic_sbp;
+	return (unsigned long)sb->s_fs_info;
 }
 
 static inline struct romfs_inode_info *ROMFS_I(struct inode *inode)
@@ -144,7 +144,7 @@
 	}
 
 	s->s_magic = ROMFS_MAGIC;
-	s->u.generic_sbp = (void *)(long)sz;
+	s->s_fs_info = (void *)(long)sz;
 
 	s->s_flags |= MS_RDONLY;
 
diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Fri Oct 11 21:22:54 2002
+++ b/fs/smbfs/inode.c	Fri Oct 11 21:22:54 2002
@@ -468,7 +468,7 @@
 		unload_nls(server->local_nls);
 		server->local_nls = NULL;
 	}
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	smb_unlock_server(server);
 	smb_kfree(server);
 }
@@ -499,7 +499,7 @@
 	server = smb_kmalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
 	if (!server)
 		goto out_no_server;
-	sb->u.generic_sbp = server;
+	sb->s_fs_info = server;
 	memset(server, 0, sizeof(struct smb_sb_info));
 
 	server->super_block = sb;
@@ -592,7 +592,7 @@
 out_no_mem:
 	if (!server->mnt)
 		printk(KERN_ERR "smb_fill_super: allocation failure\n");
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	smb_kfree(server);
 	goto out_fail;
 out_wrong_data:
diff -Nru a/fs/sysv/dir.c b/fs/sysv/dir.c
--- a/fs/sysv/dir.c	Fri Oct 11 21:22:55 2002
+++ b/fs/sysv/dir.c	Fri Oct 11 21:22:55 2002
@@ -21,9 +21,9 @@
 static int sysv_readdir(struct file *, void *, filldir_t);
 
 struct file_operations sysv_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	sysv_readdir,
-	fsync:		sysv_sync_file,
+	.read		= generic_read_dir,
+	.readdir	= sysv_readdir,
+	.fsync		= sysv_sync_file,
 };
 
 static inline void dir_put_page(struct page *page)
diff -Nru a/fs/sysv/file.c b/fs/sysv/file.c
--- a/fs/sysv/file.c	Fri Oct 11 21:23:04 2002
+++ b/fs/sysv/file.c	Fri Oct 11 21:23:04 2002
@@ -20,17 +20,17 @@
  * the coh filesystem.
  */
 struct file_operations sysv_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		generic_file_write,
-	mmap:		generic_file_mmap,
-	fsync:		sysv_sync_file,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.mmap		= generic_file_mmap,
+	.fsync		= sysv_sync_file,
+	.sendfile	= generic_file_sendfile,
 };
 
 struct inode_operations sysv_file_inode_operations = {
-	truncate:	sysv_truncate,
-	getattr:	sysv_getattr,
+	.truncate	= sysv_truncate,
+	.getattr	= sysv_getattr,
 };
 
 int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync)
diff -Nru a/fs/sysv/inode.c b/fs/sysv/inode.c
--- a/fs/sysv/inode.c	Fri Oct 11 21:22:51 2002
+++ b/fs/sysv/inode.c	Fri Oct 11 21:22:51 2002
@@ -131,9 +131,9 @@
 }
 
 static struct inode_operations sysv_symlink_inode_operations = {
-	readlink:	page_readlink,
-	follow_link:	page_follow_link,
-	getattr:	sysv_getattr,
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.getattr	= sysv_getattr,
 };
 
 void sysv_set_inode(struct inode *inode, dev_t rdev)
@@ -311,14 +311,14 @@
 }
 
 struct super_operations sysv_sops = {
-	alloc_inode:	sysv_alloc_inode,
-	destroy_inode:	sysv_destroy_inode,
-	read_inode:	sysv_read_inode,
-	write_inode:	sysv_write_inode,
-	delete_inode:	sysv_delete_inode,
-	put_super:	sysv_put_super,
-	write_super:	sysv_write_super,
-	statfs:		sysv_statfs,
+	.alloc_inode	= sysv_alloc_inode,
+	.destroy_inode	= sysv_destroy_inode,
+	.read_inode	= sysv_read_inode,
+	.write_inode	= sysv_write_inode,
+	.delete_inode	= sysv_delete_inode,
+	.put_super	= sysv_put_super,
+	.write_super	= sysv_write_super,
+	.statfs		= sysv_statfs,
 };
 
 int __init sysv_init_icache(void)
diff -Nru a/fs/sysv/itree.c b/fs/sysv/itree.c
--- a/fs/sysv/itree.c	Fri Oct 11 21:22:55 2002
+++ b/fs/sysv/itree.c	Fri Oct 11 21:22:55 2002
@@ -459,15 +459,15 @@
 {
 	return block_prepare_write(page,from,to,get_block);
 }
-static int sysv_bmap(struct address_space *mapping, long block)
+static sector_t sysv_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,get_block);
 }
 struct address_space_operations sysv_aops = {
-	readpage: sysv_readpage,
-	writepage: sysv_writepage,
-	sync_page: block_sync_page,
-	prepare_write: sysv_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: sysv_bmap
+	.readpage = sysv_readpage,
+	.writepage = sysv_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = sysv_prepare_write,
+	.commit_write = generic_commit_write,
+	.bmap = sysv_bmap
 };
diff -Nru a/fs/sysv/namei.c b/fs/sysv/namei.c
--- a/fs/sysv/namei.c	Fri Oct 11 21:23:00 2002
+++ b/fs/sysv/namei.c	Fri Oct 11 21:23:00 2002
@@ -61,7 +61,7 @@
 }
 
 struct dentry_operations sysv_dentry_operations = {
-	d_hash:		sysv_hash,
+	.d_hash		= sysv_hash,
 };
 
 static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
@@ -308,14 +308,14 @@
  * directories can handle most operations...
  */
 struct inode_operations sysv_dir_inode_operations = {
-	create:		sysv_create,
-	lookup:		sysv_lookup,
-	link:		sysv_link,
-	unlink:		sysv_unlink,
-	symlink:	sysv_symlink,
-	mkdir:		sysv_mkdir,
-	rmdir:		sysv_rmdir,
-	mknod:		sysv_mknod,
-	rename:		sysv_rename,
-	getattr:	sysv_getattr,
+	.create		= sysv_create,
+	.lookup		= sysv_lookup,
+	.link		= sysv_link,
+	.unlink		= sysv_unlink,
+	.symlink	= sysv_symlink,
+	.mkdir		= sysv_mkdir,
+	.rmdir		= sysv_rmdir,
+	.mknod		= sysv_mknod,
+	.rename		= sysv_rename,
+	.getattr	= sysv_getattr,
 };
diff -Nru a/fs/sysv/super.c b/fs/sysv/super.c
--- a/fs/sysv/super.c	Fri Oct 11 21:22:54 2002
+++ b/fs/sysv/super.c	Fri Oct 11 21:22:54 2002
@@ -367,7 +367,7 @@
 
 	sbi->s_sb = sb;
 	sbi->s_block_base = 0;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	
 	sb_set_blocksize(sb, BLOCK_SIZE);
 
@@ -453,7 +453,7 @@
 	sbi->s_block_base = 0;
 	sbi->s_type = FSTYPE_V7;
 	sbi->s_bytesex = BYTESEX_PDP;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	
 	sb_set_blocksize(sb, 512);
 
@@ -509,19 +509,19 @@
 }
 
 static struct file_system_type sysv_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"sysv",
-	get_sb:		sysv_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "sysv",
+	.get_sb		= sysv_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static struct file_system_type v7_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"v7",
-	get_sb:		v7_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "v7",
+	.get_sb		= v7_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 extern int sysv_init_icache(void) __init;
diff -Nru a/fs/sysv/symlink.c b/fs/sysv/symlink.c
--- a/fs/sysv/symlink.c	Fri Oct 11 21:23:03 2002
+++ b/fs/sysv/symlink.c	Fri Oct 11 21:23:03 2002
@@ -20,6 +20,6 @@
 }
 
 struct inode_operations sysv_fast_symlink_inode_operations = {
-	readlink:	sysv_readlink,
-	follow_link:	sysv_follow_link,
+	.readlink	= sysv_readlink,
+	.follow_link	= sysv_follow_link,
 };
diff -Nru a/fs/sysv/sysv.h b/fs/sysv/sysv.h
--- a/fs/sysv/sysv.h	Fri Oct 11 21:22:51 2002
+++ b/fs/sysv/sysv.h	Fri Oct 11 21:22:51 2002
@@ -73,7 +73,7 @@
 
 static inline struct sysv_sb_info *SYSV_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 
diff -Nru a/fs/udf/dir.c b/fs/udf/dir.c
--- a/fs/udf/dir.c	Fri Oct 11 21:22:55 2002
+++ b/fs/udf/dir.c	Fri Oct 11 21:22:55 2002
@@ -48,10 +48,10 @@
 /* readdir and lookup functions */
 
 struct file_operations udf_dir_operations = {
-	read:			generic_read_dir,
-	readdir:		udf_readdir,
-	ioctl:			udf_ioctl,
-	fsync:			udf_fsync_file,
+	.read			= generic_read_dir,
+	.readdir		= udf_readdir,
+	.ioctl			= udf_ioctl,
+	.fsync			= udf_fsync_file,
 };
 
 /*
diff -Nru a/fs/udf/file.c b/fs/udf/file.c
--- a/fs/udf/file.c	Fri Oct 11 21:22:51 2002
+++ b/fs/udf/file.c	Fri Oct 11 21:22:51 2002
@@ -144,11 +144,11 @@
 }
 
 struct address_space_operations udf_adinicb_aops = {
-	readpage:		udf_adinicb_readpage,
-	writepage:		udf_adinicb_writepage,
-	sync_page:		block_sync_page,
-	prepare_write:		udf_adinicb_prepare_write,
-	commit_write:		udf_adinicb_commit_write,
+	.readpage		= udf_adinicb_readpage,
+	.writepage		= udf_adinicb_writepage,
+	.sync_page		= block_sync_page,
+	.prepare_write		= udf_adinicb_prepare_write,
+	.commit_write		= udf_adinicb_commit_write,
 };
 
 static ssize_t udf_file_write(struct file * file, const char * buf,
@@ -358,16 +358,16 @@
 }
 
 struct file_operations udf_file_operations = {
-	read:			generic_file_read,
-	ioctl:			udf_ioctl,
-	open:			udf_open_file,
-	mmap:			generic_file_mmap,
-	write:			udf_file_write,
-	release:		udf_release_file,
-	fsync:			udf_fsync_file,
-	sendfile:		generic_file_sendfile,
+	.read			= generic_file_read,
+	.ioctl			= udf_ioctl,
+	.open			= udf_open_file,
+	.mmap			= generic_file_mmap,
+	.write			= udf_file_write,
+	.release		= udf_release_file,
+	.fsync			= udf_fsync_file,
+	.sendfile		= generic_file_sendfile,
 };
 
 struct inode_operations udf_file_inode_operations = {
-	truncate:		udf_truncate,
+	.truncate		= udf_truncate,
 };
diff -Nru a/fs/udf/inode.c b/fs/udf/inode.c
--- a/fs/udf/inode.c	Fri Oct 11 21:23:05 2002
+++ b/fs/udf/inode.c	Fri Oct 11 21:23:05 2002
@@ -146,18 +146,18 @@
 	return block_prepare_write(page, from, to, udf_get_block);
 }
 
-static int udf_bmap(struct address_space *mapping, long block)
+static sector_t udf_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,udf_get_block);
 }
 
 struct address_space_operations udf_aops = {
-	readpage:		udf_readpage,
-	writepage:		udf_writepage,
-	sync_page:		block_sync_page,
-	prepare_write:		udf_prepare_write,
-	commit_write:		generic_commit_write,
-	bmap:			udf_bmap,
+	.readpage		= udf_readpage,
+	.writepage		= udf_writepage,
+	.sync_page		= block_sync_page,
+	.prepare_write		= udf_prepare_write,
+	.commit_write		= generic_commit_write,
+	.bmap			= udf_bmap,
 };
 
 void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
diff -Nru a/fs/udf/namei.c b/fs/udf/namei.c
--- a/fs/udf/namei.c	Fri Oct 11 21:23:03 2002
+++ b/fs/udf/namei.c	Fri Oct 11 21:23:03 2002
@@ -1304,13 +1304,13 @@
 }
 
 struct inode_operations udf_dir_inode_operations = {
-	lookup:				udf_lookup,
-	create:				udf_create,
-	link:				udf_link,
-	unlink:				udf_unlink,
-	symlink:			udf_symlink,
-	mkdir:				udf_mkdir,
-	rmdir:				udf_rmdir,
-	mknod:				udf_mknod,
-	rename:				udf_rename,
+	.lookup				= udf_lookup,
+	.create				= udf_create,
+	.link				= udf_link,
+	.unlink				= udf_unlink,
+	.symlink			= udf_symlink,
+	.mkdir				= udf_mkdir,
+	.rmdir				= udf_rmdir,
+	.mknod				= udf_mknod,
+	.rename				= udf_rename,
 };
diff -Nru a/fs/udf/super.c b/fs/udf/super.c
--- a/fs/udf/super.c	Fri Oct 11 21:23:00 2002
+++ b/fs/udf/super.c	Fri Oct 11 21:23:00 2002
@@ -104,11 +104,11 @@
 }
 
 static struct file_system_type udf_fstype = {
-	owner:		THIS_MODULE,
-	name:		"udf",
-	get_sb:		udf_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "udf",
+	.get_sb		= udf_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static kmem_cache_t * udf_inode_cachep;
@@ -155,16 +155,16 @@
 
 /* Superblock operations */
 static struct super_operations udf_sb_ops = {
-	alloc_inode:		udf_alloc_inode,
-	destroy_inode:		udf_destroy_inode,
-	read_inode:		udf_read_inode,
-	write_inode:		udf_write_inode,
-	put_inode:		udf_put_inode,
-	delete_inode:		udf_delete_inode,
-	put_super:		udf_put_super,
-	write_super:		udf_write_super,
-	statfs:			udf_statfs,
-	remount_fs:		udf_remount_fs,
+	.alloc_inode		= udf_alloc_inode,
+	.destroy_inode		= udf_destroy_inode,
+	.read_inode		= udf_read_inode,
+	.write_inode		= udf_write_inode,
+	.put_inode		= udf_put_inode,
+	.delete_inode		= udf_delete_inode,
+	.put_super		= udf_put_super,
+	.write_super		= udf_write_super,
+	.statfs			= udf_statfs,
+	.remount_fs		= udf_remount_fs,
 };
 
 struct udf_options
@@ -1425,7 +1425,7 @@
 	sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
 
 #if UDFFS_RW != 1
@@ -1615,7 +1615,7 @@
 	udf_release_data(UDF_SB_LVIDBH(sb));
 	UDF_SB_FREE(sb);
 	kfree(sbi);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	return -EINVAL;
 }
 
@@ -1706,8 +1706,8 @@
 		udf_close_lvid(sb);
 	udf_release_data(UDF_SB_LVIDBH(sb));
 	UDF_SB_FREE(sb);
-	kfree(sb->u.generic_sbp);
-	sb->u.generic_sbp = NULL;
+	kfree(sb->s_fs_info);
+	sb->s_fs_info = NULL;
 }
 
 /*
diff -Nru a/fs/udf/symlink.c b/fs/udf/symlink.c
--- a/fs/udf/symlink.c	Fri Oct 11 21:22:54 2002
+++ b/fs/udf/symlink.c	Fri Oct 11 21:22:54 2002
@@ -126,5 +126,5 @@
  * symlinks can't do much...
  */
 struct address_space_operations udf_symlink_aops = {
-	readpage:		udf_symlink_filler,
+	.readpage		= udf_symlink_filler,
 };
diff -Nru a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
--- a/fs/udf/udf_sb.h	Fri Oct 11 21:22:55 2002
+++ b/fs/udf/udf_sb.h	Fri Oct 11 21:22:55 2002
@@ -32,7 +32,7 @@
 
 static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 #define UDF_SB_FREE(X)\
diff -Nru a/fs/ufs/inode.c b/fs/ufs/inode.c
--- a/fs/ufs/inode.c	Fri Oct 11 21:22:54 2002
+++ b/fs/ufs/inode.c	Fri Oct 11 21:22:54 2002
@@ -457,7 +457,7 @@
 {
 	return block_prepare_write(page,from,to,ufs_getfrag_block);
 }
-static int ufs_bmap(struct address_space *mapping, long block)
+static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
 {
 	return generic_block_bmap(mapping,block,ufs_getfrag_block);
 }
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Fri Oct 11 21:22:50 2002
+++ b/fs/ufs/super.c	Fri Oct 11 21:22:50 2002
@@ -457,7 +457,7 @@
 	sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
 	if (!sbi)
 		goto failed_nomem;
-	sb->u.generic_sbp = sbi;
+	sb->s_fs_info = sbi;
 	memset(sbi, 0, sizeof(struct ufs_sb_info));
 
 	UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY)))
@@ -844,7 +844,7 @@
 	if (ubh) ubh_brelse_uspi (uspi);
 	if (uspi) kfree (uspi);
 	if (sbi) kfree(sbi);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	UFSD(("EXIT (FAILED)\n"))
 	return -EINVAL;
 
@@ -892,7 +892,7 @@
 	ubh_brelse_uspi (sbi->s_uspi);
 	kfree (sbi->s_uspi);
 	kfree (sbi);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	return;
 }
 
diff -Nru a/fs/umsdos/namei.c b/fs/umsdos/namei.c
--- a/fs/umsdos/namei.c	Fri Oct 11 21:23:02 2002
+++ b/fs/umsdos/namei.c	Fri Oct 11 21:23:02 2002
@@ -552,7 +552,7 @@
 		goto out;
 
 	ret = -ENOMEM;
-	buffer = get_free_page(GFP_KERNEL);
+	buffer = get_zeroed_page(GFP_KERNEL);
 	if (!buffer)
 		goto out;
 
diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c	Fri Oct 11 21:23:00 2002
+++ b/fs/vfat/namei.c	Fri Oct 11 21:23:00 2002
@@ -49,22 +49,22 @@
 
 static struct dentry_operations vfat_dentry_ops[4] = {
 	{
-		d_hash:		vfat_hashi,
-		d_compare:	vfat_cmpi,
+		.d_hash		= vfat_hashi,
+		.d_compare	= vfat_cmpi,
 	},
 	{
-		d_revalidate:	vfat_revalidate,
-		d_hash:		vfat_hashi,
-		d_compare:	vfat_cmpi,
+		.d_revalidate	= vfat_revalidate,
+		.d_hash		= vfat_hashi,
+		.d_compare	= vfat_cmpi,
 	},
 	{
-		d_hash:		vfat_hash,
-		d_compare:	vfat_cmp,
+		.d_hash		= vfat_hash,
+		.d_compare	= vfat_cmp,
 	},
 	{
-		d_revalidate:	vfat_revalidate,
-		d_hash:		vfat_hash,
-		d_compare:	vfat_cmp,
+		.d_revalidate	= vfat_revalidate,
+		.d_hash		= vfat_hash,
+		.d_compare	= vfat_cmp,
 	}
 };
 
@@ -1269,13 +1269,13 @@
 
 /* Public inode operations for the VFAT fs */
 struct inode_operations vfat_dir_inode_operations = {
-	create:		vfat_create,
-	lookup:		vfat_lookup,
-	unlink:		vfat_unlink,
-	mkdir:		vfat_mkdir,
-	rmdir:		vfat_rmdir,
-	rename:		vfat_rename,
-	setattr:	fat_notify_change,
+	.create		= vfat_create,
+	.lookup		= vfat_lookup,
+	.unlink		= vfat_unlink,
+	.mkdir		= vfat_mkdir,
+	.rmdir		= vfat_rmdir,
+	.rename		= vfat_rename,
+	.setattr	= fat_notify_change,
 };
 
 int vfat_fill_super(struct super_block *sb, void *data, int silent)
diff -Nru a/fs/vfat/vfatfs_syms.c b/fs/vfat/vfatfs_syms.c
--- a/fs/vfat/vfatfs_syms.c	Fri Oct 11 21:23:02 2002
+++ b/fs/vfat/vfatfs_syms.c	Fri Oct 11 21:23:02 2002
@@ -18,11 +18,11 @@
 }
 
 static struct file_system_type vfat_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"vfat",
-	get_sb:		vfat_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "vfat",
+	.get_sb		= vfat_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 EXPORT_SYMBOL(vfat_create);
diff -Nru a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c
--- a/fs/xfs/linux/xfs_aops.c	Fri Oct 11 21:23:03 2002
+++ b/fs/xfs/linux/xfs_aops.c	Fri Oct 11 21:23:03 2002
@@ -692,10 +692,11 @@
 					linvfs_get_blocks_direct);
 }
 
-STATIC int
+
+STATIC sector_t
 linvfs_bmap(
 	struct address_space	*mapping,
-	long			block)
+	sector_t		block)
 {
 	struct inode		*inode = (struct inode *)mapping->host;
 	vnode_t			*vp = LINVFS_GET_VP(inode);
diff -Nru a/fs/xfs/linux/xfs_super.h b/fs/xfs/linux/xfs_super.h
--- a/fs/xfs/linux/xfs_super.h	Fri Oct 11 21:22:55 2002
+++ b/fs/xfs/linux/xfs_super.h	Fri Oct 11 21:22:55 2002
@@ -75,9 +75,9 @@
 
 
 #define LINVFS_GET_VFS(s) \
-	(vfs_t *)((s)->u.generic_sbp)
+	(vfs_t *)((s)->s_fs_info)
 #define LINVFS_SET_VFS(s, vfsp) \
-	((s)->u.generic_sbp = vfsp)
+	((s)->s_fs_info = vfsp)
 
 
 struct xfs_mount_args;
diff -Nru a/include/asm-alpha/pal.h b/include/asm-alpha/pal.h
--- a/include/asm-alpha/pal.h	Fri Oct 11 21:22:57 2002
+++ b/include/asm-alpha/pal.h	Fri Oct 11 21:22:57 2002
@@ -45,7 +45,7 @@
 #define PAL_wrperfmon	57
 #define PAL_rdusp	58
 #define PAL_whami	60
-#define PAL_rtsys	61
+#define PAL_retsys	61
 #define PAL_rti		63
 
 #endif /* __ALPHA_PAL_H */
diff -Nru a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
--- a/include/asm-alpha/unistd.h	Fri Oct 11 21:22:56 2002
+++ b/include/asm-alpha/unistd.h	Fri Oct 11 21:22:56 2002
@@ -331,19 +331,19 @@
 #define __NR_removexattr		391
 #define __NR_lremovexattr		392
 #define __NR_fremovexattr		393
-#define __NR_futex		394
-#define __NR_sched_setaffinity	395     
-#define __NR_sched_getaffinity	396
-#define __NR_tuxcall		397
-#define __NR_io_setup		398
-#define __NR_io_destroy		399
-#define __NR_io_getevents	400
-#define __NR_io_submit		401
-#define __NR_io_cancel		402
-#define __NR_alloc_hugepages	403
-#define __NR_free_hugepages	404
-#define __NR_exit_group		405
-
+#define __NR_futex			394
+#define __NR_sched_setaffinity		395     
+#define __NR_sched_getaffinity		396
+#define __NR_tuxcall			397
+#define __NR_io_setup			398
+#define __NR_io_destroy			399
+#define __NR_io_getevents		400
+#define __NR_io_submit			401
+#define __NR_io_cancel			402
+#define __NR_alloc_hugepages		403
+#define __NR_free_hugepages		404
+#define __NR_exit_group			405
+#define NR_SYSCALLS			406
 
 #if defined(__GNUC__)
 
@@ -598,7 +598,7 @@
 	return sys_wait4(pid, wait_stat, flags, NULL);
 }
 
-#endif
+#endif /* __KERNEL_SYSCALLS__ */
 
 /*
  * "Conditional" syscalls
diff -Nru a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
--- a/include/asm-generic/siginfo.h	Fri Oct 11 21:22:55 2002
+++ b/include/asm-generic/siginfo.h	Fri Oct 11 21:22:55 2002
@@ -91,7 +91,7 @@
 #define __SI_FAULT	(3 << 16)
 #define __SI_CHLD	(4 << 16)
 #define __SI_RT		(5 << 16)
-#define __SI_CODE(T,N)	((T) << 16 | ((N) & 0xffff))
+#define __SI_CODE(T,N)	((T) | ((N) & 0xffff))
 #else
 #define __SI_KILL	0
 #define __SI_TIMER	0
diff -Nru a/include/asm-i386/apic.h b/include/asm-i386/apic.h
--- a/include/asm-i386/apic.h	Fri Oct 11 21:23:05 2002
+++ b/include/asm-i386/apic.h	Fri Oct 11 21:23:05 2002
@@ -87,7 +87,6 @@
 extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback);
 extern void apic_pm_unregister(struct pm_dev*);
 
-extern unsigned int apic_timer_irqs [NR_CPUS];
 extern int check_nmi_watchdog (void);
 extern void enable_NMI_through_LVT0 (void * dummy);
 
diff -Nru a/include/asm-i386/byteorder.h b/include/asm-i386/byteorder.h
--- a/include/asm-i386/byteorder.h	Fri Oct 11 21:23:00 2002
+++ b/include/asm-i386/byteorder.h	Fri Oct 11 21:23:00 2002
@@ -24,21 +24,41 @@
 	return x;
 }
 
+/* gcc should generate this for open coded C now too. May be worth switching to 
+   it because inline assembly cannot be scheduled. -AK */
 static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
-	__asm__("xchgb %b0,%h0"		/* swap bytes		*/ \
-		: "=q" (x) \
-		:  "0" (x)); \
+	__asm__("xchgb %b0,%h0"		/* swap bytes		*/
+		: "=q" (x)
+		:  "0" (x));
 		return x;
 }
 
+
+static inline __u64 ___arch__swab64(__u64 val) 
+{ 
+	union { 
+		struct { __u32 a,b; } s;
+		__u64 u;
+	} v;
+	v.u = val;
+#ifdef CONFIG_X86_BSWAP
+	asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1" 
+	    : "=r" (v.s.a), "=r" (v.s.b) 
+	    : "0" (v.s.a), "1" (v.s.b)); 
+#else
+   v.s.a = ___arch__swab32(v.s.a); 
+	v.s.b = ___arch__swab32(v.s.b); 
+	asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b));
+#endif
+	return v.u;	
+} 
+
+#define __arch__swab64(x) ___arch__swab64(x)
 #define __arch__swab32(x) ___arch__swab32(x)
 #define __arch__swab16(x) ___arch__swab16(x)
 
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-#  define __BYTEORDER_HAS_U64__
-#  define __SWAB_64_THRU_32__
-#endif
+#define __BYTEORDER_HAS_U64__
 
 #endif /* __GNUC__ */
 
diff -Nru a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
--- a/include/asm-i386/fixmap.h	Fri Oct 11 21:22:52 2002
+++ b/include/asm-i386/fixmap.h	Fri Oct 11 21:22:52 2002
@@ -65,6 +65,9 @@
 #ifdef CONFIG_X86_F00F_BUG
 	FIX_F00F_IDT,	/* Virtual mapping for IDT */
 #endif
+#ifdef CONFIG_X86_CYCLONE
+	FIX_CYCLONE_TIMER, /*cyclone timer register*/
+#endif 
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
diff -Nru a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
--- a/include/asm-i386/hardirq.h	Fri Oct 11 21:23:02 2002
+++ b/include/asm-i386/hardirq.h	Fri Oct 11 21:23:02 2002
@@ -12,6 +12,7 @@
 	struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
 	unsigned long idle_timestamp;
 	unsigned int __nmi_count;	/* arch dependent */
+	unsigned int apic_timer_irqs;	/* arch dependent */
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
diff -Nru a/include/asm-i386/io.h b/include/asm-i386/io.h
--- a/include/asm-i386/io.h	Fri Oct 11 21:23:05 2002
+++ b/include/asm-i386/io.h	Fri Oct 11 21:23:05 2002
@@ -165,8 +165,8 @@
 #define __raw_writel writel
 
 #define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
-#define memcpy_fromio(a,b,c)	memcpy((a),__io_virt(b),(c))
-#define memcpy_toio(a,b,c)	memcpy(__io_virt(a),(b),(c))
+#define memcpy_fromio(a,b,c)	__memcpy((a),__io_virt(b),(c))
+#define memcpy_toio(a,b,c)	__memcpy(__io_virt(a),(b),(c))
 
 /*
  * ISA space is 'always mapped' on a typical x86 system, no need to
@@ -286,122 +286,90 @@
 #endif /* __KERNEL__ */
 
 #ifdef SLOW_IO_BY_JUMPING
-#define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:"
+#define __SLOW_DOWN_IO "jmp 1f; 1: jmp 1f; 1:"
 #else
-#define __SLOW_DOWN_IO "\noutb %%al,$0x80"
+#define __SLOW_DOWN_IO "outb %%al,$0x80;"
 #endif
 
+static inline void slow_down_io(void) {
+	__asm__ __volatile__(
+		__SLOW_DOWN_IO
 #ifdef REALLY_SLOW_IO
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
-#else
-#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
+		__SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
 #endif
+		: : );
+}
 
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_X86_NUMAQ
 extern void *xquad_portio;    /* Where the IO area was mapped */
-#endif /* CONFIG_MULTIQUAD */
-
-/*
- * Talk about misusing macros..
- */
-#define __OUT1(s,x) \
-static inline void out##s(unsigned x value, unsigned short port) {
-
-#define __OUT2(s,s1,s2) \
-__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
-
-#ifdef CONFIG_MULTIQUAD
-#define __OUTQ(s,ss,x)    /* Do the equivalent of the portio op on quads */ \
-static inline void out##ss(unsigned x value, unsigned short port) { \
+#define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port)
+#define __BUILDIO(bwl,bw,type) \
+static inline void out##bwl##_quad(unsigned type value, int port, int quad) { \
 	if (xquad_portio) \
-		write##s(value, (unsigned long) xquad_portio + port); \
-	else               /* We're still in early boot, running on quad 0 */ \
-		out##ss##_local(value, port); \
+		write##bwl(value, XQUAD_PORT_ADDR(port, quad)); \
+	else \
+		out##bwl##_local(value, port); \
 } \
-static inline void out##ss##_quad(unsigned x value, unsigned short port, int quad) { \
+static inline void out##bwl(unsigned type value, int port) { \
+	out##bwl##_quad(value, port, 0); \
+} \
+static inline unsigned type in##bwl##_quad(int port, int quad) { \
 	if (xquad_portio) \
-		write##s(value, (unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
-			+ port); \
+		return read##bwl(XQUAD_PORT_ADDR(port, quad)); \
+	else \
+		return in##bwl##_local(port); \
+} \
+static inline unsigned type in##bwl(int port) { \
+	return in##bwl##_quad(port, 0); \
+}
+#else
+#define __BUILDIO(bwl,bw,type) \
+static inline void out##bwl(unsigned type value, int port) { \
+	out##bwl##_local(value, port); \
+} \
+static inline unsigned type in##bwl(int port) { \
+	return in##bwl##_local(port); \
 }
+#endif
 
-#define __INQ(s,ss)       /* Do the equivalent of the portio op on quads */ \
-static inline RETURN_TYPE in##ss(unsigned short port) { \
-	if (xquad_portio) \
-		return read##s((unsigned long) xquad_portio + port); \
-	else               /* We're still in early boot, running on quad 0 */ \
-		return in##ss##_local(port); \
+
+#define BUILDIO(bwl,bw,type) \
+static inline void out##bwl##_local(unsigned type value, int port) { \
+	__asm__ __volatile__("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)); \
 } \
-static inline RETURN_TYPE in##ss##_quad(unsigned short port, int quad) { \
-	if (xquad_portio) \
-		return read##s((unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
-			+ port); \
-	else\
-		return 0;\
-}
-#endif /* CONFIG_MULTIQUAD */
-
-#ifndef CONFIG_MULTIQUAD
-#define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} 
-#else
-/* Make the default portio routines operate on quad 0 */
-#define __OUT(s,s1,x) \
-__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
-__OUTQ(s,s,x) \
-__OUTQ(s,s##_p,x) 
-#endif /* CONFIG_MULTIQUAD */
-
-#define __IN1(s) \
-static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
-
-#define __IN2(s,s1,s2) \
-__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
-
-#ifndef CONFIG_MULTIQUAD
-#define __IN(s,s1,i...) \
-__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } 
-#else
-/* Make the default portio routines operate on quad 0 */
-#define __IN(s,s1,i...) \
-__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__INQ(s,s) \
-__INQ(s,s##_p) 
-#endif /* CONFIG_MULTIQUAD */
-
-#define __INS(s) \
-static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("rep ; ins" #s \
-: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-#define __OUTS(s) \
-static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
-{ __asm__ __volatile__ ("rep ; outs" #s \
-: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
-
-#define RETURN_TYPE unsigned char
-__IN(b,"")
-#undef RETURN_TYPE
-#define RETURN_TYPE unsigned short
-__IN(w,"")
-#undef RETURN_TYPE
-#define RETURN_TYPE unsigned int
-__IN(l,"")
-#undef RETURN_TYPE
-
-__OUT(b,"b",char)
-__OUT(w,"w",short)
-__OUT(l,,int)
-
-__INS(b)
-__INS(w)
-__INS(l)
-
-__OUTS(b)
-__OUTS(w)
-__OUTS(l)
+static inline unsigned type in##bwl##_local(int port) { \
+	unsigned type value; \
+	__asm__ __volatile__("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)); \
+	return value; \
+} \
+static inline void out##bwl##_local_p(unsigned type value, int port) { \
+	out##bwl##_local(value, port); \
+	slow_down_io(); \
+} \
+static inline unsigned type in##bwl##_local_p(int port) { \
+	unsigned type value = in##bwl##_local(port); \
+	slow_down_io(); \
+	return value; \
+} \
+__BUILDIO(bwl,bw,type) \
+static inline void out##bwl##_p(unsigned type value, int port) { \
+	out##bwl(value, port); \
+	slow_down_io(); \
+} \
+static inline unsigned type in##bwl##_p(int port) { \
+	unsigned type value = in##bwl(port); \
+	slow_down_io(); \
+	return value; \
+} \
+static inline void outs##bwl(int port, const void *addr, unsigned long count) { \
+	__asm__ __volatile__("rep; outs" #bwl : "+S"(addr), "+c"(count) : "d"(port)); \
+} \
+static inline void ins##bwl(int port, void *addr, unsigned long count) { \
+	__asm__ __volatile__("rep; ins" #bwl : "+D"(addr), "+c"(count) : "d"(port)); \
+}
+
+BUILDIO(b,b,char)
+BUILDIO(w,w,short)
+BUILDIO(l,,long)
 
 #endif
diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
--- a/include/asm-i386/mpspec.h	Fri Oct 11 21:22:50 2002
+++ b/include/asm-i386/mpspec.h	Fri Oct 11 21:22:50 2002
@@ -16,11 +16,11 @@
 /*
  * a maximum of 16 APICs with the current APIC ID architecture.
  */
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_X86_NUMAQ
 #define MAX_APICS 256
-#else /* !CONFIG_MULTIQUAD */
+#else /* !CONFIG_X86_NUMAQ */
 #define MAX_APICS 16
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_X86_NUMAQ */
 
 #define MAX_MPC_ENTRY 1024
 
@@ -184,11 +184,11 @@
  *	7	2 CPU MCA+PCI
  */
 
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_X86_NUMAQ
 #define MAX_IRQ_SOURCES 512
-#else /* !CONFIG_MULTIQUAD */
+#else /* !CONFIG_X86_NUMAQ */
 #define MAX_IRQ_SOURCES 256
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_X86_NUMAQ */
 
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
diff -Nru a/include/asm-i386/page.h b/include/asm-i386/page.h
--- a/include/asm-i386/page.h	Fri Oct 11 21:22:54 2002
+++ b/include/asm-i386/page.h	Fri Oct 11 21:22:54 2002
@@ -142,6 +142,7 @@
 #define MAXMEM			((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 #ifndef CONFIG_DISCONTIGMEM
 #define pfn_to_page(pfn)	(mem_map + (pfn))
 #define page_to_pfn(page)	((unsigned long)((page) - mem_map))
diff -Nru a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
--- a/include/asm-i386/pgtable.h	Fri Oct 11 21:23:02 2002
+++ b/include/asm-i386/pgtable.h	Fri Oct 11 21:23:02 2002
@@ -259,12 +259,21 @@
 		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 #define pte_offset_kernel(dir, address) \
 	((pte_t *) pmd_page_kernel(*(dir)) +  __pte_offset(address))
+
+#if defined(CONFIG_HIGHPTE)
 #define pte_offset_map(dir, address) \
 	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + __pte_offset(address))
 #define pte_offset_map_nested(dir, address) \
 	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + __pte_offset(address))
 #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
 #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+#else
+#define pte_offset_map(dir, address) \
+	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
+#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
+#define pte_unmap(pte) do { } while (0)
+#define pte_unmap_nested(pte) do { } while (0)
+#endif
 
 #if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G)
 typedef u32 pte_addr_t;
diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h
--- a/include/asm-i386/processor.h	Fri Oct 11 21:22:52 2002
+++ b/include/asm-i386/processor.h	Fri Oct 11 21:22:52 2002
@@ -380,7 +380,7 @@
 /* virtual 86 mode info */
 	struct vm86_struct	* vm86_info;
 	unsigned long		screen_bitmap;
-	unsigned long		v86flags, v86mask, v86mode, saved_esp0;
+	unsigned long		v86flags, v86mask, saved_esp0;
 /* IO permissions */
 	unsigned long	*ts_io_bitmap;
 };
@@ -392,7 +392,7 @@
 	{ [0 ... 7] = 0 },	/* debugging registers */	\
 	0, 0, 0,						\
 	{ { 0, }, },		/* 387 state */			\
-	0,0,0,0,0,0,						\
+	0,0,0,0,0,						\
 	NULL,			/* io permissions */		\
 }
 
diff -Nru a/include/asm-i386/smp.h b/include/asm-i386/smp.h
--- a/include/asm-i386/smp.h	Fri Oct 11 21:22:51 2002
+++ b/include/asm-i386/smp.h	Fri Oct 11 21:22:51 2002
@@ -22,7 +22,7 @@
 #endif
 
 #ifdef CONFIG_SMP
-# ifdef CONFIG_MULTIQUAD
+# ifdef CONFIG_CLUSTERED_APIC
 #  define TARGET_CPUS 0xf     /* all CPUs in *THIS* quad */
 #  define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
 # else
@@ -35,13 +35,13 @@
 #endif
 
 #ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
+ #ifdef CONFIG_CLUSTERED_APIC
   #define clustered_apic_mode (1)
   #define esr_disable (1)
- #else /* !CONFIG_MULTIQUAD */
+ #else /* !CONFIG_CLUSTERED_APIC */
   #define clustered_apic_mode (0)
   #define esr_disable (0)
- #endif /* CONFIG_MULTIQUAD */
+ #endif /* CONFIG_CLUSTERED_APIC */
 #endif 
 
 #ifdef CONFIG_SMP
diff -Nru a/include/asm-i386/smpboot.h b/include/asm-i386/smpboot.h
--- a/include/asm-i386/smpboot.h	Fri Oct 11 21:23:04 2002
+++ b/include/asm-i386/smpboot.h	Fri Oct 11 21:23:04 2002
@@ -2,35 +2,35 @@
 #define __ASM_SMPBOOT_H
 
 #ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
+ #ifdef CONFIG_CLUSTERED_APIC
   #define clustered_apic_mode (1)
- #else /* !CONFIG_MULTIQUAD */
+ #else /* !CONFIG_CLUSTERED_APIC */
   #define clustered_apic_mode (0)
- #endif /* CONFIG_MULTIQUAD */
+ #endif /* CONFIG_CLUSTERED_APIC */
 #endif 
  
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_CLUSTERED_APIC
  #define TRAMPOLINE_LOW phys_to_virt(0x8)
  #define TRAMPOLINE_HIGH phys_to_virt(0xa)
-#else /* !CONFIG_MULTIQUAD */
+#else /* !CONFIG_CLUSTERED_APIC */
  #define TRAMPOLINE_LOW phys_to_virt(0x467)
  #define TRAMPOLINE_HIGH phys_to_virt(0x469)
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_CLUSTERED_APIC */
 
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_CLUSTERED_APIC
  #define boot_cpu_apicid boot_cpu_logical_apicid
-#else /* !CONFIG_MULTIQUAD */
+#else /* !CONFIG_CLUSTERED_APIC */
  #define boot_cpu_apicid boot_cpu_physical_apicid
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_CLUSTERED_APIC */
 
 /*
  * How to map from the cpu_present_map
  */
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_CLUSTERED_APIC
  #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) )
-#else /* !CONFIG_MULTIQUAD */
+#else /* !CONFIG_CLUSTERED_APIC */
  #define cpu_present_to_apicid(apicid) (apicid)
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_CLUSTERED_APIC */
 
 /*
  * Mappings between logical cpu number and logical / physical apicid
@@ -45,18 +45,13 @@
 #define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu]
 #define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
 #define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu]
-#ifdef CONFIG_MULTIQUAD			/* use logical IDs to bootstrap */
+#ifdef CONFIG_CLUSTERED_APIC			/* use logical IDs to bootstrap */
 #define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid]
 #define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu]
-#else /* !CONFIG_MULTIQUAD */		/* use physical IDs to bootstrap */
+#else /* !CONFIG_CLUSTERED_APIC */		/* use physical IDs to bootstrap */
 #define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
 #define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
-#endif /* CONFIG_MULTIQUAD */
-
-
-#ifdef CONFIG_MULTIQUAD
-#else /* !CONFIG_MULTIQUAD */
-#endif /* CONFIG_MULTIQUAD */
+#endif /* CONFIG_CLUSTERED_APIC */
 
 
 #endif
diff -Nru a/include/asm-i386/timer.h b/include/asm-i386/timer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/timer.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,22 @@
+#ifndef _ASMi386_TIMER_H
+#define _ASMi386_TIMER_H
+
+/**
+ * struct timer_ops - used to define a timer source
+ *
+ * @init: Probes and initializes the timer.  Returns 0 on success, anything
+ *	else on failure.
+ * @mark_offset: called by the timer interrupt
+ * @get_offset: called by gettimeofday().  Returns the number of ms since the
+ *	last timer intruupt.
+ */
+struct timer_opts{
+	int (*init)(void);
+	void (*mark_offset)(void);
+	unsigned long (*get_offset)(void);
+};
+
+#define TICK_SIZE (tick_nsec / 1000)
+
+extern struct timer_opts* select_timer(void);
+#endif
diff -Nru a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
--- a/include/asm-i386/tlbflush.h	Fri Oct 11 21:22:56 2002
+++ b/include/asm-i386/tlbflush.h	Fri Oct 11 21:22:56 2002
@@ -10,8 +10,8 @@
 		unsigned int tmpreg;					\
 									\
 		__asm__ __volatile__(					\
-			"movl %%cr3, %0;  # flush TLB \n"		\
-			"movl %0, %%cr3;              \n"		\
+			"movl %%cr3, %0;              \n"		\
+			"movl %0, %%cr3;  # flush TLB \n"		\
 			: "=r" (tmpreg)					\
 			:: "memory");					\
 	} while (0)
@@ -26,8 +26,8 @@
 									\
 		__asm__ __volatile__(					\
 			"movl %1, %%cr4;  # turn off PGE     \n"	\
-			"movl %%cr3, %0;  # flush TLB        \n"	\
-			"movl %0, %%cr3;                     \n"	\
+			"movl %%cr3, %0;                     \n"	\
+			"movl %0, %%cr3;  # flush TLB        \n"	\
 			"movl %2, %%cr4;  # turn PGE back on \n"	\
 			: "=&r" (tmpreg)				\
 			: "r" (mmu_cr4_features & ~X86_CR4_PGE),	\
@@ -129,7 +129,7 @@
 {
 	struct mm_struct *active_mm;
 	int state;
-	char __cacheline_padding[24];
+	char __cacheline_padding[L1_CACHE_BYTES-8];
 };
 extern struct tlb_state cpu_tlbstate[NR_CPUS];
 
diff -Nru a/include/asm-i386/types.h b/include/asm-i386/types.h
--- a/include/asm-i386/types.h	Fri Oct 11 21:22:51 2002
+++ b/include/asm-i386/types.h	Fri Oct 11 21:22:51 2002
@@ -52,6 +52,11 @@
 #endif
 typedef u64 dma64_addr_t;
 
+#ifdef CONFIG_LBD
+typedef u64 sector_t;
+#define HAVE_SECTOR_T
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif
diff -Nru a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h
--- a/include/asm-m68k/machdep.h	Fri Oct 11 21:22:54 2002
+++ b/include/asm-m68k/machdep.h	Fri Oct 11 21:22:54 2002
@@ -4,17 +4,12 @@
 #include <linux/seq_file.h>
 
 struct pt_regs;
-struct kbd_repeat;
 struct mktime;
 struct rtc_time;
+struct rtc_pll_info;
 struct buffer_head;
 
 extern void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *));
-/* machine dependent keyboard functions */
-extern int (*mach_keyb_init) (void);
-extern int (*mach_kbdrate) (struct kbd_repeat *);
-extern void (*mach_kbd_leds) (unsigned int);
-extern int (*mach_kbd_translate)(unsigned char scancode, unsigned char *keycode, char raw_mode);
 /* machine dependent irq functions */
 extern void (*mach_init_IRQ) (void);
 extern void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *);
@@ -28,6 +23,8 @@
 /* machine dependent timer functions */
 extern unsigned long (*mach_gettimeoffset)(void);
 extern int (*mach_hwclk)(int, struct rtc_time*);
+extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
+extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
 extern int (*mach_set_clock_mmss)(unsigned long);
 extern void (*mach_reset)( void );
 extern void (*mach_halt)( void );
@@ -38,9 +35,6 @@
 extern void (*mach_floppy_setup)(char *, int *);
 extern void (*mach_heartbeat) (int);
 extern void (*mach_l2_flush) (int);
-extern int mach_sysrq_key;
-extern int mach_sysrq_shift_state;
-extern int mach_sysrq_shift_mask;
-extern char *mach_sysrq_xlate;
+extern void (*mach_beep) (unsigned int, unsigned int);
 
 #endif /* _M68K_MACHDEP_H */
diff -Nru a/include/asm-m68k/q40_keyboard.h b/include/asm-m68k/q40_keyboard.h
--- a/include/asm-m68k/q40_keyboard.h	Fri Oct 11 21:23:05 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,33 +0,0 @@
-/*
- *  linux/include/asm-m68k/q40_keyboard.h
- *
- *  Q40 specific keyboard definitions
- */
-
-
-#ifdef __KERNEL__
-
-
-#include <asm/machdep.h>
-
-
-
-extern int q40kbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int q40kbd_getkeycode(unsigned int scancode);
-extern int q40kbd_pretranslate(unsigned char scancode, char raw_mode);
-extern int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char q40kbd_unexpected_up(unsigned char keycode);
-extern void q40kbd_leds(unsigned char leds);
-extern int q40kbd_is_sysrq(unsigned char keycode);
-extern int q40kbd_init_hw(void);
-extern unsigned char q40kbd_sysrq_xlate[128];
-
-
-
-#endif /* __KERNEL__ */
-
-
-
-
-
diff -Nru a/include/asm-m68k/sun3_pgalloc.h b/include/asm-m68k/sun3_pgalloc.h
--- a/include/asm-m68k/sun3_pgalloc.h	Fri Oct 11 21:22:56 2002
+++ b/include/asm-m68k/sun3_pgalloc.h	Fri Oct 11 21:22:56 2002
@@ -87,7 +87,7 @@
 {
      pgd_t *new_pgd;
 
-     new_pgd = (pgd_t *)get_free_page(GFP_KERNEL);
+     new_pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL);
      memcpy(new_pgd, swapper_pg_dir, PAGE_SIZE);
      memset(new_pgd, 0, (PAGE_OFFSET >> PGDIR_SHIFT));
      return new_pgd;
diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
--- a/include/asm-ppc/hardirq.h	Fri Oct 11 21:22:50 2002
+++ b/include/asm-ppc/hardirq.h	Fri Oct 11 21:22:50 2002
@@ -82,7 +82,7 @@
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
 #if CONFIG_PREEMPT
-# define in_atomic()	(preempt_count() != kernel_locked())
+# define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
 # define in_atomic()	(preempt_count() != 0)
diff -Nru a/include/asm-ppc/ibm405.h b/include/asm-ppc/ibm405.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/ibm405.h	Fri Oct 11 21:22:51 2002
@@ -0,0 +1,334 @@
+/*
+ * ibm405.h
+ *
+ *	This was derived from the ppc4xx.h and contains
+ *	common 405 offsets
+ *
+ *      Armin Kuster akuster@pacbell.net
+ *      Jan, 2002
+ *
+ *
+ * Copyright 2002 MontaVista Softare Inc.
+ *
+ * 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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 (02/01/17) - A. Kuster
+ *	Initial version	 - moved 405  specific out of the other core.h's
+ *
+ *	Version 1.0 (02/08/02) - A. Kuster
+ *	removed DCRN_UIC1_BASE to NP405L & H
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IBM405_H__
+#define __ASM_IBM405_H__
+
+#ifdef DCRN_BE_BASE
+#define DCRN_BEAR	(DCRN_BE_BASE + 0x0)	/* Bus Error Address Register */
+#define DCRN_BESR	(DCRN_BE_BASE + 0x1)	/* Bus Error Syndrome Register */
+#endif
+/* DCRN_BESR */
+#define BESR_DSES	0x80000000	/* Data-Side Error Status */
+#define BESR_DMES	0x40000000	/* DMA Error Status */
+#define BESR_RWS	0x20000000	/* Read/Write Status */
+#define BESR_ETMASK	0x1C000000	/* Error Type */
+#define ET_PROT	0
+#define ET_PARITY	1
+#define ET_NCFG	2
+#define ET_BUSERR	4
+#define ET_BUSTO	6
+
+#ifdef DCRN_CHCR_BASE
+#define DCRN_CHCR0	(DCRN_CHCR_BASE + 0x0)	/* Chip Control Register 1 */
+#define DCRN_CHCR1	(DCRN_CHCR_BASE + 0x1)	/* Chip Control Register 2 */
+#endif
+#define CHR1_PCIPW	0x00008000	/* PCI Int enable/Peripheral Write enable */
+
+#ifdef DCRN_CHPSR_BASE
+#define DCRN_CHPSR	(DCRN_CHPSR_BASE + 0x0)	/* Chip Pin Strapping */
+#endif
+
+#ifdef DCRN_CPMFR_BASE
+#define DCRN_CPMFR	(DCRN_CPMFR_BASE + 0x0)	/* CPM Force */
+#endif
+
+#ifdef DCRN_CPMSR_BASE
+#define DCRN_CPMSR	(DCRN_CPMSR_BASE + 0x0)	/* CPM Status */
+#define DCRN_CPMER	(DCRN_CPMSR_BASE + 0x1)	/* CPM Enable */
+#endif
+
+#ifdef DCRN_DCP0_BASE
+/* Decompression Controller Address */
+#define DCRN_DCP0_CFGADDR	(DCRN_DCP0_BASE + 0x0)
+/* Decompression Controller Data */
+#define DCRN_DCP0_CFGDATA	(DCRN_DCP0_BASE + 0x1)
+#else
+#define DCRN_DCP0_CFGADDR	0x0
+#define DCRN_DCP0_CFGDATA	0x0
+#endif
+
+#ifdef DCRN_DMA0_BASE
+/* DMA Channel Control Register 0 */
+#define DCRN_DMACR0	(DCRN_DMA0_BASE + 0x0)
+#define DCRN_DMACT0	(DCRN_DMA0_BASE + 0x1)	/* DMA Count Register 0 */
+/* DMA Destination Address Register 0 */
+#define DCRN_DMADA0	(DCRN_DMA0_BASE + 0x2)
+/* DMA Source Address Register 0 */
+#define DCRN_DMASA0	(DCRN_DMA0_BASE + 0x3)
+#ifdef DCRNCAP_DMA_CC
+/* DMA Chained Count Register 0 */
+#define DCRN_DMACC0	(DCRN_DMA0_BASE + 0x4)
+#endif
+#ifdef DCRNCAP_DMA_SG
+/* DMA Scatter/Gather Descriptor Addr 0 */
+#define DCRN_ASG0	(DCRN_DMA0_BASE + 0x4)
+#endif
+#endif
+
+#ifdef DCRN_DMA1_BASE
+/* DMA Channel Control Register 1 */
+#define DCRN_DMACR1	(DCRN_DMA1_BASE + 0x0)
+#define DCRN_DMACT1	(DCRN_DMA1_BASE + 0x1)	/* DMA Count Register 1 */
+/* DMA Destination Address Register 1 */
+#define DCRN_DMADA1	(DCRN_DMA1_BASE + 0x2)
+/* DMA Source Address Register 1 */
+#define DCRN_DMASA1	(DCRN_DMA1_BASE + 0x3)	/* DMA Source Address Register 1 */
+#ifdef DCRNCAP_DMA_CC
+/* DMA Chained Count Register 1 */
+#define DCRN_DMACC1	(DCRN_DMA1_BASE + 0x4)
+#endif
+#ifdef DCRNCAP_DMA_SG
+/* DMA Scatter/Gather Descriptor Addr 1 */
+#define DCRN_ASG1	(DCRN_DMA1_BASE + 0x4)
+#endif
+#endif
+
+#ifdef DCRN_DMA2_BASE
+#define DCRN_DMACR2	(DCRN_DMA2_BASE + 0x0)	/* DMA Channel Control Register 2 */
+#define DCRN_DMACT2	(DCRN_DMA2_BASE + 0x1)	/* DMA Count Register 2 */
+#define DCRN_DMADA2	(DCRN_DMA2_BASE + 0x2)	/* DMA Destination Address Register 2 */
+#define DCRN_DMASA2	(DCRN_DMA2_BASE + 0x3)	/* DMA Source Address Register 2 */
+#ifdef DCRNCAP_DMA_CC
+#define DCRN_DMACC2	(DCRN_DMA2_BASE + 0x4)	/* DMA Chained Count Register 2 */
+#endif
+#ifdef DCRNCAP_DMA_SG
+#define DCRN_ASG2	(DCRN_DMA2_BASE + 0x4)	/* DMA Scatter/Gather Descriptor Addr 2 */
+#endif
+#endif
+
+#ifdef DCRN_DMA3_BASE
+#define DCRN_DMACR3	(DCRN_DMA3_BASE + 0x0)	/* DMA Channel Control Register 3 */
+#define DCRN_DMACT3	(DCRN_DMA3_BASE + 0x1)	/* DMA Count Register 3 */
+#define DCRN_DMADA3	(DCRN_DMA3_BASE + 0x2)	/* DMA Destination Address Register 3 */
+#define DCRN_DMASA3	(DCRN_DMA3_BASE + 0x3)	/* DMA Source Address Register 3 */
+#ifdef DCRNCAP_DMA_CC
+#define DCRN_DMACC3	(DCRN_DMA3_BASE + 0x4)	/* DMA Chained Count Register 3 */
+#endif
+#ifdef DCRNCAP_DMA_SG
+#define DCRN_ASG3	(DCRN_DMA3_BASE + 0x4)	/* DMA Scatter/Gather Descriptor Addr 3 */
+#endif
+#endif
+
+#ifdef DCRN_DMASR_BASE
+#define DCRN_DMASR	(DCRN_DMASR_BASE + 0x0)	/* DMA Status Register */
+#ifdef DCRNCAP_DMA_SG
+#define DCRN_ASGC	(DCRN_DMASR_BASE + 0x3)	/* DMA Scatter/Gather Command */
+/* don't know if these two registers always exist if scatter/gather exists */
+#define DCRN_POL	(DCRN_DMASR_BASE + 0x6)	/* DMA Polarity Register */
+#define DCRN_SLP	(DCRN_DMASR_BASE + 0x5)	/* DMA Sleep Register */
+#endif
+#endif
+
+#ifdef DCRN_EBC_BASE
+#define DCRN_EBCCFGADR	(DCRN_EBC_BASE + 0x0)	/* Peripheral Controller Address */
+#define DCRN_EBCCFGDATA	(DCRN_EBC_BASE + 0x1)	/* Peripheral Controller Data */
+#endif
+
+#ifdef DCRN_EXIER_BASE
+#define DCRN_EXIER	(DCRN_EXIER_BASE + 0x0)	/* External Interrupt Enable Register */
+#endif
+
+#ifdef DCRN_EXISR_BASE
+#define DCRN_EXISR	(DCRN_EXISR_BASE + 0x0)	/* External Interrupt Status Register */
+#endif
+
+#define EXIER_CIE	0x80000000	/* Critical Interrupt Enable */
+#define EXIER_SRIE	0x08000000	/* Serial Port Rx Int. Enable */
+#define EXIER_STIE	0x04000000	/* Serial Port Tx Int. Enable */
+#define EXIER_JRIE	0x02000000	/* JTAG Serial Port Rx Int. Enable */
+#define EXIER_JTIE	0x01000000	/* JTAG Serial Port Tx Int. Enable */
+#define EXIER_D0IE	0x00800000	/* DMA Channel 0 Interrupt Enable */
+#define EXIER_D1IE	0x00400000	/* DMA Channel 1 Interrupt Enable */
+#define EXIER_D2IE	0x00200000	/* DMA Channel 2 Interrupt Enable */
+#define EXIER_D3IE	0x00100000	/* DMA Channel 3 Interrupt Enable */
+#define EXIER_E0IE	0x00000010	/* External Interrupt 0 Enable */
+#define EXIER_E1IE	0x00000008	/* External Interrupt 1 Enable */
+#define EXIER_E2IE	0x00000004	/* External Interrupt 2 Enable */
+#define EXIER_E3IE	0x00000002	/* External Interrupt 3 Enable */
+#define EXIER_E4IE	0x00000001	/* External Interrupt 4 Enable */
+
+#ifdef DCRN_IOCR_BASE
+#define DCRN_IOCR	(DCRN_IOCR_BASE + 0x0)	/* Input/Output Configuration Register */
+#endif
+#define IOCR_E0TE	0x80000000
+#define IOCR_E0LP	0x40000000
+#define IOCR_E1TE	0x20000000
+#define IOCR_E1LP	0x10000000
+#define IOCR_E2TE	0x08000000
+#define IOCR_E2LP	0x04000000
+#define IOCR_E3TE	0x02000000
+#define IOCR_E3LP	0x01000000
+#define IOCR_E4TE	0x00800000
+#define IOCR_E4LP	0x00400000
+#define IOCR_EDT	0x00080000
+#define IOCR_SOR	0x00040000
+#define IOCR_EDO	0x00008000
+#define IOCR_2XC	0x00004000
+#define IOCR_ATC	0x00002000
+#define IOCR_SPD	0x00001000
+#define IOCR_BEM	0x00000800
+#define IOCR_PTD	0x00000400
+#define IOCR_ARE	0x00000080
+#define IOCR_DRC	0x00000020
+#define IOCR_RDM(x)	(((x) & 0x3) << 3)
+#define IOCR_TCS	0x00000004
+#define IOCR_SCS	0x00000002
+#define IOCR_SPC	0x00000001
+
+#define DCRN_MALCR(base)	(base + 0x0)	/* MAL Configuration */
+#define DCRN_MALDBR(base)	((base) + 0x3)	/* Debug Register */
+#define DCRN_MALESR(base)	((base) + 0x1)	/* Error Status */
+#define DCRN_MALIER(base)	((base) + 0x2)	/* Interrupt Enable */
+#define DCRN_MALTXCARR(base)	((base) + 0x5)	/* TX Channed Active Reset Register */
+#define DCRN_MALTXCASR(base)	((base) + 0x4)	/* TX Channel Active Set Register */
+#define DCRN_MALTXDEIR(base)	((base) + 0x7)	/* Tx Descriptor Error Interrupt */
+#define DCRN_MALTXEOBISR(base)	((base) + 0x6)	/* Tx End of Buffer Interrupt Status */
+#define DCRN_MALRXCARR(base)	((base) + 0x11)	/* RX Channed Active Reset Register */
+#define DCRN_MALRXCASR(base)	((base) + 0x10)	/* RX Channel Active Set Register */
+#define DCRN_MALRXDEIR(base)	((base) + 0x13)	/* Rx Descriptor Error Interrupt */
+#define DCRN_MALRXEOBISR(base)	((base) + 0x12)	/* Rx End of Buffer Interrupt Status */
+#define DCRN_MALRXCTP0R(base)	((base) + 0x40)	/* Channel Rx 0 Channel Table Pointer */
+#define DCRN_MALRXCTP1R(base)	((base) + 0x41)	/* Channel Rx 1 Channel Table Pointer */
+#define DCRN_MALTXCTP0R(base)	((base) + 0x20)	/* Channel Tx 0 Channel Table Pointer */
+#define DCRN_MALTXCTP1R(base)	((base) + 0x21)	/* Channel Tx 1 Channel Table Pointer */
+#define DCRN_MALTXCTP2R(base)	((base) + 0x22)	/* Channel Tx 2 Channel Table Pointer */
+#define DCRN_MALTXCTP3R(base)	((base) + 0x23)	/* Channel Tx 3 Channel Table Pointer */
+#define DCRN_MALRCBS0(base)	((base) + 0x60)	/* Channel Rx 0 Channel Buffer Size */
+#define DCRN_MALRCBS1(base)	((base) + 0x61)	/* Channel Rx 1 Channel Buffer Size */
+
+/* EMAC DCRN's */
+#define DCRN_MALRXCTP2R(base)	((base) + 0x42)	/* Channel Rx 2 Channel Table Pointer */
+#define DCRN_MALRXCTP3R(base)	((base) + 0x43)	/* Channel Rx 3 Channel Table Pointer */
+#define DCRN_MALTXCTP4R(base)	((base) + 0x24)	/* Channel Tx 4 Channel Table Pointer */
+#define DCRN_MALTXCTP5R(base)	((base) + 0x25)	/* Channel Tx 5 Channel Table Pointer */
+#define DCRN_MALTXCTP6R(base)	((base) + 0x26)	/* Channel Tx 6 Channel Table Pointer */
+#define DCRN_MALTXCTP7R(base)	((base) + 0x27)	/* Channel Tx 7 Channel Table Pointer */
+#define DCRN_MALRCBS2(base)	((base) + 0x62)	/* Channel Rx 2 Channel Buffer Size */
+#define DCRN_MALRCBS3(base)	((base) + 0x63)	/* Channel Rx 3 Channel Buffer Size */
+
+ /* DCRN_MALCR */
+#define MALCR_MMSR		0x80000000	/* MAL Software reset */
+#define MALCR_PLBP_1		0x00400000	/* MAL reqest priority: */
+#define MALCR_PLBP_2		0x00800000	/* lowsest is 00 */
+#define MALCR_PLBP_3		0x00C00000	/* highest */
+#define MALCR_GA		0x00200000	/* Guarded Active Bit */
+#define MALCR_OA		0x00100000	/* Ordered Active Bit */
+#define MALCR_PLBLE		0x00080000	/* PLB Lock Error Bit */
+#define MALCR_PLBLT_1		0x00040000	/* PLB Latency Timer */
+#define MALCR_PLBLT_2 		0x00020000
+#define MALCR_PLBLT_3		0x00010000
+#define MALCR_PLBLT_4		0x00008000
+#define MALCR_PLBLT_DEFAULT	0x00078000	/* JSP: Is this a valid default?? */
+#define MALCR_PLBB		0x00004000	/* PLB Burst Deactivation Bit */
+#define MALCR_OPBBL		0x00000080	/* OPB Lock Bit */
+#define MALCR_EOPIE		0x00000004	/* End Of Packet Interrupt Enable */
+#define MALCR_LEA		0x00000002	/* Locked Error Active */
+#define MALCR_MSD		0x00000001	/* MAL Scroll Descriptor Bit */
+/* DCRN_MALESR */
+#define MALESR_EVB		0x80000000	/* Error Valid Bit */
+#define MALESR_CIDRX		0x40000000	/* Channel ID Receive */
+#define MALESR_DE		0x00100000	/* Descriptor Error */
+#define MALESR_OEN		0x00080000	/* OPB Non-Fullword Error */
+#define MALESR_OTE		0x00040000	/* OPB Timeout Error */
+#define MALESR_OSE		0x00020000	/* OPB Slave Error */
+#define MALESR_PEIN		0x00010000	/* PLB Bus Error Indication */
+#define MALESR_DEI		0x00000010	/* Descriptor Error Interrupt */
+#define MALESR_ONEI		0x00000008	/* OPB Non-Fullword Error Interrupt */
+#define MALESR_OTEI		0x00000004	/* OPB Timeout Error Interrupt */
+#define MALESR_OSEI		0x00000002	/* OPB Slace Error Interrupt */
+#define MALESR_PBEI		0x00000001	/* PLB Bus Error Interrupt */
+/* DCRN_MALIER */
+#define MALIER_DE		0x00000010	/* Descriptor Error Interrupt Enable */
+#define MALIER_NE		0x00000008	/* OPB Non-word Transfer Int Enable */
+#define MALIER_TE		0x00000004	/* OPB Time Out Error Interrupt Enable */
+#define MALIER_OPBE		0x00000002	/* OPB Slave Error Interrupt Enable */
+#define MALIER_PLBE		0x00000001	/* PLB Error Interrupt Enable */
+/* DCRN_MALTXEOBISR */
+#define MALOBISR_CH0		0x80000000	/* EOB channel 1 bit */
+#define MALOBISR_CH2		0x40000000	/* EOB channel 2 bit */
+
+#ifdef DCRN_PLB0_BASE
+#define DCRN_PLB0_BESR	(DCRN_PLB0_BASE + 0x0)
+#define DCRN_PLB0_BEAR	(DCRN_PLB0_BASE + 0x2)
+/* doesn't exist on stb03xxx? */
+#define DCRN_PLB0_ACR	(DCRN_PLB0_BASE + 0x3)
+#endif
+
+#ifdef DCRN_PLB1_BASE
+#define DCRN_PLB1_BESR	(DCRN_PLB1_BASE + 0x0)
+#define DCRN_PLB1_BEAR	(DCRN_PLB1_BASE + 0x1)
+/* doesn't exist on stb03xxx? */
+#define DCRN_PLB1_ACR	(DCRN_PLB1_BASE + 0x2)
+#endif
+
+#ifdef DCRN_PLLMR_BASE
+#define DCRN_PLLMR	(DCRN_PLLMR_BASE + 0x0)	/* PL1 Mode */
+#endif
+
+#ifdef DCRN_POB0_BASE
+#define DCRN_POB0_BESR0	(DCRN_POB0_BASE + 0x0)
+#define DCRN_POB0_BEAR	(DCRN_POB0_BASE + 0x2)
+#define DCRN_POB0_BESR1	(DCRN_POB0_BASE + 0x4)
+#endif
+
+#define DCRN_UIC_SR(base)	(base + 0x0)
+#define DCRN_UIC_ER(base)	(base + 0x2)
+#define DCRN_UIC_CR(base)	(base + 0x3)
+#define DCRN_UIC_PR(base)	(base + 0x4)
+#define DCRN_UIC_TR(base)	(base + 0x5)
+#define DCRN_UIC_MSR(base)	(base + 0x6)
+#define DCRN_UIC_VR(base)	(base + 0x7)
+#define DCRN_UIC_VCR(base)	(base + 0x8)
+
+#ifdef DCRN_SDRAM0_BASE
+#define DCRN_SDRAM0_CFGADDR	(DCRN_SDRAM0_BASE + 0x0)	/* Memory Controller Address */
+#define DCRN_SDRAM0_CFGDATA	(DCRN_SDRAM0_BASE + 0x1)	/* Memory Controller Data */
+#endif
+
+#ifdef DCRN_OCM0_BASE
+#define DCRN_OCMISARC	(DCRN_OCM0_BASE + 0x0)	/* OCM Instr Side Addr Range Compare */
+#define DCRN_OCMISCR	(DCRN_OCM0_BASE + 0x1)	/* OCM Instr Side Control */
+#define DCRN_OCMDSARC	(DCRN_OCM0_BASE + 0x2)	/* OCM Data Side Addr Range Compare */
+#define DCRN_OCMDSCR	(DCRN_OCM0_BASE + 0x3)	/* OCM Data Side Control */
+#endif
+
+#endif				/* __ASM_IBM405_H__ */
+#endif				/* __KERNEL__ */
diff -Nru a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h
--- a/include/asm-ppc/pgalloc.h	Fri Oct 11 21:22:50 2002
+++ b/include/asm-ppc/pgalloc.h	Fri Oct 11 21:22:50 2002
@@ -21,9 +21,9 @@
 #define pgd_populate(mm, pmd, pte)      BUG()
 
 #define pmd_populate_kernel(mm, pmd, pte)	\
-		(pmd_val(*(pmd)) = __pa(pte))
+		(pmd_val(*(pmd)) = __pa(pte) | _PMD_PRESENT)
 #define pmd_populate(mm, pmd, pte)	\
-		(pmd_val(*(pmd)) = (page_to_pfn(pte) << PAGE_SHIFT))
+		(pmd_val(*(pmd)) = (page_to_pfn(pte) << PAGE_SHIFT) | _PMD_PRESENT)
 
 extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
 extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
diff -Nru a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
--- a/include/asm-ppc/pgtable.h	Fri Oct 11 21:22:54 2002
+++ b/include/asm-ppc/pgtable.h	Fri Oct 11 21:22:54 2002
@@ -145,8 +145,8 @@
      is cleared in the TLB miss handler before the TLB entry is loaded.
    - All other bits of the PTE are loaded into TLBLO without
      modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
-     software PTE bits.  We actually use use bits 21, 24, 25, 26, and
-     30 respectively for the software bits: ACCESSED, DIRTY, RW, EXEC,
+     software PTE bits.  We actually use use bits 21, 24, 25, and
+     30 respectively for the software bits: ACCESSED, DIRTY, RW, and
      PRESENT.
 */
 
@@ -162,6 +162,13 @@
 #define _PAGE_HWEXEC	0x200	/* hardware: EX permission */
 #define _PAGE_ACCESSED	0x400	/* software: R: page referenced */
 
+#define _PMD_PRESENT	0x400	/* PMD points to page of PTEs */
+#define _PMD_BAD	0x802
+#define _PMD_SIZE	0x0e0	/* size field, != 0 for large-page PMD entry */
+#define _PMD_SIZE_4M	0x0c0
+#define _PMD_SIZE_16M	0x0e0
+#define PMD_PAGE_SIZE(pmdval)	(1024 << (((pmdval) & _PMD_SIZE) >> 4))
+
 #elif defined(CONFIG_8xx)
 /* Definitions for 8xx embedded chips. */
 #define _PAGE_PRESENT	0x0001	/* Page is valid */
@@ -184,9 +191,21 @@
 #define _PAGE_HWWRITE	0x0100	/* h/w write enable: never set in Linux PTE */
 #define _PAGE_USER	0x0800	/* One of the PP bits, the other is USER&~RW */
 
+#define _PMD_PRESENT	0x0001
+#define _PMD_BAD	0x0ff0
 #define _PMD_PAGE_MASK	0x000c
 #define _PMD_PAGE_8M	0x000c
 
+/*
+ * The 8xx TLB miss handler allegedly sets _PAGE_ACCESSED in the PTE
+ * for an address even if _PAGE_PRESENT is not set, as a performance
+ * optimization.  This is a bug if you ever want to use swap unless
+ * _PAGE_ACCESSED is 2, which it isn't, or unless you have 8xx-specific
+ * definitions for __swp_entry etc. below, which would be gross.
+ *  -- paulus
+ */
+#define _PTE_NONE_MASK _PAGE_ACCESSED
+
 #else /* CONFIG_6xx */
 /* Definitions for 60x, 740/750, etc. */
 #define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
@@ -200,21 +219,22 @@
 #define _PAGE_ACCESSED	0x100	/* R: page referenced */
 #define _PAGE_EXEC	0x200	/* software: i-cache coherency required */
 #define _PAGE_RW	0x400	/* software: user write access allowed */
+
+#define _PTE_NONE_MASK	_PAGE_HASHPTE
+
+#define _PMD_PRESENT	0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD	(~PAGE_MASK)
 #endif
 
-/* The non-standard PowerPC MMUs, which includes the 4xx and 8xx (and
- * mabe 603e) have TLB miss handlers that unconditionally set the
- * _PAGE_ACCESSED flag as a performance optimization.  This causes
- * problems for the page_none() macro, just like the HASHPTE flag does
- * for the standard PowerPC MMUs.  Depending upon the MMU configuration,
- * either HASHPTE or ACCESSED will have to be masked to give us a
- * proper pte_none() condition.
+/*
+ * Some bits are only used on some cpu families...
  */
 #ifndef _PAGE_HASHPTE
 #define _PAGE_HASHPTE	0
-#define _PTE_NONE_MASK _PAGE_ACCESSED
-#else
-#define _PTE_NONE_MASK _PAGE_HASHPTE
+#endif
+#ifndef _PTE_NONE_MASK
+#define _PTE_NONE_MASK 0
 #endif
 #ifndef _PAGE_SHARED
 #define _PAGE_SHARED	0
@@ -228,6 +248,13 @@
 #ifndef _PAGE_EXEC
 #define _PAGE_EXEC	0
 #endif
+#ifndef _PMD_PRESENT_MASK
+#define _PMD_PRESENT_MASK	_PMD_PRESENT
+#endif
+#ifndef _PMD_SIZE
+#define _PMD_SIZE	0
+#define PMD_PAGE_SIZE(pmd)	bad_call_to_PMD_PAGE_SIZE()
+#endif
 
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
@@ -237,27 +264,28 @@
  * to have it in the Linux PTE, and in fact the bit could be reused for
  * another purpose.  -- paulus.
  */
-#define _PAGE_BASE	_PAGE_PRESENT | _PAGE_ACCESSED
-#define _PAGE_WRENABLE	_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE
 
-#define _PAGE_KERNEL	_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | _PAGE_HWEXEC
-#define _PAGE_IO	_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED
+#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE)
+#define _PAGE_KERNEL	(_PAGE_BASE | _PAGE_SHARED | _PAGE_WRENABLE)
+
+#ifdef CONFIG_PPC_STD_MMU
+/* On standard PPC MMU, no user access implies kernel read/write access,
+ * so to write-protect kernel memory we must turn on user access */
+#define _PAGE_KERNEL_RO	(_PAGE_BASE | _PAGE_SHARED | _PAGE_USER)
+#else
+#define _PAGE_KERNEL_RO	(_PAGE_BASE | _PAGE_SHARED)
+#endif
 
-#define _PAGE_RAM	_PAGE_KERNEL
+#define _PAGE_IO	(_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define _PAGE_RAM	(_PAGE_KERNEL | _PAGE_HWEXEC)
 
 #if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
 /* We want the debuggers to be able to set breakpoints anywhere, so
  * don't write protect the kernel text */
 #define _PAGE_RAM_TEXT	_PAGE_RAM
 #else
-#ifdef CONFIG_PPC_STD_MMU
-/* On standard PPC MMU, no user access implies kernel read/write
- * access, so to write-protect the kernel text we must turn on user
- * access */
-#define _PAGE_RAM_TEXT	(_PAGE_RAM & ~_PAGE_WRENABLE) | _PAGE_USER
-#else
-#define _PAGE_RAM_TEXT	(_PAGE_RAM & ~_PAGE_WRENABLE)
-#endif
+#define _PAGE_RAM_TEXT	(_PAGE_KERNEL_RO | _PAGE_HWEXEC)
 #endif
 
 #define PAGE_NONE	__pgprot(_PAGE_BASE)
@@ -268,9 +296,7 @@
 #define PAGE_COPY	__pgprot(_PAGE_BASE | _PAGE_USER)
 #define PAGE_COPY_X	__pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
 
-#define PAGE_KERNEL	__pgprot(_PAGE_KERNEL)
-#define PAGE_KERNEL_RO	__pgprot(_PAGE_BASE | _PAGE_SHARED)
-#define PAGE_KERNEL_CI	__pgprot(_PAGE_IO)
+#define PAGE_KERNEL	__pgprot(_PAGE_RAM)
 
 /*
  * The PowerPC can only do execute protection on a segment (256MB) basis,
@@ -297,6 +323,10 @@
 #define __S111	PAGE_SHARED_X
 
 #ifndef __ASSEMBLY__
+/* Make sure we get a link error if PMD_PAGE_SIZE is ever called on a
+ * kernel without large page PMD support */
+extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
+
 /*
  * Conversions between PTE values and page frame numbers.
  */
@@ -321,8 +351,8 @@
 #define pte_clear(ptep)		do { set_pte((ptep), __pte(0)); } while (0)
 
 #define pmd_none(pmd)		(!pmd_val(pmd))
-#define	pmd_bad(pmd)		(0)
-#define	pmd_present(pmd)	(pmd_val(pmd) != 0)
+#define	pmd_bad(pmd)		(pmd_val(pmd) & _PMD_BAD)
+#define	pmd_present(pmd)	(pmd_val(pmd) & _PMD_PRESENT_MASK)
 #define	pmd_clear(pmdp)		do { pmd_val(*(pmdp)) = 0; } while (0)
 
 #ifndef __ASSEMBLY__
diff -Nru a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h
--- a/include/asm-ppc/semaphore.h	Fri Oct 11 21:22:59 2002
+++ b/include/asm-ppc/semaphore.h	Fri Oct 11 21:22:59 2002
@@ -83,6 +83,7 @@
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
 #endif
+	might_sleep();
 
 	/*
 	 * Try to get the semaphore, take the slow path if we fail.
@@ -99,6 +100,7 @@
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
 #endif
+	might_sleep();
 
 	if (atomic_dec_return(&sem->count) < 0)
 		ret = __down_interruptible(sem);
diff -Nru a/include/asm-ppc/sigcontext.h b/include/asm-ppc/sigcontext.h
--- a/include/asm-ppc/sigcontext.h	Fri Oct 11 21:22:50 2002
+++ b/include/asm-ppc/sigcontext.h	Fri Oct 11 21:22:50 2002
@@ -4,7 +4,7 @@
 #include <asm/ptrace.h>
 
 
-struct sigcontext_struct {
+struct sigcontext {
 	unsigned long	_unused[4];
 	int		signal;
 	unsigned long	handler;
diff -Nru a/include/asm-ppc/types.h b/include/asm-ppc/types.h
--- a/include/asm-ppc/types.h	Fri Oct 11 21:23:03 2002
+++ b/include/asm-ppc/types.h	Fri Oct 11 21:23:03 2002
@@ -45,6 +45,11 @@
 typedef u32 dma_addr_t;
 typedef u64 dma64_addr_t;
 
+#ifdef CONFIG_LBD
+typedef u64 sector_t;
+#define HAVE_SECTOR_T
+#endif
+
 #endif /* __KERNEL__ */
 
 /*
diff -Nru a/include/asm-ppc/ucontext.h b/include/asm-ppc/ucontext.h
--- a/include/asm-ppc/ucontext.h	Fri Oct 11 21:23:00 2002
+++ b/include/asm-ppc/ucontext.h	Fri Oct 11 21:23:00 2002
@@ -7,7 +7,7 @@
 	unsigned long	  uc_flags;
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
-	struct sigcontext_struct uc_mcontext;
+	struct sigcontext uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
 };
 
diff -Nru a/include/asm-s390/debug.h b/include/asm-s390/debug.h
--- a/include/asm-s390/debug.h	Fri Oct 11 21:22:50 2002
+++ b/include/asm-s390/debug.h	Fri Oct 11 21:22:50 2002
@@ -261,7 +261,7 @@
 void *b;
 #define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b)
 #define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x)
-#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b)
+#define get_zeroed_page(x...) (PRINT_INFO(" gfp %p\n",b=get_zeroed_page(x)),b)
 #define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b)
 #endif				/* DEBUG_MALLOC */
 
diff -Nru a/include/asm-s390x/debug.h b/include/asm-s390x/debug.h
--- a/include/asm-s390x/debug.h	Fri Oct 11 21:22:59 2002
+++ b/include/asm-s390x/debug.h	Fri Oct 11 21:22:59 2002
@@ -261,7 +261,7 @@
 void *b;
 #define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b)
 #define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x)
-#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b)
+#define get_zeroed_page(x...) (PRINT_INFO(" gfp %p\n",b=get_zeroed_page(x)),b)
 #define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b)
 #endif				/* DEBUG_MALLOC */
 
diff -Nru a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
--- a/include/asm-um/pgtable.h	Fri Oct 11 21:23:06 2002
+++ b/include/asm-um/pgtable.h	Fri Oct 11 21:23:06 2002
@@ -233,11 +233,25 @@
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-static inline int pte_read(pte_t pte)	{ return pte_val(pte) & _PAGE_USER; }
-static inline int pte_exec(pte_t pte)	{ return pte_val(pte) & _PAGE_USER; }
+static inline int pte_read(pte_t pte)
+{ 
+	return((pte_val(pte) & _PAGE_USER) && 
+	       !(pte_val(pte) & _PAGE_PROTNONE));
+}
+
+static inline int pte_exec(pte_t pte){
+	return((pte_val(pte) & _PAGE_USER) &&
+	       !(pte_val(pte) & _PAGE_PROTNONE));
+}
+
+static inline int pte_write(pte_t pte)
+{
+	return((pte_val(pte) & _PAGE_RW) &&
+	       !(pte_val(pte) & _PAGE_PROTNONE));
+}
+
 static inline int pte_dirty(pte_t pte)	{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)	{ return pte_val(pte) & _PAGE_ACCESSED; }
-static inline int pte_write(pte_t pte)	{ return pte_val(pte) & _PAGE_RW; }
 static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
 static inline int pte_newprot(pte_t pte)
 { 
diff -Nru a/include/asm-um/topology.h b/include/asm-um/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/topology.h	Fri Oct 11 21:23:07 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_UM_TOPOLOGY_H
+#define _ASM_UM_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif
diff -Nru a/include/asm-um/xor.h b/include/asm-um/xor.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/xor.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_XOR_H
+#define __UM_XOR_H
+
+#include "asm-generic/xor.h"
+
+#endif
diff -Nru a/include/linux/adfs_fs.h b/include/linux/adfs_fs.h
--- a/include/linux/adfs_fs.h	Fri Oct 11 21:23:02 2002
+++ b/include/linux/adfs_fs.h	Fri Oct 11 21:23:02 2002
@@ -63,7 +63,7 @@
 
 static inline struct adfs_sb_info *ADFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct adfs_inode_info *ADFS_I(struct inode *inode)
diff -Nru a/include/linux/affs_fs_sb.h b/include/linux/affs_fs_sb.h
--- a/include/linux/affs_fs_sb.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/affs_fs_sb.h	Fri Oct 11 21:22:54 2002
@@ -52,7 +52,7 @@
 /* short cut to get to the affs specific sb data */
 static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 #endif
diff -Nru a/include/linux/agp_backend.h b/include/linux/agp_backend.h
--- a/include/linux/agp_backend.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/agp_backend.h	Fri Oct 11 21:23:03 2002
@@ -75,6 +75,7 @@
 	ALI_M1644,
 	ALI_M1647,
 	ALI_M1651,
+	ALI_M1671,
 	ALI_GENERIC,
 	SVWRKS_HE,
 	SVWRKS_LE,
diff -Nru a/include/linux/aio.h b/include/linux/aio.h
--- a/include/linux/aio.h	Fri Oct 11 21:22:51 2002
+++ b/include/linux/aio.h	Fri Oct 11 21:22:51 2002
@@ -2,10 +2,11 @@
 #define __LINUX__AIO_H
 
 #include <linux/list.h>
-#include <asm/atomic.h>
-
+#include <linux/workqueue.h>
 #include <linux/aio_abi.h>
 
+#include <asm/atomic.h>
+
 #define AIO_MAXSEGS		4
 #define AIO_KIOGRP_NR_ATOMIC	8
 
@@ -22,28 +23,54 @@
 
 #define KIOCB_SYNC_KEY		(~0U)
 
-#define KIOCB_PRIVATE_SIZE	(16 * sizeof(long))
+#define KIOCB_PRIVATE_SIZE	(24 * sizeof(long))
+
+/* ki_flags bits */
+#define KIF_LOCKED		0
+#define KIF_KICKED		1
+#define KIF_CANCELLED		2
+
+#define kiocbTryLock(iocb)	test_and_set_bit(KIF_LOCKED, &(iocb)->ki_flags)
+#define kiocbTryKick(iocb)	test_and_set_bit(KIF_KICKED, &(iocb)->ki_flags)
+
+#define kiocbSetLocked(iocb)	set_bit(KIF_LOCKED, &(iocb)->ki_flags)
+#define kiocbSetKicked(iocb)	set_bit(KIF_KICKED, &(iocb)->ki_flags)
+#define kiocbSetCancelled(iocb)	set_bit(KIF_CANCELLED, &(iocb)->ki_flags)
+
+#define kiocbClearLocked(iocb)	set_bit(KIF_LOCKED, &(iocb)->ki_flags)
+#define kiocbClearKicked(iocb)	set_bit(KIF_KICKED, &(iocb)->ki_flags)
+#define kiocbClearCancelled(iocb)	set_bit(KIF_CANCELLED, &(iocb)->ki_flags)
+
+#define kiocbIsLocked(iocb)	test_bit(0, &(iocb)->ki_flags)
+#define kiocbIsKicked(iocb)	test_bit(1, &(iocb)->ki_flags)
+#define kiocbIsCancelled(iocb)	test_bit(2, &(iocb)->ki_flags)
 
 struct kiocb {
+	struct list_head	ki_run_list;
+	long			ki_flags;
 	int			ki_users;
 	unsigned		ki_key;		/* id of this request */
 
 	struct file		*ki_filp;
 	struct kioctx		*ki_ctx;	/* may be NULL for sync ops */
 	int			(*ki_cancel)(struct kiocb *, struct io_event *);
+	long			(*ki_retry)(struct kiocb *);
 
-	struct list_head	ki_list;
+	struct list_head	ki_list;	/* the aio core uses this
+						 * for cancellation */
 
-	void			*ki_data;	/* for use by the the file */
 	void			*ki_user_obj;	/* pointer to userland's iocb */
 	__u64			ki_user_data;	/* user's data for completion */
+	loff_t			ki_pos;
 
-	long			private[KIOCB_PRIVATE_SIZE/sizeof(long)];
+	char			private[KIOCB_PRIVATE_SIZE];
 };
 
+#define is_sync_kiocb(iocb)	((iocb)->ki_key == KIOCB_SYNC_KEY)
 #define init_sync_kiocb(x, filp)			\
 	do {						\
 		struct task_struct *tsk = current;	\
+		(x)->ki_flags = 0;			\
 		(x)->ki_users = 1;			\
 		(x)->ki_key = KIOCB_SYNC_KEY;		\
 		(x)->ki_filp = (filp);			\
@@ -101,10 +128,13 @@
 
 	int			reqs_active;
 	struct list_head	active_reqs;	/* used for cancellation */
+	struct list_head	run_list;	/* used for kicked reqs */
 
 	unsigned		max_reqs;
 
 	struct aio_ring_info	ring_info;
+
+	struct work_struct	wq;
 };
 
 /* prototypes */
@@ -112,6 +142,7 @@
 
 extern ssize_t FASTCALL(wait_on_sync_kiocb(struct kiocb *iocb));
 extern int FASTCALL(aio_put_req(struct kiocb *iocb));
+extern void FASTCALL(kick_iocb(struct kiocb *iocb));
 extern int FASTCALL(aio_complete(struct kiocb *iocb, long res, long res2));
 extern void FASTCALL(__put_ioctx(struct kioctx *ctx));
 struct mm_struct;
diff -Nru a/include/linux/atalk.h b/include/linux/atalk.h
--- a/include/linux/atalk.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/atalk.h	Fri Oct 11 21:23:03 2002
@@ -199,13 +199,13 @@
 #define at_sk(__sk) ((struct atalk_sock *)(__sk)->protinfo)
 
 extern struct sock *atalk_sockets;
-extern spinlock_t atalk_sockets_lock;
+extern rwlock_t atalk_sockets_lock;
 
 extern struct atalk_route *atalk_routes;
 extern rwlock_t atalk_routes_lock;
 
 extern struct atalk_iface *atalk_interfaces;
-extern spinlock_t atalk_interfaces_lock;
+extern rwlock_t atalk_interfaces_lock;
 
 extern struct atalk_route atrtr_default;
 
diff -Nru a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/bio.h	Fri Oct 11 21:23:03 2002
@@ -81,8 +81,7 @@
 	unsigned short		bi_hw_segments;
 
 	unsigned int		bi_size;	/* residual I/O count */
-	unsigned int		bi_max;		/* max bvl_vecs we can hold,
-						   used as index into pool */
+	unsigned int		bi_max_vecs;	/* max bvl_vecs we can hold */
 
 	struct bio_vec		*bi_io_vec;	/* the actual vec list */
 
@@ -103,6 +102,14 @@
 #define BIO_SEG_VALID	3	/* nr_hw_seg valid */
 #define BIO_CLONED	4	/* doesn't own data */
 #define bio_flagged(bio, flag)	((bio)->bi_flags & (1 << (flag)))
+
+/*
+ * top 4 bits of bio flags indicate the pool this bio came from
+ */
+#define BIO_POOL_BITS		(4)
+#define BIO_POOL_OFFSET		(BITS_PER_LONG - BIO_POOL_BITS)
+#define BIO_POOL_MASK		(1UL << BIO_POOL_OFFSET)
+#define BIO_POOL_IDX(bio)	((bio)->bi_flags >> BIO_POOL_OFFSET)	
 
 /*
  * bio bi_rw flags
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/blkdev.h	Fri Oct 11 21:22:54 2002
@@ -7,6 +7,7 @@
 #include <linux/list.h>
 #include <linux/pagemap.h>
 #include <linux/backing-dev.h>
+#include <linux/wait.h>
 
 #include <asm/scatterlist.h>
 
@@ -36,7 +37,7 @@
 	int errors;
 	sector_t sector;
 	unsigned long nr_sectors;
-	unsigned long hard_sector;	/* the hard_* are block layer
+	sector_t hard_sector;		/* the hard_* are block layer
 					 * internals, no driver should
 					 * touch them
 					 */
@@ -393,12 +394,28 @@
 
 typedef struct {struct page *v;} Sector;
 
-unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *);
+unsigned char *read_dev_sector(struct block_device *, sector_t, Sector *);
 
 static inline void put_dev_sector(Sector p)
 {
 	page_cache_release(p.v);
 }
+
+#ifdef CONFIG_LBD
+# include <asm/div64.h>
+# define sector_div(a, b) do_div(a, b)
+#else
+# define sector_div(n, b)( \
+{ \
+	int _res; \
+	_res = (n) % (b); \
+	(n) /= (b); \
+	_res; \
+} \
+)
+#endif 
+ 
+
 
 extern atomic_t nr_iowait_tasks;
 void io_schedule(void);
diff -Nru a/include/linux/coda_fs_i.h b/include/linux/coda_fs_i.h
--- a/include/linux/coda_fs_i.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/coda_fs_i.h	Fri Oct 11 21:23:03 2002
@@ -20,12 +20,24 @@
         struct ViceFid     c_fid;	/* Coda identifier */
         u_short	           c_flags;     /* flags (see below) */
 	struct list_head   c_cilist;    /* list of all coda inodes */
-	struct file	  *c_container; /* container file for this cnode */
-	unsigned int       c_contcount; /* refcount for container file */
+	unsigned int	   c_mapcount;  /* nr of times this inode is mapped */
         struct coda_cred   c_cached_cred; /* credentials of cached perms */
         unsigned int       c_cached_perm; /* cached access permissions */
 	struct inode	   vfs_inode;
 };
+
+/*
+ * coda fs file private data
+ */
+#define CODA_MAGIC 0xC0DAC0DA
+struct coda_file_info {
+	int		   cfi_magic;	  /* magic number */
+	struct file	  *cfi_container; /* container file for this cnode */
+	unsigned int	   cfi_mapcount;  /* nr of times this file is mapped */
+	struct coda_cred   cfi_cred;      /* credentials of opener */
+};
+
+#define CODA_FTOC(file) ((struct coda_file_info *)((file)->private_data))
 
 /* flags */
 #define C_VATTR       0x1   /* Validity of vattr in inode */
diff -Nru a/include/linux/coda_linux.h b/include/linux/coda_linux.h
--- a/include/linux/coda_linux.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/coda_linux.h	Fri Oct 11 21:22:54 2002
@@ -21,6 +21,7 @@
 #include <linux/wait.h>		
 #include <linux/types.h>
 #include <linux/fs.h>
+#include <linux/coda_fs_i.h>
 
 /* operations */
 extern struct inode_operations coda_dir_inode_operations;
@@ -45,7 +46,6 @@
 int coda_isnullfid(ViceFid *fid);
 
 /* global variables */
-extern int coda_access_cache;
 extern int coda_fake_statfs;
 
 /* this file:  heloers */
@@ -53,7 +53,6 @@
 static __inline__ char *coda_i2s(struct inode *);
 static __inline__ void coda_flag_inode(struct inode *, int flag);
 char *coda_f2s(ViceFid *f);
-char *coda_f2s2(ViceFid *f);
 int coda_isroot(struct inode *i);
 int coda_iscontrol(const char *name, size_t length);
 
diff -Nru a/include/linux/coda_proc.h b/include/linux/coda_proc.h
--- a/include/linux/coda_proc.h	Fri Oct 11 21:22:51 2002
+++ b/include/linux/coda_proc.h	Fri Oct 11 21:22:51 2002
@@ -14,7 +14,6 @@
 
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
-void coda_upcall_stats(int opcode, unsigned long jiffies);
 
 #include <linux/sysctl.h>
 #include <linux/coda_fs_i.h>
@@ -23,13 +22,11 @@
 /* these four files are presented to show the result of the statistics:
  *
  *	/proc/fs/coda/vfs_stats
- *		      upcall_stats
  *		      cache_inv_stats
  *
  * these four files are presented to reset the statistics to 0:
  *
  *	/proc/sys/coda/vfs_stats
- *		       upcall_stats
  *		       cache_inv_stats
  */
 
@@ -61,13 +58,6 @@
 	int readlink;
 };
 
-struct coda_upcall_stats_entry 
-{
-  int count;
-  unsigned long time_sum;
-  unsigned long time_squared_sum;
-};
-
 /* cache invalidation statistics */
 struct coda_cache_inv_stats
 {
@@ -83,31 +73,16 @@
 /* these global variables hold the actual statistics data */
 extern struct coda_vfs_stats		coda_vfs_stat;
 extern struct coda_cache_inv_stats	coda_cache_inv_stat;
-extern int				coda_upcall_timestamping;
 
 /* reset statistics to 0 */
 void reset_coda_vfs_stats( void );
-void reset_coda_upcall_stats( void );
 void reset_coda_cache_inv_stats( void );
 
-/* some utitlities to make it easier for you to do statistics for time */
-void do_time_stats( struct coda_upcall_stats_entry * pentry, 
-		    unsigned long jiffy );
-/*
-double get_time_average( const struct coda_upcall_stats_entry * pentry );
-double get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
-*/
-unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry );
-unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
-
 /* like coda_dointvec, these functions are to be registered in the ctl_table
  * data structure for /proc/sys/... files 
  */
 int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
 			     void * buffer, size_t * lenp );
-int do_reset_coda_upcall_stats( ctl_table * table, int write, 
-				struct file * filp, void * buffer, 
-				size_t * lenp );
 int do_reset_coda_cache_inv_stats( ctl_table * table, int write, 
 				   struct file * filp, void * buffer, 
 				   size_t * lenp );
@@ -115,8 +90,6 @@
 /* these functions are called to form the content of /proc/fs/coda/... files */
 int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
 			     int length);
-int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
-				int length);
 int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
 				   int length);
 
diff -Nru a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
--- a/include/linux/coda_psdev.h	Fri Oct 11 21:22:58 2002
+++ b/include/linux/coda_psdev.h	Fri Oct 11 21:22:58 2002
@@ -26,7 +26,7 @@
 
 static inline struct coda_sb_info *coda_sbp(struct super_block *sb)
 {
-    return ((struct coda_sb_info *)((sb)->u.generic_sbp));
+    return ((struct coda_sb_info *)((sb)->s_fs_info));
 }
 
 
@@ -98,27 +98,7 @@
 /*
  * Statistics
  */
-struct coda_upcallstats {
-	int	ncalls;			/* client requests */
-	int	nbadcalls;		/* upcall failures */
-	int	reqs[CODA_NCALLS];	/* count of each request */
-} ;
 
-extern struct coda_upcallstats coda_callstats;
 extern struct venus_comm coda_comms[];
-
-static inline void clstats(int opcode)
-{
-    coda_callstats.ncalls++;
-    if ( (0 <= opcode) && (opcode <= CODA_NCALLS) )
-	coda_callstats.reqs[opcode]++;
-    else
-	printk("clstats called with bad opcode %d\n", opcode); 
-}
-
-static inline void badclstats(void)
-{
-    coda_callstats.nbadcalls++;
-}
 
 #endif
diff -Nru a/include/linux/cramfs_fs_sb.h b/include/linux/cramfs_fs_sb.h
--- a/include/linux/cramfs_fs_sb.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/cramfs_fs_sb.h	Fri Oct 11 21:23:03 2002
@@ -14,7 +14,7 @@
 
 static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 #endif
diff -Nru a/include/linux/dcache.h b/include/linux/dcache.h
--- a/include/linux/dcache.h	Fri Oct 11 21:23:05 2002
+++ b/include/linux/dcache.h	Fri Oct 11 21:23:05 2002
@@ -156,8 +156,7 @@
 static __inline__ void d_drop(struct dentry * dentry)
 {
 	spin_lock(&dcache_lock);
-	list_del(&dentry->d_hash);
-	INIT_LIST_HEAD(&dentry->d_hash);
+	list_del_init(&dentry->d_hash);
 	spin_unlock(&dcache_lock);
 }
 
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/device.h	Fri Oct 11 21:23:03 2002
@@ -289,6 +289,7 @@
 	void		*platform_data;	/* Platform specific data (e.g. ACPI,
 					   BIOS data relevant to device) */
 
+	u32		present;
 	u32		current_state;  /* Current operating state. In
 					   ACPI-speak, this is D0-D3, D0
 					   being fully functional, and D3
@@ -327,7 +328,7 @@
  * High level routines for use by the bus drivers
  */
 extern int device_register(struct device * dev);
-
+extern void device_unregister(struct device * dev);
 
 /* driverfs interface for exporting device attributes */
 
@@ -420,5 +421,24 @@
 extern int device_suspend(u32 state, u32 level);
 extern void device_resume(u32 level);
 extern void device_shutdown(void);
+
+/* debugging and troubleshooting/diagnostic helpers. */
+#ifdef DEBUG
+#define dev_dbg(dev, format, arg...)		\
+	printk (KERN_DEBUG "%s %s: " format ,	\
+		dev.driver->name , dev.bus_id , ## arg)
+#else
+#define dev_dbg(dev, format, arg...) do {} while (0)
+#endif
+
+#define dev_err(dev, format, arg...)		\
+	printk (KERN_ERR "%s %s: " format ,	\
+		dev.driver->name , dev.bus_id , ## arg)
+#define dev_info(dev, format, arg...)		\
+	printk (KERN_INFO "%s %s: " format ,	\
+		dev.driver->name , dev.bus_id , ## arg)
+#define dev_warn(dev, format, arg...)		\
+	printk (KERN_WARN "%s %s: " format ,	\
+		dev.driver->name , dev.bus_id , ## arg)
 
 #endif /* _DEVICE_H_ */
diff -Nru a/include/linux/efs_fs.h b/include/linux/efs_fs.h
--- a/include/linux/efs_fs.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/efs_fs.h	Fri Oct 11 21:22:55 2002
@@ -46,7 +46,7 @@
 
 static inline struct efs_sb_info *SUPER_INFO(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 extern struct inode_operations efs_dir_inode_operations;
diff -Nru a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
--- a/include/linux/ext2_fs.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/ext2_fs.h	Fri Oct 11 21:22:54 2002
@@ -74,7 +74,7 @@
 #ifdef __KERNEL__
 static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 #else
 /* Assume that user mode programs are passing in an ext2fs superblock, not
diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
--- a/include/linux/ext3_fs.h	Fri Oct 11 21:22:51 2002
+++ b/include/linux/ext3_fs.h	Fri Oct 11 21:22:51 2002
@@ -41,6 +41,11 @@
 #define EXT3FS_VERSION		"2.4-0.9.16"
 
 /*
+ * Always enable hashed directories
+ */
+#define CONFIG_EXT3_INDEX
+
+/*
  * Debug code
  */
 #ifdef EXT3FS_DEBUG
@@ -440,14 +445,17 @@
 /*E0*/	__u32	s_journal_inum;		/* inode number of journal file */
 	__u32	s_journal_dev;		/* device number of journal file */
 	__u32	s_last_orphan;		/* start of list of inodes to delete */
-
-/*EC*/	__u32	s_reserved[197];	/* Padding to the end of the block */
+	__u32	s_hash_seed[4];		/* HTREE hash seed */
+	__u8	s_def_hash_version;	/* Default hash version to use */
+	__u8	s_reserved_char_pad;
+	__u16	s_reserved_word_pad;
+	__u32	s_reserved[192];	/* Padding to the end of the block */
 };
 
 #ifdef __KERNEL__
 static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
 {
@@ -584,9 +592,46 @@
 #define EXT3_DIR_ROUND			(EXT3_DIR_PAD - 1)
 #define EXT3_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT3_DIR_ROUND) & \
 					 ~EXT3_DIR_ROUND)
+/*
+ * Hash Tree Directory indexing
+ * (c) Daniel Phillips, 2001
+ */
+
+#ifdef CONFIG_EXT3_INDEX
+  #define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \
+					      EXT3_FEATURE_COMPAT_DIR_INDEX) && \
+		      (EXT3_I(dir)->i_flags & EXT3_INDEX_FL))
+#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX)
+#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
+#else
+  #define is_dx(dir) 0
+#define EXT3_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT3_LINK_MAX)
+#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2)
+#endif
+
+/* Legal values for the dx_root hash_version field: */
+
+#define DX_HASH_LEGACY		0
+#define DX_HASH_HALF_MD4	1
+#define DX_HASH_TEA		2
+
+/* hash info structure used by the directory hash */
+struct dx_hash_info
+{
+	u32		hash;
+	u32		minor_hash;
+	int		hash_version;
+	u32		*seed;
+};
 
 #ifdef __KERNEL__
 /*
+ * Control parameters used by ext3_htree_next_block
+ */
+#define HASH_NB_ALWAYS		1
+
+
+/*
  * Describe an inode's exact location on disk and in memory
  */
 struct ext3_iloc
@@ -596,6 +641,27 @@
 	unsigned long block_group;
 };
 
+
+/*
+ * This structure is stuffed into the struct file's private_data field
+ * for directories.  It is where we put information so that we can do
+ * readdir operations in hash tree order.
+ */
+struct dir_private_info {
+	struct rb_root	root;
+	struct rb_node	*curr_node;
+	struct fname	*extra_fname;
+	loff_t		last_pos;
+	__u32		curr_hash;
+	__u32		curr_minor_hash;
+	__u32		next_hash;
+};
+
+/*
+ * Special error return code only used by dx_probe() and its callers.
+ */
+#define ERR_BAD_DX_DIR	-75000
+
 /*
  * Function prototypes
  */
@@ -623,11 +689,20 @@
 
 /* dir.c */
 extern int ext3_check_dir_entry(const char *, struct inode *,
-				struct ext3_dir_entry_2 *, struct buffer_head *,
-				unsigned long);
+				struct ext3_dir_entry_2 *,
+				struct buffer_head *, unsigned long);
+extern void ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
+				    __u32 minor_hash,
+				    struct ext3_dir_entry_2 *dirent);
+extern void ext3_htree_free_dir_info(struct dir_private_info *p);
+
 /* fsync.c */
 extern int ext3_sync_file (struct file *, struct dentry *, int);
 
+/* hash.c */
+extern int ext3fs_dirhash(const char *name, int len, struct
+			  dx_hash_info *hinfo);
+
 /* ialloc.c */
 extern struct inode * ext3_new_inode (handle_t *, struct inode *, int);
 extern void ext3_free_inode (handle_t *, struct inode *);
@@ -636,6 +711,7 @@
 extern void ext3_check_inodes_bitmap (struct super_block *);
 extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
 
+
 /* inode.c */
 extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
@@ -659,6 +735,8 @@
 /* namei.c */
 extern int ext3_orphan_add(handle_t *, struct inode *);
 extern int ext3_orphan_del(handle_t *, struct inode *);
+extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+				__u32 start_minor_hash, __u32 *next_hash);
 
 /* super.c */
 extern void ext3_error (struct super_block *, const char *, const char *, ...)
diff -Nru a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h
--- a/include/linux/ext3_fs_sb.h	Fri Oct 11 21:23:04 2002
+++ b/include/linux/ext3_fs_sb.h	Fri Oct 11 21:23:04 2002
@@ -48,6 +48,8 @@
 	int s_inode_size;
 	int s_first_ino;
 	u32 s_next_generation;
+	u32 s_hash_seed[4];
+	int s_def_hash_version;
 
 	/* Journaling */
 	struct inode * s_journal_inode;
diff -Nru a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
--- a/include/linux/ext3_jbd.h	Fri Oct 11 21:22:53 2002
+++ b/include/linux/ext3_jbd.h	Fri Oct 11 21:22:53 2002
@@ -63,6 +63,8 @@
 
 #define EXT3_RESERVE_TRANS_BLOCKS	12
 
+#define EXT3_INDEX_EXTRA_TRANS_BLOCKS	8
+
 int
 ext3_mark_iloc_dirty(handle_t *handle, 
 		     struct inode *inode,
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/fs.h	Fri Oct 11 21:22:55 2002
@@ -305,7 +305,7 @@
 	int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
 	int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
 	/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
-	int (*bmap)(struct address_space *, long);
+	sector_t (*bmap)(struct address_space *, sector_t);
 	int (*invalidatepage) (struct page *, unsigned long);
 	int (*releasepage) (struct page *, int);
 	int (*direct_IO)(int, struct file *, const struct iovec *iov,
@@ -356,7 +356,7 @@
 	int			bd_holders;
 	struct block_device *	bd_contains;
 	unsigned		bd_block_size;
-	unsigned long		bd_offset;
+	sector_t		bd_offset;
 	unsigned		bd_part_count;
 	int			bd_invalidated;
 };
@@ -667,9 +667,8 @@
 
 	char s_id[32];				/* Informational name */
 
-	union {
-		void			*generic_sbp;
-	} u;
+	void 			*s_fs_info;	/* Filesystem private info */
+
 	/*
 	 * The next field is for VFS *only*. No filesystems have any business
 	 * even looking at it. You had been warned.
@@ -747,7 +746,7 @@
 	ssize_t (*read) (struct file *, char *, size_t, loff_t *);
 	ssize_t (*aio_read) (struct kiocb *, char *, size_t, loff_t);
 	ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
-	ssize_t (*aio_write) (struct kiocb *, char *, size_t, loff_t);
+	ssize_t (*aio_write) (struct kiocb *, const char *, size_t, loff_t);
 	int (*readdir) (struct file *, void *, filldir_t);
 	unsigned int (*poll) (struct file *, struct poll_table_struct *);
 	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
@@ -1142,7 +1141,7 @@
 extern int filemap_fdatawrite(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
 extern void sync_supers(void);
-extern int bmap(struct inode *, int);
+extern sector_t bmap(struct inode *, sector_t);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
 extern int vfs_permission(struct inode *, int);
@@ -1199,6 +1198,10 @@
 extern int inode_needs_sync(struct inode *inode);
 extern void generic_delete_inode(struct inode *inode);
 
+extern struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
+		int (*test)(struct inode *, void *), void *data);
+extern struct inode *ilookup(struct super_block *sb, unsigned long ino);
+
 extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *);
 extern struct inode * iget_locked(struct super_block *, unsigned long);
 extern void unlock_new_inode(struct inode *);
@@ -1239,6 +1242,10 @@
 extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
+extern ssize_t generic_file_aio_read(struct kiocb *, char *, size_t, loff_t);
+extern ssize_t generic_file_aio_write(struct kiocb *, const char *, size_t, loff_t);
+extern ssize_t do_sync_read(struct file *filp, char *buf, size_t len, loff_t *ppos);
+extern ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *ppos);
 ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
 				unsigned long nr_segs, loff_t *ppos);
 extern ssize_t generic_file_sendfile(struct file *, struct file *, loff_t *, size_t);
@@ -1286,6 +1293,12 @@
 extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
 extern int dcache_readdir(struct file *, void *, filldir_t);
 extern int simple_statfs(struct super_block *, struct statfs *);
+extern int simple_link(struct dentry *, struct inode *, struct dentry *);
+extern int simple_unlink(struct inode *, struct dentry *);
+extern int simple_rmdir(struct inode *, struct dentry *);
+extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int simple_sync_file(struct file *, struct dentry *, int);
+extern int simple_empty(struct dentry *);
 extern struct dentry *simple_lookup(struct inode *, struct dentry *);
 extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
 extern struct file_operations simple_dir_operations;
diff -Nru a/include/linux/gameport.h b/include/linux/gameport.h
--- a/include/linux/gameport.h	Fri Oct 11 21:22:56 2002
+++ b/include/linux/gameport.h	Fri Oct 11 21:22:56 2002
@@ -2,33 +2,16 @@
 #define _GAMEPORT_H
 
 /*
- * $Id: gameport.h,v 1.20 2002/01/03 08:55:05 vojtech Exp $
+ *  Copyright (c) 1999-2002 Vojtech Pavlik
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #include <asm/io.h>
 #include <linux/input.h>
+#include <linux/list.h>
 
 struct gameport;
 
@@ -53,7 +36,8 @@
 	void (*close)(struct gameport *);
 
 	struct gameport_dev *dev;
-	struct gameport *next;
+
+	struct list_head node;
 };
 
 struct gameport_dev {
@@ -64,7 +48,7 @@
 	void (*connect)(struct gameport *, struct gameport_dev *dev);
 	void (*disconnect)(struct gameport *);
 
-	struct gameport_dev *next;
+	struct list_head node;
 };
 
 int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode);
diff -Nru a/include/linux/genhd.h b/include/linux/genhd.h
--- a/include/linux/genhd.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/genhd.h	Fri Oct 11 21:22:54 2002
@@ -59,8 +59,8 @@
 #  include <linux/devfs_fs_kernel.h>
 
 struct hd_struct {
-	unsigned long start_sect;
-	unsigned long nr_sects;
+	sector_t start_sect;
+	sector_t nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
 	struct device hd_driverfs_dev;  /* support driverfs hiearchy     */
 };
@@ -95,7 +95,7 @@
 extern void del_gendisk(struct gendisk *gp);
 extern void unlink_gendisk(struct gendisk *gp);
 extern struct gendisk *get_gendisk(dev_t dev, int *part);
-static inline unsigned long get_start_sect(struct block_device *bdev)
+static inline sector_t get_start_sect(struct block_device *bdev)
 {
 	return bdev->bd_offset;
 }
diff -Nru a/include/linux/gfp.h b/include/linux/gfp.h
--- a/include/linux/gfp.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/gfp.h	Fri Oct 11 21:22:55 2002
@@ -38,8 +38,6 @@
  * can allocate highmem pages, the *get*page*() variants return
  * virtual kernel addresses to the allocated page(s).
  */
-extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, struct zonelist *zonelist));
-extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order);
 
 /*
  * We get the zone list from the current node and the gfp_mask.
@@ -48,14 +46,23 @@
  * For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets
  * optimized to &contig_page_data at compile-time.
  */
-static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
+extern struct page * FASTCALL(__alloc_pages(unsigned int, unsigned int, struct zonelist *));
+static inline struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order)
 {
-	pg_data_t *pgdat = NODE_DATA(numa_node_id());
+	struct pglist_data *pgdat = NODE_DATA(nid);
 	unsigned int idx = (gfp_mask & GFP_ZONEMASK);
 
 	if (unlikely(order >= MAX_ORDER))
 		return NULL;
+	return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + idx);
+}
+static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
+{
+	struct pglist_data *pgdat = NODE_DATA(numa_node_id());
+	unsigned int idx = (gfp_mask & GFP_ZONEMASK);
 
+	if (unlikely(order >= MAX_ORDER))
+		return NULL;
 	return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + idx);
 }
 
@@ -69,11 +76,6 @@
 
 #define __get_dma_pages(gfp_mask, order) \
 		__get_free_pages((gfp_mask) | GFP_DMA,(order))
-
-/*
- * The old interface name will be removed in 2.5:
- */
-#define get_free_page get_zeroed_page
 
 /*
  * There is only one 'core' page-freeing function.
diff -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h
--- a/include/linux/hdreg.h	Fri Oct 11 21:22:57 2002
+++ b/include/linux/hdreg.h	Fri Oct 11 21:22:57 2002
@@ -8,6 +8,8 @@
 
 /* ide.c has its own port definitions in "ide.h" */
 
+#define HD_IRQ		14
+
 /* Hd controller regs. Ref: IBM AT Bios-listing */
 #define HD_DATA		0x1f0		/* _CTL when writing */
 #define HD_ERROR	0x1f1		/* see err-bits */
diff -Nru a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h
--- a/include/linux/hfs_fs.h	Fri Oct 11 21:23:02 2002
+++ b/include/linux/hfs_fs.h	Fri Oct 11 21:23:02 2002
@@ -327,7 +327,7 @@
 
 static inline struct hfs_sb_info *HFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline void hfs_nameout(struct inode *dir, struct hfs_name *out,
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/ide.h	Fri Oct 11 21:22:55 2002
@@ -213,14 +213,6 @@
 #define PRD_ENTRIES     (PAGE_SIZE / (2 * PRD_BYTES))
 
 /*
- * sector count bits
- */
-#define NSEC_CD			0x01
-#define NSEC_IO			0x02
-#define NSEC_REL		0x04
-
-
-/*
  * Our Physical Region Descriptor (PRD) table should be large enough
  * to handle the biggest I/O request we are likely to see.  Since requests
  * can have no more than 256 sectors, and since the typical blocksize is
@@ -689,6 +681,15 @@
 	} b;
 } atapi_select_t;
 
+/*
+ * Status returned from various ide_ functions
+ */
+typedef enum {
+	ide_stopped,	/* no drive operation was started */
+	ide_started,	/* a drive operation was started, handler was set */
+	ide_released,	/* as ide_started, but bus also released */
+} ide_startstop_t;
+
 struct ide_driver_s;
 struct ide_settings_s;
 
@@ -746,6 +747,7 @@
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
 	unsigned blocked        : 1;	/* 1=powermanagment told us not to do anything, so sleep nicely */
+	unsigned queue_setup	: 1;
 	unsigned addressing;		/*      : 3;
 					 *  0=28-bit
 					 *  1=48-bit
@@ -775,6 +777,7 @@
 	u8	sect;		/* "real" sectors per track */
 	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
 	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+	u8	queue_depth;	/* max queue depth */
 
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
@@ -791,6 +794,7 @@
 	int		lun;		/* logical unit */
 	int		crc_count;	/* crc counter to reduce drive speed */
 	struct list_head list;
+	struct device	gendev;
 	struct gendisk *disk;
 } ide_drive_t;
 
@@ -822,6 +826,12 @@
 	int (*ide_dma_retune)(ide_drive_t *drive);
 	int (*ide_dma_lostirq)(ide_drive_t *drive);
 	int (*ide_dma_timeout)(ide_drive_t *drive);
+	/* dma queued operations */
+	int (*ide_dma_queued_on)(ide_drive_t *drive);
+	int (*ide_dma_queued_off)(ide_drive_t *drive);
+	ide_startstop_t (*ide_dma_queued_read)(ide_drive_t *drive);
+	ide_startstop_t (*ide_dma_queued_write)(ide_drive_t *drive);
+	ide_startstop_t (*ide_dma_queued_start)(ide_drive_t *drive);
 } ide_dma_ops_t;
 
 /*
@@ -958,6 +968,13 @@
 	int (*ide_dma_retune)(ide_drive_t *drive);
 	int (*ide_dma_lostirq)(ide_drive_t *drive);
 	int (*ide_dma_timeout)(ide_drive_t *drive);
+
+	/* dma queued operations */
+	int (*ide_dma_queued_on)(ide_drive_t *drive);
+	int (*ide_dma_queued_off)(ide_drive_t *drive);
+	ide_startstop_t (*ide_dma_queued_read)(ide_drive_t *drive);
+	ide_startstop_t (*ide_dma_queued_write)(ide_drive_t *drive);
+	ide_startstop_t (*ide_dma_queued_start)(ide_drive_t *drive);
 #endif
 
 #if 0
@@ -1016,21 +1033,15 @@
 	unsigned	reset      : 1;	/* reset after probe */
 	unsigned	autodma    : 1;	/* auto-attempt using DMA at boot */
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
-	unsigned	highmem    : 1;	/* can do full 32-bit dma */
 	unsigned	no_dsc     : 1;	/* 0 default, 1 dsc_overlap disabled */
+	unsigned	auto_poll  : 1; /* supports nop auto-poll */
 
 	struct device	gendev;
 
 	void		*hwif_data;	/* extra hwif data */
-} ide_hwif_t;
 
-/*
- * Status returned from various ide_ functions
- */
-typedef enum {
-	ide_stopped,	/* no drive operation was started */
-	ide_started	/* a drive operation was started, handler was set */
-} ide_startstop_t;
+	unsigned dma;
+} ide_hwif_t;
 
 /*
  *  internal ide interrupt handler type
@@ -1071,6 +1082,8 @@
 	int (*expiry)(ide_drive_t *);
 		/* ide_system_bus_speed */
 	int pio_clock;
+
+	unsigned char cmd_buf[4];
 } ide_hwgroup_t;
 
 /* structure attached to the request for IDE_TASK_CMDS */
@@ -1171,7 +1184,7 @@
 	int		(*suspend)(ide_drive_t *);
 	int		(*resume)(ide_drive_t *);
 	int		(*flushcache)(ide_drive_t *);
-	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
+	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, sector_t);
 	int		(*end_request)(ide_drive_t *, int, int);
 	u8		(*sense)(ide_drive_t *, const char *, u8);
 	ide_startstop_t	(*error)(ide_drive_t *, const char *, u8);
@@ -1187,6 +1200,7 @@
 	int		(*attach)(ide_drive_t *);
 	void		(*ata_prebuilder)(ide_drive_t *);
 	void		(*atapi_prebuilder)(ide_drive_t *);
+	struct device_driver	gen_driver;
 	struct list_head drives;
 	struct list_head drivers;
 } ide_driver_t;
@@ -1661,6 +1675,7 @@
 extern ide_startstop_t ide_dma_intr(ide_drive_t *);
 extern int ide_release_dma(ide_hwif_t *);
 extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
+extern int ide_start_dma(ide_hwif_t *, ide_drive_t *, int);
 
 extern int __ide_dma_host_off(ide_drive_t *);
 extern int __ide_dma_off_quietly(ide_drive_t *);
@@ -1681,6 +1696,24 @@
 extern int __ide_dma_lostirq(ide_drive_t *);
 extern int __ide_dma_timeout(ide_drive_t *);
 
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+extern int __ide_dma_queued_on(ide_drive_t *drive);
+extern int __ide_dma_queued_off(ide_drive_t *drive);
+extern ide_startstop_t __ide_dma_queued_read(ide_drive_t *drive);
+extern ide_startstop_t __ide_dma_queued_write(ide_drive_t *drive);
+extern ide_startstop_t __ide_dma_queued_start(ide_drive_t *drive);
+#else
+static inline int __ide_dma_queued_on(ide_drive_t *drive)
+{
+	return 1;
+}
+
+static inline int __ide_dma_queued_off(ide_drive_t *drive)
+{
+	return 1;
+}
+#endif
+
 extern void hwif_unregister(ide_hwif_t *);
 
 extern void export_ide_init_queue(ide_drive_t *);
@@ -1707,6 +1740,28 @@
 extern spinlock_t ide_lock;
 
 #define local_irq_set(flags)	do { local_save_flags((flags)); local_irq_enable(); } while (0)
+
+#define IDE_MAX_TAG	32
+#ifdef CONFIG_BLK_DEV_IDE_TCQ
+static inline int ata_pending_commands(ide_drive_t *drive)
+{
+	if (drive->using_tcq)
+		return blk_queue_tag_depth(&drive->queue);
+
+	return 0;
+}
+
+static inline int ata_can_queue(ide_drive_t *drive)
+{
+	if (drive->using_tcq)
+		return blk_queue_tag_queue(&drive->queue);
+
+	return 1;
+}
+#else
+#define ata_pending_commands(drive)	(0)
+#define ata_can_queue(drive)		(1)
+#endif
 
 extern struct bus_type ide_bus_type;
 
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	Fri Oct 11 21:22:56 2002
+++ b/include/linux/input.h	Fri Oct 11 21:22:57 2002
@@ -2,33 +2,16 @@
 #define _INPUT_H
 
 /*
- * $Id: input.h,v 1.68 2002/05/31 10:35:49 fsirl Exp $
+ * Copyright (c) 1999-2002 Vojtech Pavlik
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #ifdef __KERNEL__
 #include <linux/time.h>
+#include <linux/list.h>
 #else
 #include <sys/time.h>
 #include <sys/ioctl.h>
@@ -349,6 +332,7 @@
 #define KEY_CANCEL		223
 #define KEY_BRIGHTNESSDOWN	224
 #define KEY_BRIGHTNESSUP	225
+#define KEY_MEDIA		226
 
 #define KEY_UNKNOWN		240
 
@@ -759,6 +743,8 @@
 
 #define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
 	((dev->keycodesize == 1) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
+
+#define init_input_dev(dev)	do { INIT_LIST_HEAD(&((dev)->h_list)); INIT_LIST_HEAD(&((dev)->node)); } while (0)
 
 struct input_dev {
 
diff -Nru a/include/linux/ipc.h b/include/linux/ipc.h
--- a/include/linux/ipc.h	Fri Oct 11 21:22:50 2002
+++ b/include/linux/ipc.h	Fri Oct 11 21:22:50 2002
@@ -63,6 +63,7 @@
 	gid_t		cgid;
 	mode_t		mode; 
 	unsigned long	seq;
+	void		*security;
 };
 
 #endif /* __KERNEL__ */
diff -Nru a/include/linux/isdn.h b/include/linux/isdn.h
--- a/include/linux/isdn.h	Fri Oct 11 21:23:05 2002
+++ b/include/linux/isdn.h	Fri Oct 11 21:23:05 2002
@@ -339,10 +339,11 @@
 				       /* phone[1] = Outgoing Numbers      */
 
   struct list_head       slaves;       /* list of all bundled channels     */
-  struct list_head       online;       /* circular list of all bundled
-					  channels, which are currently
-					  online                           */
-  spinlock_t             online_lock;  /* lock to protect queue            */
+  struct list_head       online;       /* list of all bundled channels, 
+					  which are currently online       */
+  spinlock_t             online_lock;  /* lock to protect online list      */
+  struct list_head       running_devs; /* member of global running_devs    */
+  atomic_t               refcnt;       /* references held by ISDN code     */
 
 #ifdef CONFIG_ISDN_X25
   struct concap_device_ops *dops;      /* callbacks used by encapsulator   */
@@ -403,8 +404,8 @@
 
   isdn_net_local        *mlp;          /* Ptr to master device for all devs*/
 
-  struct list_head       slaves;       /* Members of local->slaves         */
-  struct list_head       online;       /* Members of local->online         */
+  struct list_head       slaves;       /* member of local->slaves          */
+  struct list_head       online;       /* member of local->online          */
 
   char                   name[10];     /* Name of device                   */
   struct list_head       global_list;  /* global list of all isdn_net_devs */
diff -Nru a/include/linux/iso_fs.h b/include/linux/iso_fs.h
--- a/include/linux/iso_fs.h	Fri Oct 11 21:23:00 2002
+++ b/include/linux/iso_fs.h	Fri Oct 11 21:23:00 2002
@@ -174,7 +174,7 @@
 
 static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct iso_inode_info *ISOFS_I(struct inode *inode)
@@ -230,7 +230,7 @@
 int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
 extern struct dentry *isofs_lookup(struct inode *, struct dentry *);
-extern struct buffer_head *isofs_bread(struct inode *, unsigned int);
+extern struct buffer_head *isofs_bread(struct inode *, sector_t);
 extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
 
 extern struct inode_operations isofs_dir_inode_operations;
diff -Nru a/include/linux/jbd.h b/include/linux/jbd.h
--- a/include/linux/jbd.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/jbd.h	Fri Oct 11 21:23:03 2002
@@ -54,7 +54,7 @@
 #define jbd_debug(f, a...)	/**/
 #endif
 
-extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry);
+extern void * __jbd_kmalloc (const char *where, size_t size, int flags, int retry);
 #define jbd_kmalloc(size, flags) \
 	__jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
 #define jbd_rep_kmalloc(size, flags) \
diff -Nru a/include/linux/kd.h b/include/linux/kd.h
--- a/include/linux/kd.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/kd.h	Fri Oct 11 21:23:03 2002
@@ -134,7 +134,8 @@
 
 struct kbd_repeat {
 	int delay;	/* in msec; <= 0: don't change */
-	int rate;	/* in msec; <= 0: don't change */
+	int period;	/* in msec; <= 0: don't change */
+			/* earlier this field was misnamed "rate" */
 };
 
 #define KDKBDREP        0x4B52  /* set keyboard delay/repeat rate;
diff -Nru a/include/linux/kernel.h b/include/linux/kernel.h
--- a/include/linux/kernel.h	Fri Oct 11 21:22:50 2002
+++ b/include/linux/kernel.h	Fri Oct 11 21:22:50 2002
@@ -201,6 +201,9 @@
 
 #define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
 
+extern void BUILD_BUG(void);
+#define BUILD_BUG_ON(condition) do { if (condition) BUILD_BUG(); } while(0)
+
 /* Trap pasters of __FUNCTION__ at compile-time */
 #if __GNUC__ > 2 || __GNUC_MINOR__ >= 95
 #define __FUNCTION__ (__func__)
diff -Nru a/include/linux/keyboard.h b/include/linux/keyboard.h
--- a/include/linux/keyboard.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/keyboard.h	Fri Oct 11 21:22:54 2002
@@ -2,6 +2,7 @@
 #define __LINUX_KEYBOARD_H
 
 #include <linux/wait.h>
+#include <linux/input.h>
 
 #define KG_SHIFT	0
 #define KG_CTRL		2
@@ -15,9 +16,9 @@
 
 #define NR_SHIFT	9
 
-#define NR_KEYS		128
+#define NR_KEYS		(KEY_MAX+1)
 #define MAX_NR_KEYMAPS	256
-/* This means 64Kb if all keymaps are allocated. Only the superuser
+/* This means 128Kb if all keymaps are allocated. Only the superuser
 	may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */
 #define MAX_NR_OF_USER_KEYMAPS 256 	/* should be at least 7 */
 
diff -Nru a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
--- a/include/linux/lockd/bind.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/lockd/bind.h	Fri Oct 11 21:22:55 2002
@@ -13,7 +13,6 @@
 
 /* Dummy declarations */
 struct svc_rqst;
-struct svc_client;		/* opaque type */
 
 /*
  * This is the set of functions for lockd->nfsd communication
diff -Nru a/include/linux/loop.h b/include/linux/loop.h
--- a/include/linux/loop.h	Fri Oct 11 21:23:05 2002
+++ b/include/linux/loop.h	Fri Oct 11 21:23:05 2002
@@ -33,7 +33,7 @@
 	int		lo_flags;
 	int		(*transfer)(struct loop_device *, int cmd,
 				    char *raw_buf, char *loop_buf, int size,
-				    int real_block);
+				    sector_t real_block);
 	char		lo_name[LO_NAME_SIZE];
 	char		lo_encrypt_key[LO_KEY_SIZE];
 	__u32           lo_init[2];
@@ -123,7 +123,7 @@
 struct loop_func_table {
 	int number; 	/* filter type */ 
 	int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf,
-			char *loop_buf, int size, int real_block);
+			char *loop_buf, int size, sector_t real_block);
 	int (*init)(struct loop_device *, struct loop_info *); 
 	/* release is called from loop_unregister_transfer or clr_fd */
 	int (*release)(struct loop_device *); 
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Fri Oct 11 21:22:51 2002
+++ b/include/linux/mmzone.h	Fri Oct 11 21:22:51 2002
@@ -172,7 +172,7 @@
 } pg_data_t;
 
 extern int numnodes;
-extern pg_data_t *pgdat_list;
+extern struct pglist_data *pgdat_list;
 
 static inline int
 memclass(struct zone *pgzone, struct zone *classzone)
@@ -184,19 +184,8 @@
 	return 1;
 }
 
-/*
- * The following two are not meant for general usage. They are here as
- * prototypes for the discontig memory code.
- */
-struct page;
-extern void calculate_totalpages (pg_data_t *pgdat, unsigned long *zones_size,
-		unsigned long *zholes_size);
-extern void free_area_init_core(pg_data_t *pgdat, unsigned long *zones_size,
-		unsigned long *zholes_size);
 void get_zone_counts(unsigned long *active, unsigned long *inactive);
-extern void build_all_zonelists(void);
-
-extern pg_data_t contig_page_data;
+void build_all_zonelists(void);
 
 /**
  * for_each_pgdat - helper macro to iterate over all nodes
@@ -260,11 +249,10 @@
 #define numa_node_id()		(__cpu_to_node(smp_processor_id()))
 
 #ifndef CONFIG_DISCONTIGMEM
-
+extern struct pglist_data contig_page_data;
 #define NODE_DATA(nid)		(&contig_page_data)
 #define NODE_MEM_MAP(nid)	mem_map
 #define MAX_NR_NODES		1
-
 #else /* CONFIG_DISCONTIGMEM */
 
 #include <asm/mmzone.h>
diff -Nru a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
--- a/include/linux/msdos_fs.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/msdos_fs.h	Fri Oct 11 21:23:03 2002
@@ -193,7 +193,7 @@
 
 static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct msdos_inode_info *MSDOS_I(struct inode *inode)
diff -Nru a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
--- a/include/linux/ncp_fs.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/ncp_fs.h	Fri Oct 11 21:22:54 2002
@@ -192,7 +192,7 @@
 
 static inline struct ncp_server *NCP_SBP(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 #define NCP_SERVER(inode)	NCP_SBP((inode)->i_sb)
diff -Nru a/include/linux/nfs3.h b/include/linux/nfs3.h
--- a/include/linux/nfs3.h	Fri Oct 11 21:23:00 2002
+++ b/include/linux/nfs3.h	Fri Oct 11 21:23:00 2002
@@ -28,6 +28,7 @@
 #define NFS3_ACCESS_EXTEND	0x0008
 #define NFS3_ACCESS_DELETE	0x0010
 #define NFS3_ACCESS_EXECUTE	0x0020
+#define NFS3_ACCESS_FULL	0x003f
 
 /* Flags for create mode */
 enum nfs3_createmode {
diff -Nru a/include/linux/nfs4.h b/include/linux/nfs4.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/nfs4.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,205 @@
+/*
+ *  include/linux/nfs4.h
+ *
+ *  NFSv4 protocol definitions.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+#ifndef _LINUX_NFS4_H
+#define _LINUX_NFS4_H
+
+#define NFS4_VERIFIER_SIZE	8
+#define NFS4_FHSIZE		128
+#define NFS4_MAXNAMLEN		NAME_MAX
+
+#define NFS4_ACCESS_READ        0x0001
+#define NFS4_ACCESS_LOOKUP      0x0002
+#define NFS4_ACCESS_MODIFY      0x0004
+#define NFS4_ACCESS_EXTEND      0x0008
+#define NFS4_ACCESS_DELETE      0x0010
+#define NFS4_ACCESS_EXECUTE     0x0020
+
+#define NFS4_FH_PERISTENT		0x0000
+#define NFS4_FH_NOEXPIRE_WITH_OPEN	0x0001
+#define NFS4_FH_VOLATILE_ANY		0x0002
+#define NFS4_FH_VOL_MIGRATION		0x0004
+#define NFS4_FH_VOL_RENAME		0x0008
+
+#define NFS4_OPEN_RESULT_CONFIRM 0x0002
+
+#define NFS4_SHARE_ACCESS_READ	0x0001
+#define NFS4_SHARE_ACCESS_WRITE	0x0002
+#define NFS4_SHARE_ACCESS_BOTH	0x0003
+
+#define NFS4_SET_TO_SERVER_TIME	0
+#define NFS4_SET_TO_CLIENT_TIME	1
+
+#define NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE 0
+#define NFS4_ACE_ACCESS_DENIED_ACE_TYPE  1
+#define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE   2
+#define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE   3
+
+typedef char nfs4_verifier[NFS4_VERIFIER_SIZE];
+typedef char nfs4_stateid[16];
+
+enum nfs_opnum4 {
+	OP_ACCESS = 3,
+	OP_CLOSE = 4,
+	OP_COMMIT = 5,
+	OP_CREATE = 6,
+	OP_DELEGPURGE = 7,
+	OP_DELEGRETURN = 8,
+	OP_GETATTR = 9,
+	OP_GETFH = 10,
+	OP_LINK = 11,
+	OP_LOCK = 12,
+	OP_LOCKT = 13,
+	OP_LOCKU = 14,
+	OP_LOOKUP = 15,
+	OP_LOOKUPP = 16,
+	OP_NVERIFY = 17,
+	OP_OPEN = 18,
+	OP_OPENATTR = 19,
+	OP_OPEN_CONFIRM = 20,
+	OP_OPEN_DOWNGRADE = 21,
+	OP_PUTFH = 22,
+	OP_PUTPUBFH = 23,
+	OP_PUTROOTFH = 24,
+	OP_READ = 25,
+	OP_READDIR = 26,
+	OP_READLINK = 27,
+	OP_REMOVE = 28,
+	OP_RENAME = 29,
+	OP_RENEW = 30,
+	OP_RESTOREFH = 31,
+	OP_SAVEFH = 32,
+	OP_SECINFO = 33,
+	OP_SETATTR = 34,
+	OP_SETCLIENTID = 35,
+	OP_SETCLIENTID_CONFIRM = 36,
+	OP_VERIFY = 37,
+	OP_WRITE = 38,
+};
+
+/*
+ * Note: NF4BAD is not actually part of the protocol; it is just used
+ * internally by nfsd.
+ */
+enum nfs_ftype4 {
+	NF4BAD		= 0,
+        NF4REG          = 1,    /* Regular File */
+        NF4DIR          = 2,    /* Directory */
+        NF4BLK          = 3,    /* Special File - block device */
+        NF4CHR          = 4,    /* Special File - character device */
+        NF4LNK          = 5,    /* Symbolic Link */
+        NF4SOCK         = 6,    /* Special File - socket */
+        NF4FIFO         = 7,    /* Special File - fifo */
+        NF4ATTRDIR      = 8,    /* Attribute Directory */
+        NF4NAMEDATTR    = 9     /* Named Attribute */
+};
+
+enum open_claim_type4 {
+	NFS4_OPEN_CLAIM_NULL = 0,
+	NFS4_OPEN_CLAIM_PREVIOUS = 1,
+	NFS4_OPEN_CLAIM_DELEGATE_CUR = 2,
+	NFS4_OPEN_CLAIM_DELEGATE_PREV = 3
+};
+
+enum opentype4 {
+	NFS4_OPEN_NOCREATE = 0,
+	NFS4_OPEN_CREATE = 1
+};
+
+enum createmode4 {
+	NFS4_CREATE_UNCHECKED = 0,
+	NFS4_CREATE_GUARDED = 1,
+	NFS4_CREATE_EXCLUSIVE = 2
+};
+
+enum limit_by4 {
+	NFS4_LIMIT_SIZE = 1,
+	NFS4_LIMIT_BLOCKS = 2
+};
+
+enum open_delegation_type4 {
+	NFS4_OPEN_DELEGATE_NONE = 0,
+	NFS4_OPEN_DELEGATE_READ = 1,
+	NFS4_OPEN_DELEGATE_WRITE = 2
+};
+
+/* Mandatory Attributes */
+#define FATTR4_WORD0_SUPPORTED_ATTRS    (1)
+#define FATTR4_WORD0_TYPE               (1 << 1)
+#define FATTR4_WORD0_FH_EXPIRE_TYPE     (1 << 2)
+#define FATTR4_WORD0_CHANGE             (1 << 3)
+#define FATTR4_WORD0_SIZE               (1 << 4)
+#define FATTR4_WORD0_LINK_SUPPORT       (1 << 5)
+#define FATTR4_WORD0_SYMLINK_SUPPORT    (1 << 6)
+#define FATTR4_WORD0_NAMED_ATTR         (1 << 7)
+#define FATTR4_WORD0_FSID               (1 << 8)
+#define FATTR4_WORD0_UNIQUE_HANDLES     (1 << 9)
+#define FATTR4_WORD0_LEASE_TIME         (1 << 10)
+#define FATTR4_WORD0_RDATTR_ERROR       (1 << 11)
+
+/* Recommended Attributes */
+#define FATTR4_WORD0_ACL                (1 << 12)
+#define FATTR4_WORD0_ACLSUPPORT         (1 << 13)
+#define FATTR4_WORD0_ARCHIVE            (1 << 14)
+#define FATTR4_WORD0_CANSETTIME         (1 << 15)
+#define FATTR4_WORD0_CASE_INSENSITIVE   (1 << 16)
+#define FATTR4_WORD0_CASE_PRESERVING    (1 << 17)
+#define FATTR4_WORD0_CHOWN_RESTRICTED   (1 << 18)
+#define FATTR4_WORD0_FILEHANDLE         (1 << 19)
+#define FATTR4_WORD0_FILEID             (1 << 20)
+#define FATTR4_WORD0_FILES_AVAIL        (1 << 21)
+#define FATTR4_WORD0_FILES_FREE         (1 << 22)
+#define FATTR4_WORD0_FILES_TOTAL        (1 << 23)
+#define FATTR4_WORD0_FS_LOCATIONS       (1 << 24)
+#define FATTR4_WORD0_HIDDEN             (1 << 25)
+#define FATTR4_WORD0_HOMOGENEOUS        (1 << 26)
+#define FATTR4_WORD0_MAXFILESIZE        (1 << 27)
+#define FATTR4_WORD0_MAXLINK            (1 << 28)
+#define FATTR4_WORD0_MAXNAME            (1 << 29)
+#define FATTR4_WORD0_MAXREAD            (1 << 30)
+#define FATTR4_WORD0_MAXWRITE           (1 << 31)
+#define FATTR4_WORD1_MIMETYPE           (1)
+#define FATTR4_WORD1_MODE               (1 << 1)
+#define FATTR4_WORD1_NO_TRUNC           (1 << 2)
+#define FATTR4_WORD1_NUMLINKS           (1 << 3)
+#define FATTR4_WORD1_OWNER              (1 << 4)
+#define FATTR4_WORD1_OWNER_GROUP        (1 << 5)
+#define FATTR4_WORD1_QUOTA_HARD         (1 << 6)
+#define FATTR4_WORD1_QUOTA_SOFT         (1 << 7)
+#define FATTR4_WORD1_QUOTA_USED         (1 << 8)
+#define FATTR4_WORD1_RAWDEV             (1 << 9)
+#define FATTR4_WORD1_SPACE_AVAIL        (1 << 10)
+#define FATTR4_WORD1_SPACE_FREE         (1 << 11)
+#define FATTR4_WORD1_SPACE_TOTAL        (1 << 12)
+#define FATTR4_WORD1_SPACE_USED         (1 << 13)
+#define FATTR4_WORD1_SYSTEM             (1 << 14)
+#define FATTR4_WORD1_TIME_ACCESS        (1 << 15)
+#define FATTR4_WORD1_TIME_ACCESS_SET    (1 << 16)
+#define FATTR4_WORD1_TIME_BACKUP        (1 << 17)
+#define FATTR4_WORD1_TIME_CREATE        (1 << 18)
+#define FATTR4_WORD1_TIME_DELTA         (1 << 19)
+#define FATTR4_WORD1_TIME_METADATA      (1 << 20)
+#define FATTR4_WORD1_TIME_MODIFY        (1 << 21)
+#define FATTR4_WORD1_TIME_MODIFY_SET    (1 << 22)
+
+#define NFSPROC4_NULL 0
+#define NFSPROC4_COMPOUND 1
+#define NFS4_MINOR_VERSION 0
+#define NFS4_DEBUG 1
+
+#endif
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/nfs_fs.h	Fri Oct 11 21:22:55 2002
@@ -25,6 +25,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
 #include <linux/nfs3.h>
+#include <linux/nfs4.h>
 #include <linux/nfs_page.h>
 #include <linux/nfs_xdr.h>
 
@@ -143,6 +144,7 @@
 	__u64			read_cache_isize;
 	unsigned long		attrtimeo;
 	unsigned long		attrtimeo_timestamp;
+	__u64			change_attr;		/* v4 only */
 
 	/*
 	 * Timestamp that dates the change made to read_cache_mtime.
@@ -192,7 +194,7 @@
 {
 	return container_of(inode, struct nfs_inode, vfs_inode);
 }
-#define NFS_SB(s)		((struct nfs_server *)(s->u.generic_sbp))
+#define NFS_SB(s)		((struct nfs_server *)(s->s_fs_info))
 
 #define NFS_FH(inode)			(&NFS_I(inode)->fh)
 #define NFS_SERVER(inode)		(NFS_SB(inode->i_sb))
@@ -207,6 +209,7 @@
 #define NFS_CACHE_CTIME(inode)		(NFS_I(inode)->read_cache_ctime)
 #define NFS_CACHE_MTIME(inode)		(NFS_I(inode)->read_cache_mtime)
 #define NFS_CACHE_ISIZE(inode)		(NFS_I(inode)->read_cache_isize)
+#define NFS_CHANGE_ATTR(inode)		(NFS_I(inode)->change_attr)
 #define NFS_NEXTSCAN(inode)		(NFS_I(inode)->nextscan)
 #define NFS_CACHEINV(inode) \
 do { \
@@ -320,6 +323,14 @@
 extern int  nfs_writepage(struct page *);
 extern int  nfs_flush_incompatible(struct file *file, struct page *page);
 extern int  nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
+extern void nfs_writeback_done(struct rpc_task *task, int stable,
+			       unsigned int arg_count, unsigned int res_count);
+extern void nfs_writedata_release(struct rpc_task *task);
+
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+extern void nfs_commit_done(struct rpc_task *);
+#endif
+
 /*
  * Try to write back everything synchronously (but check the
  * return value!)
@@ -329,7 +340,7 @@
 extern int  nfs_flush_list(struct list_head *, int, int);
 extern int  nfs_scan_lru_dirty(struct nfs_server *, struct list_head *);
 extern int  nfs_scan_lru_dirty_timeout(struct nfs_server *, struct list_head *);
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 extern int  nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
 extern int  nfs_commit_list(struct list_head *, int);
 extern int  nfs_scan_lru_commit(struct nfs_server *, struct list_head *);
@@ -376,6 +387,11 @@
 	return (error < 0) ? error : 0;
 }
 
+/* Hack for future NFS swap support */
+#ifndef IS_SWAPFILE
+# define IS_SWAPFILE(inode)	(0)
+#endif
+
 /*
  * linux/fs/nfs/read.c
  */
@@ -384,6 +400,8 @@
 extern int  nfs_pagein_list(struct list_head *, int);
 extern int  nfs_scan_lru_read(struct nfs_server *, struct list_head *);
 extern int  nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
+extern void nfs_readpage_result(struct rpc_task *, unsigned int count, int eof);
+extern void nfs_readdata_release(struct rpc_task *);
 
 /*
  * linux/fs/mount_clnt.c
@@ -452,28 +470,7 @@
 	__retval;							\
 })
 
-#ifdef CONFIG_NFS_V3
-
 #define NFS_JUKEBOX_RETRY_TIME (5 * HZ)
-static inline int
-nfs_async_handle_jukebox(struct rpc_task *task)
-{
-	if (task->tk_status != -EJUKEBOX)
-		return 0;
-	task->tk_status = 0;
-	rpc_restart_call(task);
-	rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
-	return 1;
-}
-
-#else
-
-static inline int
-nfs_async_handle_jukebox(struct rpc_task *task)
-{
-	return 0;
-}
-#endif /* CONFIG_NFS_V3 */
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
--- a/include/linux/nfs_xdr.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/nfs_xdr.h	Fri Oct 11 21:23:03 2002
@@ -24,17 +24,27 @@
 		} nfs3;
 	} du;
 	__u32			rdev;
-	__u64			fsid;
+	union {
+		__u64		nfs3;		/* also nfs2 */
+		struct {
+			__u64	major;
+			__u64	minor;
+		} nfs4;
+	} fsid_u;
 	__u64			fileid;
 	__u64			atime;
 	__u64			mtime;
 	__u64			ctime;
+	__u64			change_attr;	/* NFSv4 change attribute */
+	__u64			pre_change_attr;/* pre-op NFSv4 change attribute */
 	unsigned long		timestamp;
 };
 
 #define NFS_ATTR_WCC		0x0001		/* pre-op WCC data    */
 #define NFS_ATTR_FATTR		0x0002		/* post-op attributes */
 #define NFS_ATTR_FATTR_V3	0x0004		/* NFSv3 attributes */
+#define NFS_ATTR_FATTR_V4	0x0008
+#define NFS_ATTR_PRE_CHANGE	0x0010
 
 /*
  * Info on the file system
@@ -57,6 +67,7 @@
 	__u64			afiles;	/* # of files available to user */
 	__u32			linkmax;/* max # of hard links */
 	__u32			namelen;/* max name length */
+	__u32			lease_time; /* in seconds */
 };
 
 /*
@@ -298,6 +309,43 @@
 	int			plus;
 };
 
+struct nfs_read_data {
+	struct rpc_task		task;
+	struct inode		*inode;
+	struct rpc_cred		*cred;
+	struct nfs_fattr	fattr;	/* fattr storage */
+	struct list_head	pages;	/* Coalesced read requests */
+	struct page		*pagevec[NFS_READ_MAXIOV];
+	union {
+		struct {
+			struct nfs_readargs args;
+			struct nfs_readres  res;
+		} v3;   /* also v2 */
+#ifdef CONFIG_NFS_V4
+		/* NFSv4 data will come here... */
+#endif
+	} u;
+};
+
+struct nfs_write_data {
+	struct rpc_task		task;
+	struct inode		*inode;
+	struct rpc_cred		*cred;
+	struct nfs_fattr	fattr;
+	struct nfs_writeverf	verf;
+	struct list_head	pages;		/* Coalesced requests we wish to flush */
+	struct page		*pagevec[NFS_WRITE_MAXIOV];
+	union {
+		struct {
+			struct nfs_writeargs args;
+			struct nfs_writeres  res;
+		} v3;
+#ifdef CONFIG_NFS_V4
+		/* NFSv4 data to come here... */
+#endif
+	} u;
+};
+
 /*
  * RPC procedure vector for NFSv2/NFSv3 demuxing
  */
@@ -307,7 +355,7 @@
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fattr *);
 	int	(*getattr) (struct inode *, struct nfs_fattr *);
-	int	(*setattr) (struct inode *, struct nfs_fattr *,
+	int	(*setattr) (struct dentry *, struct nfs_fattr *,
 			    struct iattr *);
 	int	(*lookup)  (struct inode *, struct qstr *,
 			    struct nfs_fh *, struct nfs_fattr *);
@@ -328,7 +376,7 @@
 	int	(*remove)  (struct inode *, struct qstr *);
 	int	(*unlink_setup)  (struct rpc_message *,
 			    struct dentry *, struct qstr *);
-	void	(*unlink_done) (struct dentry *, struct rpc_message *);
+	int	(*unlink_done) (struct dentry *, struct rpc_task *);
 	int	(*rename)  (struct inode *, struct qstr *,
 			    struct inode *, struct qstr *);
 	int	(*link)    (struct inode *, struct inode *, struct qstr *);
@@ -338,13 +386,16 @@
 	int	(*mkdir)   (struct inode *, struct qstr *, struct iattr *,
 			    struct nfs_fh *, struct nfs_fattr *);
 	int	(*rmdir)   (struct inode *, struct qstr *);
-	int	(*readdir) (struct inode *, struct rpc_cred *,
+	int	(*readdir) (struct dentry *, struct rpc_cred *,
 			    u64, struct page *, unsigned int, int);
 	int	(*mknod)   (struct inode *, struct qstr *, struct iattr *,
 			    dev_t, struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsinfo *);
 	u32 *	(*decode_dirent)(u32 *, struct nfs_entry *, int plus);
+	void	(*read_setup)   (struct nfs_read_data *, unsigned int count);
+	void	(*write_setup)  (struct nfs_write_data *, unsigned int count, int how);
+	void	(*commit_setup) (struct nfs_write_data *, u64 start, u32 len, int how);
 };
 
 /*
diff -Nru a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h
--- a/include/linux/nfsd/const.h	Fri Oct 11 21:23:00 2002
+++ b/include/linux/nfsd/const.h	Fri Oct 11 21:23:00 2002
@@ -12,6 +12,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs2.h>
 #include <linux/nfs3.h>
+#include <linux/nfs4.h>
 
 /*
  * Maximum protocol version supported by knfsd
@@ -27,6 +28,16 @@
 
 #ifndef NFS_SUPER_MAGIC
 # define NFS_SUPER_MAGIC	0x6969
+#endif
+
+#define NFSD_BUFSIZE		(1024 + NFSSVC_MAXBLKSIZE)
+
+#ifdef CONFIG_NFSD_V4
+# define NFSSVC_XDRSIZE		NFS4_SVC_XDRSIZE
+#elif defined(CONFIG_NFSD_V3)
+# define NFSSVC_XDRSIZE		NFS3_SVC_XDRSIZE
+#else
+# define NFSSVC_XDRSIZE		NFS2_SVC_XDRSIZE
 #endif
 
 #endif /* __KERNEL__ */
diff -Nru a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
--- a/include/linux/nfsd/export.h	Fri Oct 11 21:22:59 2002
+++ b/include/linux/nfsd/export.h	Fri Oct 11 21:22:59 2002
@@ -45,14 +45,9 @@
 
 #ifdef __KERNEL__
 
-struct svc_client {
-	struct svc_client *	cl_next;
-	char			cl_ident[NFSCLNT_IDMAX];
-};
-
 struct svc_export {
-	struct list_head	ex_hash;
-	struct svc_client *	ex_client;
+	struct cache_head	h;
+	struct auth_domain *	ex_client;
 	int			ex_flags;
 	struct vfsmount *	ex_mnt;
 	struct dentry *		ex_dentry;
@@ -66,13 +61,13 @@
  * for type 0 (dev/ino), one for type 1 (fsid)
  */
 struct svc_expkey {
-	struct list_head	ek_hash;
+	struct cache_head	h;
 
-	struct svc_client	*ek_client;
+	struct auth_domain *	ek_client;
 	int			ek_fsidtype;
 	u32			ek_fsid[2];
 
-	struct svc_export	*ek_export;
+	struct svc_export *	ek_export;
 };
 
 #define EX_SECURE(exp)		(!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
@@ -90,26 +85,47 @@
 void			nfsd_export_shutdown(void);
 void			exp_readlock(void);
 void			exp_readunlock(void);
-struct svc_client *	exp_getclient(struct sockaddr_in *sin);
-void			exp_putclient(struct svc_client *clp);
-struct svc_expkey *	exp_find_key(struct svc_client *clp, int fsid_type, u32 *fsidv);
-struct svc_export *	exp_get_by_name(struct svc_client *clp,
+struct svc_expkey *	exp_find_key(struct auth_domain *clp, 
+				     int fsid_type, u32 *fsidv,
+				     struct cache_req *reqp);
+struct svc_export *	exp_get_by_name(struct auth_domain *clp,
 					struct vfsmount *mnt,
-					struct dentry *dentry);
-struct svc_export *	exp_parent(struct svc_client *clp, struct vfsmount *mnt,
-				   struct dentry *dentry);
-int			exp_rootfh(struct svc_client *, 
+					struct dentry *dentry,
+					struct cache_req *reqp);
+struct svc_export *	exp_parent(struct auth_domain *clp,
+				   struct vfsmount *mnt,
+				   struct dentry *dentry,
+				   struct cache_req *reqp);
+int			exp_rootfh(struct auth_domain *, 
 					char *path, struct knfsd_fh *, int maxsize);
+int			exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp);
 int			nfserrno(int errno);
 
+extern void expkey_put(struct cache_head *item, struct cache_detail *cd);
+extern void svc_export_put(struct cache_head *item, struct cache_detail *cd);
+extern struct cache_detail svc_export_cache, svc_expkey_cache;
+
+static inline void exp_put(struct svc_export *exp)
+{
+	svc_export_put(&exp->h, &svc_export_cache);
+}
+
 static inline struct svc_export *
-exp_find(struct svc_client *clp, int fsid_type, u32 *fsidv)
+exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
+	 struct cache_req *reqp)
 {
-	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv);
-	if (ek)
-		return ek->ek_export;
-	else
-		return NULL;
+	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
+	if (ek && !IS_ERR(ek)) {
+		struct svc_export *exp = ek->ek_export;
+		int err;
+		cache_get(&exp->h);
+		expkey_put(&ek->h, &svc_expkey_cache);
+		if (exp &&
+		    (err = cache_check(&svc_export_cache, &exp->h, reqp)))
+			exp = ERR_PTR(err);
+		return exp;
+	} else
+		return ERR_PTR(PTR_ERR(ek));
 }
 
 #endif /* __KERNEL__ */
diff -Nru a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
--- a/include/linux/nfsd/nfsd.h	Fri Oct 11 21:22:57 2002
+++ b/include/linux/nfsd/nfsd.h	Fri Oct 11 21:22:57 2002
@@ -26,6 +26,7 @@
  * nfsd version
  */
 #define NFSD_VERSION		"0.5"
+#define NFSD_SUPPORTED_MINOR_VERSION	0
 
 #ifdef __KERNEL__
 /*
@@ -69,6 +70,9 @@
 #ifdef CONFIG_NFSD_V3
 extern struct svc_procedure	nfsd_procedures3[];
 #endif /* CONFIG_NFSD_V3 */
+#ifdef CONFIG_NFSD_V4
+extern struct svc_procedure	nfsd_procedures4[];
+#endif /* CONFIG_NFSD_V4 */
 extern struct svc_program	nfsd_program;
 
 /*
@@ -135,7 +139,6 @@
  */
 void		nfsd_lockd_init(void);
 void		nfsd_lockd_shutdown(void);
-void		nfsd_lockd_unexport(struct svc_client *);
 
 
 /*
@@ -196,6 +199,73 @@
  * Time of server startup
  */
 extern struct timeval	nfssvc_boot;
+
+
+#ifdef CONFIG_NFSD_V4
+
+/* before processing a COMPOUND operation, we have to check that there
+ * is enough space in the buffer for XDR encode to succeed.  otherwise,
+ * we might process an operation with side effects, and be unable to
+ * tell the client that the operation succeeded.
+ *
+ * COMPOUND_SLACK_SPACE - this is the minimum amount of buffer space
+ * needed to encode an "ordinary" _successful_ operation.  (GETATTR,
+ * READ, READDIR, and READLINK have their own buffer checks.)  if we
+ * fall below this level, we fail the next operation with NFS4ERR_RESOURCE.
+ *
+ * COMPOUND_ERR_SLACK_SPACE - this is the minimum amount of buffer space
+ * needed to encode an operation which has failed with NFS4ERR_RESOURCE.
+ * care is taken to ensure that we never fall below this level for any
+ * reason.
+ */
+#define	COMPOUND_SLACK_SPACE		140    /* OP_GETFH */
+#define COMPOUND_ERR_SLACK_SPACE	12     /* OP_SETATTR */
+
+#define NFSD_LEASE_TIME			60  /* seconds */
+
+/*
+ * The following attributes are currently not supported by the NFSv4 server:
+ *    ACL           (will be supported in a forthcoming patch)
+ *    ARCHIVE       (deprecated anyway)
+ *    FS_LOCATIONS  (will be supported eventually)
+ *    HIDDEN        (unlikely to be supported any time soon)
+ *    MIMETYPE      (unlikely to be supported any time soon)
+ *    QUOTA_*       (will be supported in a forthcoming patch)
+ *    SYSTEM        (unlikely to be supported any time soon)
+ *    TIME_BACKUP   (unlikely to be supported any time soon)
+ *    TIME_CREATE   (unlikely to be supported any time soon)
+ */
+#define NFSD_SUPPORTED_ATTRS_WORD0                                                          \
+(FATTR4_WORD0_SUPPORTED_ATTRS   | FATTR4_WORD0_TYPE         | FATTR4_WORD0_FH_EXPIRE_TYPE   \
+ | FATTR4_WORD0_CHANGE          | FATTR4_WORD0_SIZE         | FATTR4_WORD0_LINK_SUPPORT     \
+ | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR   | FATTR4_WORD0_FSID             \
+ | FATTR4_WORD0_UNIQUE_HANDLES  | FATTR4_WORD0_LEASE_TIME   | FATTR4_WORD0_RDATTR_ERROR     \
+ | FATTR4_WORD0_ACLSUPPORT      | FATTR4_WORD0_CANSETTIME   | FATTR4_WORD0_CASE_INSENSITIVE \
+ | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED                             \
+ | FATTR4_WORD0_FILEHANDLE      | FATTR4_WORD0_FILEID       | FATTR4_WORD0_FILES_AVAIL      \
+ | FATTR4_WORD0_FILES_FREE      | FATTR4_WORD0_FILES_TOTAL  | FATTR4_WORD0_HOMOGENEOUS      \
+ | FATTR4_WORD0_MAXFILESIZE     | FATTR4_WORD0_MAXLINK      | FATTR4_WORD0_MAXNAME          \
+ | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE)
+
+#define NFSD_SUPPORTED_ATTRS_WORD1                                                          \
+(FATTR4_WORD1_MODE              | FATTR4_WORD1_NO_TRUNC     | FATTR4_WORD1_NUMLINKS         \
+ | FATTR4_WORD1_OWNER	        | FATTR4_WORD1_OWNER_GROUP  | FATTR4_WORD1_RAWDEV           \
+ | FATTR4_WORD1_SPACE_AVAIL     | FATTR4_WORD1_SPACE_FREE   | FATTR4_WORD1_SPACE_TOTAL      \
+ | FATTR4_WORD1_SPACE_USED      | FATTR4_WORD1_TIME_ACCESS  | FATTR4_WORD1_TIME_ACCESS_SET  \
+ | FATTR4_WORD1_TIME_CREATE     | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
+ | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET)
+
+/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
+#define NFSD_WRITEONLY_ATTRS_WORD1							    \
+(FATTR4_WORD1_TIME_ACCESS_SET   | FATTR4_WORD1_TIME_MODIFY_SET)
+
+/* These are the only attrs allowed in CREATE/OPEN/SETATTR. */
+#define NFSD_WRITEABLE_ATTRS_WORD0                            FATTR4_WORD0_SIZE
+#define NFSD_WRITEABLE_ATTRS_WORD1                                                          \
+(FATTR4_WORD1_MODE              | FATTR4_WORD1_OWNER         | FATTR4_WORD1_OWNER_GROUP     \
+ | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET)
+
+#endif /* CONFIG_NFSD_V4 */
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
--- a/include/linux/nfsd/nfsfh.h	Fri Oct 11 21:23:00 2002
+++ b/include/linux/nfsd/nfsfh.h	Fri Oct 11 21:23:00 2002
@@ -96,7 +96,7 @@
 					 */
 	union {
 		struct nfs_fhbase_old	fh_old;
-		__u32			fh_pad[NFS3_FHSIZE/4];
+		__u32			fh_pad[NFS4_FHSIZE/4];
 		struct nfs_fhbase_new	fh_new;
 	} fh_base;
 };
@@ -249,6 +249,14 @@
 			
 	*dst = *src;
 	return dst;
+}
+
+static __inline__ void
+fh_dup2(struct svc_fh *dst, struct svc_fh *src)
+{
+	fh_put(dst);
+	dget(src->fh_dentry);
+	*dst = *src;
 }
 
 static __inline__ struct svc_fh *
diff -Nru a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
--- a/include/linux/nfsd/xdr.h	Fri Oct 11 21:23:02 2002
+++ b/include/linux/nfsd/xdr.h	Fri Oct 11 21:23:02 2002
@@ -119,7 +119,7 @@
 	struct nfsd_readdirargs	readdir;
 };
 
-#define NFSSVC_XDRSIZE		sizeof(union nfsd_xdrstore)
+#define NFS2_SVC_XDRSIZE	sizeof(union nfsd_xdrstore)
 
 
 int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
diff -Nru a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/nfsd/xdr4.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,328 @@
+/*
+ *  include/linux/nfsd/xdr4.h
+ *
+ *  Server-side types for NFSv4.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LINUX_NFSD_XDR4_H
+#define _LINUX_NFSD_XDR4_H
+
+#define NFSD4_MAX_TAGLEN	128
+
+typedef struct {
+	u32		cl_boot;
+	u32		cl_id;
+} clientid_t;
+
+typedef u32 stateid_boot_t;        /* used to detect stale stateids */
+typedef u32 stateid_lockowner_t;   /* lockowner id - used in various places */
+typedef u32 stateid_file_t;        /* identifies a unique file per lockowner */
+typedef u32 stateid_generation_t;  /* used to update stateids */
+
+typedef struct {
+	stateid_boot_t		so_boot;
+	stateid_lockowner_t	so_lockowner;
+	stateid_file_t		so_file;
+} stateid_other_t;
+
+typedef struct {
+	stateid_generation_t	st_generation;
+	stateid_other_t		st_other;
+} stateid_t;
+
+typedef u32 delegation_zero_t;
+typedef u32 delegation_boot_t;
+typedef u64 delegation_id_t;
+
+typedef struct {
+	delegation_zero_t	ds_zero;
+	delegation_boot_t	ds_boot;
+	delegation_id_t		ds_id;
+} delegation_stateid_t;
+
+struct nfsd4_change_info {
+	u32		atomic;
+	u32		before_size;
+	u32		before_ctime;
+	u32		after_size;
+	u32		after_ctime;
+};
+
+struct nfsd4_access {
+	u32		ac_req_access;      /* request */
+	u32		ac_supported;       /* response */
+	u32		ac_resp_access;     /* response */
+};
+
+struct nfsd4_close {
+	u32		cl_seqid;           /* request */
+	stateid_t	cl_stateid;         /* request+response */
+};
+
+struct nfsd4_commit {
+	u64		co_offset;          /* request */
+	u32		co_count;           /* request */
+	nfs4_verifier	co_verf;            /* response */
+};
+
+struct nfsd4_create {
+	u32		cr_namelen;         /* request */
+	char *		cr_name;            /* request */
+	u32		cr_type;            /* request */
+	union {                             /* request */
+		struct {
+			u32 namelen;
+			char *name;
+		} link;   /* NF4LNK */
+		struct {
+			u32 specdata1;
+			u32 specdata2;
+		} dev;    /* NF4BLK, NF4CHR */
+	} u;
+	u32		cr_bmval[2];        /* request */
+	struct iattr	cr_iattr;           /* request */
+	struct nfsd4_change_info  cr_cinfo; /* response */
+};
+#define cr_linklen	u.link.namelen
+#define cr_linkname	u.link.name
+#define cr_specdata1	u.dev.specdata1
+#define cr_specdata2	u.dev.specdata2
+
+struct nfsd4_getattr {
+	u32		ga_bmval[2];        /* request */
+	struct svc_fh	*ga_fhp;            /* response */
+};
+
+struct nfsd4_link {
+	u32		li_namelen;         /* request */
+	char *		li_name;            /* request */
+	struct nfsd4_change_info  li_cinfo; /* response */
+};
+
+struct nfsd4_lookup {
+	u32		lo_len;             /* request */
+	char *		lo_name;            /* request */
+};
+
+struct nfsd4_putfh {
+	u32		pf_fhlen;           /* request */
+	char		*pf_fhval;          /* request */
+};
+
+struct nfsd4_open {
+	u32		op_claim_type;      /* request */
+	u32		op_namelen;	    /* request - everything but CLAIM_PREV */
+	char *		op_name;	    /* request - everything but CLAIM_PREV */
+	u32		op_delegate_type;   /* request - CLAIM_PREV only */
+	delegation_stateid_t	op_delegate_stateid; /* request - CLAIM_DELEGATE_CUR only */
+	u32		op_create;     	    /* request */
+	u32		op_createmode;      /* request */
+	u32		op_bmval[2];        /* request */
+	union {                             /* request */
+		struct iattr	iattr;		            /* UNCHECKED4,GUARDED4 */
+		nfs4_verifier	verf;		                     /* EXCLUSIVE4 */
+	} u;
+	clientid_t	op_clientid;        /* request */
+	u32		op_ownerlen;        /* request */
+	char *		op_owner;           /* request */
+	u32		op_seqid;           /* request */
+	u32		op_share_access;    /* request */
+	u32		op_share_deny;      /* request */
+	stateid_t	op_stateid;         /* response */
+	struct nfsd4_change_info  op_cinfo; /* response */
+	u32		op_rflags;          /* response */
+	int		op_truncate;        /* used during processing */
+
+};
+#define op_iattr	u.iattr
+#define op_verf		u.verf
+
+struct nfsd4_read {
+	stateid_t	rd_stateid;         /* request */
+	u64		rd_offset;          /* request */
+	u32		rd_length;          /* request */
+	struct svc_rqst *rd_rqstp;          /* response */
+	struct svc_fh * rd_fhp;             /* response */
+};
+
+struct nfsd4_readdir {
+	u64		rd_cookie;          /* request */
+	nfs4_verifier	rd_verf;            /* request */
+	u32		rd_dircount;        /* request */
+	u32		rd_maxcount;        /* request */
+	u32		rd_bmval[2];        /* request */
+	struct svc_rqst *rd_rqstp;          /* response */
+	struct svc_fh * rd_fhp;             /* response */
+};
+
+struct nfsd4_readlink {
+	struct svc_rqst *rl_rqstp;          /* request */
+	struct svc_fh *	rl_fhp;             /* request */
+};
+
+struct nfsd4_remove {
+	u32		rm_namelen;         /* request */
+	char *		rm_name;            /* request */
+	struct nfsd4_change_info  rm_cinfo; /* response */
+};
+
+struct nfsd4_rename {
+	u32		rn_snamelen;        /* request */
+	char *		rn_sname;           /* request */
+	u32		rn_tnamelen;        /* request */
+	char *		rn_tname;           /* request */
+	struct nfsd4_change_info  rn_sinfo; /* response */
+	struct nfsd4_change_info  rn_tinfo; /* response */
+};
+
+struct nfsd4_setattr {
+	stateid_t	sa_stateid;         /* request */
+	u32		sa_bmval[2];        /* request */
+	struct iattr	sa_iattr;           /* request */
+};
+
+struct nfsd4_setclientid {
+	nfs4_verifier	se_verf;            /* request */
+	u32		se_namelen;         /* request */
+	char *		se_name;            /* request */
+	u32		se_callback_prog;   /* request */
+	u32		se_callback_netid_len;  /* request */
+	char *		se_callback_netid_val;  /* request */
+	u32		se_callback_addr_len;   /* request */
+	char *		se_callback_addr_val;   /* request */
+	u32		se_callback_ident;  /* request */
+	clientid_t	se_clientid;        /* response */
+};
+
+/* also used for NVERIFY */
+struct nfsd4_verify {
+	u32		ve_bmval[2];        /* request */
+	u32		ve_attrlen;         /* request */
+	char *		ve_attrval;         /* request */
+};
+
+struct nfsd4_write {
+	stateid_t	wr_stateid;         /* request */
+	u64		wr_offset;          /* request */
+	u32		wr_stable_how;      /* request */
+	u32		wr_buflen;          /* request */
+	char *		wr_buf;             /* request */
+	u32		wr_bytes_written;   /* response */
+	u32		wr_how_written;     /* response */
+	nfs4_verifier	wr_verifier;        /* response */
+};
+
+struct nfsd4_op {
+	int					opnum;
+	int					status;
+	union {
+		struct nfsd4_access		access;
+		struct nfsd4_close		close;
+		struct nfsd4_commit		commit;
+		struct nfsd4_create		create;
+		struct nfsd4_getattr		getattr;
+		struct svc_fh *			getfh;
+		struct nfsd4_link		link;
+		struct nfsd4_lookup		lookup;
+		struct nfsd4_verify		nverify;
+		struct nfsd4_open		open;
+		struct nfsd4_putfh		putfh;
+		struct nfsd4_read		read;
+		struct nfsd4_readdir		readdir;
+		struct nfsd4_readlink		readlink;
+		struct nfsd4_remove		remove;
+		struct nfsd4_rename		rename;
+		clientid_t			renew;
+		struct nfsd4_setattr		setattr;
+		struct nfsd4_setclientid	setclientid;
+		clientid_t			setclientid_confirm;
+		struct nfsd4_verify		verify;
+		struct nfsd4_write		write;
+	} u;
+};
+
+struct nfsd4_compoundargs {
+	/* scratch variables for XDR decode */
+	u32 *				p;
+	u32 *				end;
+	
+	u32				taglen;
+	char *				tag;
+	u32				minorversion;
+	u32				opcnt;
+	struct nfsd4_op			*ops;
+	struct nfsd4_op			iops[8];
+};
+
+struct nfsd4_compoundres {
+	/* scratch variables for XDR encode */
+	u32 *				p;
+	u32 *				end;
+
+	u32				taglen;
+	char *				tag;
+	u32				opcnt;
+};
+
+#define NFS4_SVC_XDRSIZE		sizeof(struct nfsd4_compoundargs)
+
+#if CONFIG_NFSD_V3
+static inline void
+set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
+{
+	BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved);
+	cinfo->atomic = 1;
+	cinfo->before_size = fhp->fh_pre_size;
+	cinfo->before_ctime = fhp->fh_pre_ctime;
+	cinfo->after_size = fhp->fh_post_size;
+	cinfo->after_ctime = fhp->fh_post_ctime;
+}
+#endif
+
+int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *);
+int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *, struct nfsd4_compoundargs *);
+int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *, struct nfsd4_compoundres *);
+
+void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
+int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+		       struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval);
+
+#endif
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Fri Oct 11 21:22:58 2002
+++ b/include/linux/pci.h	Fri Oct 11 21:22:58 2002
@@ -371,7 +371,7 @@
 	struct resource dma_resource[DEVICE_COUNT_DMA];
 	struct resource irq_resource[DEVICE_COUNT_IRQ];
 
-	char		name[80];	/* device name */
+	char		name[90];	/* device name */
 	char		slot_name[8];	/* slot name */
 	int		active;		/* ISAPnP: device is active */
 	int		ro;		/* ISAPnP: read only */
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Fri Oct 11 21:22:56 2002
+++ b/include/linux/pci_ids.h	Fri Oct 11 21:22:56 2002
@@ -623,6 +623,7 @@
 #define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
 #define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
 #define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
+#define PCI_DEVICE_ID_MOTOROLA_MPC107	0x0004
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
 #define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
 #define PCI_DEVICE_ID_MOTOROLA_HAWK	0x4803
@@ -852,6 +853,7 @@
 #define PCI_DEVICE_ID_AL_M1644		0x1644
 #define PCI_DEVICE_ID_AL_M1647		0x1647
 #define PCI_DEVICE_ID_AL_M1651		0x1651
+#define PCI_DEVICE_ID_AL_M1671		0x1671
 #define PCI_DEVICE_ID_AL_M1543		0x1543
 #define PCI_DEVICE_ID_AL_M3307		0x3307
 #define PCI_DEVICE_ID_AL_M4803		0x5215
diff -Nru a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
--- a/include/linux/qnx4_fs.h	Fri Oct 11 21:23:05 2002
+++ b/include/linux/qnx4_fs.h	Fri Oct 11 21:23:05 2002
@@ -135,7 +135,7 @@
 
 static inline struct qnx4_sb_info *qnx4_sb(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct qnx4_inode_info *qnx4_i(struct inode *inode)
diff -Nru a/include/linux/radix-tree.h b/include/linux/radix-tree.h
--- a/include/linux/radix-tree.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/radix-tree.h	Fri Oct 11 21:22:55 2002
@@ -21,8 +21,6 @@
 
 struct radix_tree_node;
 
-#define RADIX_TREE_SLOT_RESERVED ((void *)~0UL)
-
 struct radix_tree_root {
 	unsigned int		height;
 	int			gfp_mask;
@@ -41,7 +39,6 @@
 	(root)->rnode = NULL;		\
 } while (0)
 
-extern int radix_tree_reserve(struct radix_tree_root *, unsigned long, void ***);
 extern int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
 extern void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
 extern int radix_tree_delete(struct radix_tree_root *, unsigned long);
diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h
--- a/include/linux/raid/md.h	Fri Oct 11 21:22:52 2002
+++ b/include/linux/raid/md.h	Fri Oct 11 21:22:52 2002
@@ -60,7 +60,7 @@
 #define MD_MINOR_VERSION                90
 #define MD_PATCHLEVEL_VERSION           0
 
-extern int md_size[MAX_MD_DEVS];
+extern sector_t md_size[MAX_MD_DEVS];
 
 extern inline char * bdev_partition_name (struct block_device *bdev)
 {
diff -Nru a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
--- a/include/linux/raid/md_k.h	Fri Oct 11 21:22:52 2002
+++ b/include/linux/raid/md_k.h	Fri Oct 11 21:22:52 2002
@@ -144,7 +144,7 @@
 {
 	struct list_head same_set;	/* RAID devices within the same set */
 
-	unsigned long size;		/* Device size (in blocks) */
+	sector_t size;			/* Device size (in blocks) */
 	mddev_t *mddev;			/* RAID array if running */
 	unsigned long last_events;	/* IO event timestamp */
 
@@ -152,7 +152,7 @@
 
 	struct page	*sb_page;
 	mdp_super_t	*sb;
-	unsigned long	sb_offset;
+	sector_t	sb_offset;
 
 	/* A device can be in one of three states based on two flags:
 	 * Not working:   faulty==1 in_sync==0
@@ -350,5 +350,5 @@
 	__wait_disk_event(wq, condition);				\
 } while (0)
 
-#endif 
+#endif
 
diff -Nru a/include/linux/raid/raid0.h b/include/linux/raid/raid0.h
--- a/include/linux/raid/raid0.h	Fri Oct 11 21:23:05 2002
+++ b/include/linux/raid/raid0.h	Fri Oct 11 21:23:05 2002
@@ -5,9 +5,9 @@
 
 struct strip_zone
 {
-	unsigned long zone_offset;	/* Zone offset in md_dev */
-	unsigned long dev_offset;	/* Zone offset in real dev */
-	unsigned long size;		/* Zone size */
+	sector_t zone_offset;	/* Zone offset in md_dev */
+	sector_t dev_offset;	/* Zone offset in real dev */
+	sector_t size;		/* Zone size */
 	int nb_dev;			/* # of devices attached to the zone */
 	mdk_rdev_t *dev[MD_SB_DISKS]; /* Devices attached to the zone */
 };
diff -Nru a/include/linux/rbtree.h b/include/linux/rbtree.h
--- a/include/linux/rbtree.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/rbtree.h	Fri Oct 11 21:22:55 2002
@@ -122,6 +122,7 @@
 /* Find logical next and previous nodes in a tree */
 extern struct rb_node *rb_next(struct rb_node *);
 extern struct rb_node *rb_prev(struct rb_node *);
+extern struct rb_node *rb_first(struct rb_root *);
 
 /* Fast replacement of a single node without remove/rebalance/add/rebalance */
 extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/reiserfs_fs.h	Fri Oct 11 21:23:03 2002
@@ -294,7 +294,7 @@
 
 static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 /** this says about version of key of all items (but stat data) the
diff -Nru a/include/linux/security.h b/include/linux/security.h
--- a/include/linux/security.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/security.h	Fri Oct 11 21:22:54 2002
@@ -572,6 +572,50 @@
  * 	is being reparented to the init task.
  *	@p contains the task_struct for the kernel thread.
  *
+ * Security hooks affecting all System V IPC operations.
+ *
+ * @ipc_permission:
+ *	Check permissions for access to IPC
+ *	@ipcp contains the kernel IPC permission structure
+ *	@flag contains the desired (requested) permission set
+ *	Return 0 if permission is granted.
+ *
+ * Security hooks for System V IPC Message Queues
+ *
+ * @msg_queue_alloc_security:
+ *	Allocate and attach a security structure to the
+ *	msq->q_perm.security field. The security field is initialized to
+ *	NULL when the structure is first created.
+ *	@msq contains the message queue structure to be modified.
+ *	Return 0 if operation was successful and permission is granted.
+ * @msg_queue_free_security:
+ *	Deallocate security structure for this message queue.
+ *	@msq contains the message queue structure to be modified.
+ *
+ * Security hooks for System V Shared Memory Segments
+ *
+ * @shm_alloc_security:
+ *	Allocate and attach a security structure to the shp->shm_perm.security
+ *	field.  The security field is initialized to NULL when the structure is
+ *	first created.
+ *	@shp contains the shared memory structure to be modified.
+ *	Return 0 if operation was successful and permission is granted.
+ * @shm_free_security:
+ *	Deallocate the security struct for this memory segment.
+ *	@shp contains the shared memory structure to be modified.
+ *
+ * Security hooks for System V Semaphores
+ *
+ * @sem_alloc_security:
+ *	Allocate and attach a security structure to the sma->sem_perm.security
+ *	field.  The security field is initialized to NULL when the structure is
+ *	first created.
+ *	@sma contains the semaphore structure
+ *	Return 0 if operation was successful and permission is granted.
+ * @sem_free_security:
+ *	deallocate security struct for this semaphore
+ *	@sma contains the semaphore structure.
+ *
  * @ptrace:
  *	Check permission before allowing the @parent process to trace the
  *	@child process.
@@ -785,6 +829,17 @@
 			   unsigned long arg5);
 	void (*task_kmod_set_label) (void);
 	void (*task_reparent_to_init) (struct task_struct * p);
+
+	int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+
+	int (*msg_queue_alloc_security) (struct msg_queue * msq);
+	void (*msg_queue_free_security) (struct msg_queue * msq);
+
+	int (*shm_alloc_security) (struct shmid_kernel * shp);
+	void (*shm_free_security) (struct shmid_kernel * shp);
+
+	int (*sem_alloc_security) (struct sem_array * sma);
+	void (*sem_free_security) (struct sem_array * sma);
 
 	/* allow module stacking */
 	int (*register_security) (const char *name,
diff -Nru a/include/linux/serialP.h b/include/linux/serialP.h
--- a/include/linux/serialP.h	Fri Oct 11 21:22:53 2002
+++ b/include/linux/serialP.h	Fri Oct 11 21:22:53 2002
@@ -131,6 +131,9 @@
  * Digital did something really horribly wrong with the OUT1 and OUT2
  * lines on at least some ALPHA's.  The failure mode is that if either
  * is cleared, the machine locks up with endless interrupts.
+ *
+ * This is still used by arch/mips/au1000/common/serial.c for some weird
+ * reason (mips != alpha!)
  */
 #define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
 #else
@@ -138,29 +141,8 @@
 #endif
 
 /*
- * Structures and definitions for PCI support
+ * Definitions for PCI support.
  */
-struct pci_dev;
-struct pci_board {
-	int flags;
-	int num_ports;
-	int base_baud;
-	int uart_offset;
-	int reg_shift;
-	int (*init_fn)(struct pci_dev *dev, struct pci_board *board,
-			int enable);
-	int first_uart_offset;
-};
-
-struct pci_board_inst {
-	struct pci_board	board;
-	struct pci_dev		*dev;
-};
-
-#ifndef PCI_ANY_ID
-#define PCI_ANY_ID (~0)
-#endif
-
 #define SPCI_FL_BASE_MASK	0x0007
 #define SPCI_FL_BASE0	0x0000
 #define SPCI_FL_BASE1	0x0001
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	Fri Oct 11 21:23:00 2002
+++ b/include/linux/serio.h	Fri Oct 11 21:23:00 2002
@@ -2,36 +2,16 @@
 #define _SERIO_H
 
 /*
- * $Id: serio.h,v 1.21 2001/12/19 05:15:21 skids Exp $
- *
- * Copyright (C) 1999-2001 Vojtech Pavlik
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-/*
- * The serial port set type ioctl.
+ * Copyright (C) 1999-2002 Vojtech Pavlik
+*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #include <linux/ioctl.h>
+#include <linux/list.h>
+
 #define SPIOCSTYPE	_IOW('q', 0x01, unsigned long)
 
 struct serio;
@@ -57,7 +37,8 @@
 	void (*close)(struct serio *);
 
 	struct serio_dev *dev;
-	struct serio *next;
+
+	struct list_head node;
 };
 
 struct serio_dev {
@@ -69,8 +50,9 @@
 	void (*interrupt)(struct serio *, unsigned char, unsigned int);
 	void (*connect)(struct serio *, struct serio_dev *dev);
 	void (*disconnect)(struct serio *);
+	void (*cleanup)(struct serio *);
 
-	struct serio_dev *next;
+	struct list_head node;
 };
 
 int serio_open(struct serio *serio, struct serio_dev *dev);
@@ -85,13 +67,22 @@
 
 static __inline__ int serio_write(struct serio *serio, unsigned char data)
 {
-	return serio->write(serio, data);
+	if (serio->write)
+		return serio->write(serio, data);
+	else
+		return -1;
 }
 
 static __inline__ void serio_dev_write_wakeup(struct serio *serio)
 {
 	if (serio->dev && serio->dev->write_wakeup)
 		serio->dev->write_wakeup(serio);
+}
+
+static __inline__ void serio_cleanup(struct serio *serio)
+{
+	if (serio->dev && serio->dev->cleanup)
+		serio->dev->cleanup(serio);
 }
 
 /*
diff -Nru a/include/linux/smb_fs.h b/include/linux/smb_fs.h
--- a/include/linux/smb_fs.h	Fri Oct 11 21:23:00 2002
+++ b/include/linux/smb_fs.h	Fri Oct 11 21:23:00 2002
@@ -33,7 +33,7 @@
 
 static inline struct smb_sb_info *SMB_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct smb_inode_info *SMB_I(struct inode *inode)
diff -Nru a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/sunrpc/cache.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,302 @@
+/*
+ * include/linux/sunrpc/cache.h
+ *
+ * Generic code for various authentication-related caches
+ * used by sunrpc clients and servers.
+ *
+ * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
+ *
+ * Released under terms in GPL version 2.  See COPYING.
+ *
+ */
+
+#ifndef _LINUX_SUNRPC_CACHE_H_
+#define _LINUX_SUNRPC_CACHE_H_
+
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <linux/proc_fs.h>
+
+/*
+ * Each cache requires:
+ *  - A 'struct cache_detail' which contains information specific to the cache
+ *    for common code to use.
+ *  - An item structure that must contain a "struct cache_head"
+ *  - A lookup function defined using DefineCacheLookup
+ *  - A 'put' function that can release a cache item. It will only
+ *    be called after cache_put has succeed, so there are guarantee
+ *    to be no references.
+ *  - A function to calculate a hash of an item's key.
+ *
+ * as well as assorted code fragments (e.g. compare keys) and numbers
+ * (e.g. hash size, goal_age, etc).
+ *
+ * Each cache must be registered so that it can be cleaned regularly.
+ * When the cache is unregistered, it is flushed completely.
+ *
+ * Entries have a ref count and a 'hashed' flag which counts the existance
+ * in the hash table.
+ * We only expire entries when refcount is zero.
+ * Existance in the cache is not measured in refcount but rather in
+ * CACHE_HASHED flag.
+ */
+
+/* Every cache item has a common header that is used
+ * for expiring and refreshing entries.
+ * 
+ */
+struct cache_head {
+	struct cache_head * next;
+	time_t		expiry_time;	/* After time time, don't use the data */
+	time_t		last_refresh;   /* If CACHE_PENDING, this is when upcall 
+					 * was sent, else this is when update was received
+					 */
+	atomic_t 	refcnt;
+	unsigned long	flags;
+};
+#define	CACHE_VALID	0	/* Entry contains valid data */
+#define	CACHE_NEGATIVE	1	/* Negative entry - there is no match for the key */
+#define	CACHE_PENDING	2	/* An upcall has been sent but no reply received yet*/
+#define	CACHE_HASHED	3	/* Entry is in a hash table */
+
+#define	CACHE_NEW_EXPIRY 120	/* keep new things pending confirmation for 120 seconds */
+
+struct cache_detail {
+	int			hash_size;
+	struct cache_head **	hash_table;
+	rwlock_t		hash_lock;
+
+	atomic_t		inuse; /* active user-space update or lookup */
+
+	char			*name;
+	void			(*cache_put)(struct cache_head *,
+					     struct cache_detail*);
+
+	void			(*cache_request)(struct cache_detail *cd,
+						 struct cache_head *h,
+						 char **bpp, int *blen);
+	int			(*cache_parse)(struct cache_detail *,
+					       char *buf, int len);
+
+	/* fields below this comment are for internal use
+	 * and should not be touched by cache owners
+	 */
+	time_t			flush_time;		/* flush all cache items with last_refresh
+							 * earlier than this */
+	struct list_head	others;
+	time_t			nextcheck;
+	int			entries;
+
+	/* fields for communication over channel */
+	struct list_head	queue;
+	struct proc_dir_entry	*proc_ent;
+	atomic_t		readers;		/* how many time is /chennel open */
+	time_t			last_close;		/* it no readers, when did last close */
+};
+
+
+/* this must be embedded in any request structure that
+ * identifies an object that will want a callback on
+ * a cache fill
+ */
+struct cache_req {
+	struct cache_deferred_req *(*defer)(struct cache_req *req);
+};
+/* this must be embedded in a deferred_request that is being
+ * delayed awaiting cache-fill
+ */
+struct cache_deferred_req {
+	struct list_head	hash;	/* on hash chain */
+	struct list_head	recent; /* on fifo */
+	struct cache_head	*item;  /* cache item we wait on */
+	time_t			recv_time;
+	void			(*revisit)(struct cache_deferred_req *req,
+					   int too_many);
+};
+
+/*
+ * just like a template in C++, this macro does cache lookup
+ * for us.
+ * The function is passed some sort of HANDLE from which a cache_detail
+ * structure can be determined (via SETUP, DETAIL), a template
+ * cache entry (type RTN*), and a "set" flag.  Using the HASHFN and the 
+ * TEST, the function will try to find a matching cache entry in the cache.
+ * If "set" == 0 :
+ *    If an entry is found, it is returned
+ *    If no entry is found, a new non-VALID entry is created.
+ * If "set" == 1 :
+ *    If no entry is found a new one is inserted with data from "template"
+ *    If a non-CACHE_VALID entry is found, it is updated from template using UPDATE
+ *    If a CACHE_VALID entry is found, a new entry is swapped in with data
+ *       from "template"
+ * If set == 2, we UPDATE, but don't swap. i.e. update in place
+ *
+ * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not
+ * run but insteead CACHE_NEGATIVE is set in any new item.
+
+ *  In any case, the new entry is returned with a reference count.
+ *
+ *    
+ * RTN is a struct type for a cache entry
+ * MEMBER is the member of the cache which is cache_head, which must be first
+ * FNAME is the name for the function	
+ * ARGS are arguments to function and must contain RTN *item, int set.  May
+ *   also contain something to be usedby SETUP or DETAIL to find cache_detail.
+ * SETUP  locates the cache detail and makes it available as...
+ * DETAIL identifies the cache detail, possibly set up by SETUP
+ * HASHFN returns a hash value of the cache entry "item"
+ * TEST  tests if "tmp" matches "item"
+ * INIT copies key information from "item" to "new"
+ * UPDATE copies content information from "item" to "tmp"
+ */
+#define DefineCacheLookup(RTN,MEMBER,FNAME,ARGS,SETUP,DETAIL,HASHFN,TEST,INIT,UPDATE)	\
+RTN *FNAME ARGS										\
+{											\
+	RTN *tmp, *new=NULL;								\
+	struct cache_head **hp, **head;							\
+	SETUP;										\
+ retry:											\
+	head = &(DETAIL)->hash_table[HASHFN];						\
+	if (set||new) write_lock(&(DETAIL)->hash_lock);					\
+	else read_lock(&(DETAIL)->hash_lock);						\
+	for(hp=head; *hp != NULL; hp = &tmp->MEMBER.next) {				\
+		tmp = container_of(*hp, RTN, MEMBER);					\
+		if (TEST) { /* found a match */						\
+											\
+			atomic_inc(&tmp->MEMBER.refcnt);				\
+			if (set) {							\
+				if (set!= 2 && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
+				{ /* need to swap in new */				\
+					RTN *t2;					\
+					if (!new) break;				\
+											\
+					new->MEMBER.next = tmp->MEMBER.next;		\
+					*head = &new->MEMBER;				\
+					tmp->MEMBER.next = NULL;			\
+					set_bit(CACHE_HASHED, &new->MEMBER.flags);	\
+					clear_bit(CACHE_HASHED, &tmp->MEMBER.flags);	\
+					t2 = tmp; tmp = new; new = t2;			\
+				}							\
+				if (test_bit(CACHE_NEGATIVE,  &item->MEMBER.flags))	\
+					 set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);	\
+				else {UPDATE;}						\
+			}								\
+			if (set||new) write_unlock(&(DETAIL)->hash_lock);		\
+			else read_unlock(&(DETAIL)->hash_lock);				\
+			if (set)							\
+				cache_fresh(DETAIL, &tmp->MEMBER, item->MEMBER.expiry_time); \
+			if (new) (DETAIL)->cache_put(&new->MEMBER, DETAIL);		\
+			return tmp;							\
+		}									\
+	}										\
+	/* Didn't find anything */							\
+	if (new) {									\
+		new->MEMBER.next = *head;						\
+		*head = &new->MEMBER;							\
+		(DETAIL)->entries ++;							\
+		set_bit(CACHE_HASHED, &new->MEMBER.flags);				\
+		if (set) {								\
+			tmp = new;							\
+			if (test_bit(CACHE_NEGATIVE, &item->MEMBER.flags))		\
+				set_bit(CACHE_NEGATIVE, &tmp->MEMBER.flags);		\
+			else {UPDATE;}							\
+		}									\
+	}										\
+	if (set||new) write_unlock(&(DETAIL)->hash_lock);				\
+	else read_unlock(&(DETAIL)->hash_lock);						\
+	if (new && set)									\
+		cache_fresh(DETAIL, &new->MEMBER, item->MEMBER.expiry_time);		\
+	if (new)				       					\
+		return new;								\
+	new = kmalloc(sizeof(*new), GFP_KERNEL);					\
+	if (new) {									\
+		cache_init(&new->MEMBER);						\
+		atomic_inc(&new->MEMBER.refcnt);					\
+		INIT;									\
+		tmp = new;								\
+		goto retry;								\
+	}										\
+	return NULL;									\
+}
+
+#define DefineSimpleCacheLookup(STRUCT)	\
+	DefineCacheLookup(struct STRUCT, h, STRUCT##_lookup, (struct STRUCT *item, int set), /*no setup */,	\
+			  & STRUCT##_cache, STRUCT##_hash(item), STRUCT##_match(item, tmp),\
+			  STRUCT##_init(new, item), STRUCT##_update(tmp, item))
+
+#define cache_for_each(pos, detail, index, member) 						\
+	for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ;		\
+	     ({if (index==0)read_unlock(&(detail)->hash_lock); index--;});			\
+		)										\
+		for (pos = container_of((detail)->hash_table[index], typeof(*pos), member);	\
+		     &pos->member;								\
+		     pos = container_of(pos->member.next, typeof(*pos), member))
+
+	     
+
+extern void cache_defer_req(struct cache_req *req, struct cache_head *item);
+extern void cache_revisit_request(struct cache_head *item);
+
+static inline struct cache_head  *cache_get(struct cache_head *h)
+{
+	atomic_inc(&h->refcnt);
+	return h;
+}
+
+
+static int inline cache_put(struct cache_head *h, struct cache_detail *cd)
+{
+	atomic_dec(&h->refcnt);
+	if (!atomic_read(&h->refcnt) &&
+	    h->expiry_time < cd->nextcheck)
+		cd->nextcheck = h->expiry_time;
+	if (!test_bit(CACHE_HASHED, &h->flags) &&
+	    !atomic_read(&h->refcnt))
+		return 1;
+
+	return 0;
+}
+
+extern void cache_init(struct cache_head *h);
+extern void cache_fresh(struct cache_detail *detail,
+			struct cache_head *head, time_t expiry);
+extern int cache_check(struct cache_detail *detail,
+		       struct cache_head *h, struct cache_req *rqstp);
+extern int cache_clean(void);
+extern void cache_flush(void);
+extern void cache_purge(struct cache_detail *detail);
+#define NEVER (0x7FFFFFFF)
+extern void cache_register(struct cache_detail *cd);
+extern int cache_unregister(struct cache_detail *cd);
+extern struct cache_detail *cache_find(char *name);
+extern void cache_drop(struct cache_detail *detail);
+
+extern void add_word(char **bpp, int *lp, char *str);
+extern void add_hex(char **bpp, int *lp, char *buf, int blen);
+extern int get_word(char **bpp, char *dest, int bufsize);
+
+static inline int get_int(char **bpp, int *anint)
+{
+	char buf[50];
+	char *ep;
+	int rv;
+	int len = get_word(bpp, buf, 50);
+	if (len < 0) return -EINVAL;
+	if (len ==0) return -ENOENT;
+	rv = simple_strtol(buf, &ep, 0);
+	if (*ep) return -EINVAL;
+	*anint = rv;
+	return 0;
+}
+
+static inline time_t get_expiry(char **bpp)
+{
+	int rv;
+	if (get_int(bpp, &rv))
+		return 0;
+	if (rv < 0)
+		return 0;
+	return rv;
+}
+
+#endif /*  _LINUX_SUNRPC_CACHE_H_ */
diff -Nru a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
--- a/include/linux/sunrpc/debug.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/sunrpc/debug.h	Fri Oct 11 21:22:55 2002
@@ -35,6 +35,7 @@
 #define RPCDBG_SVCSOCK		0x0100
 #define RPCDBG_SVCDSP		0x0200
 #define RPCDBG_MISC		0x0400
+#define RPCDBG_CACHE		0x0800
 #define RPCDBG_ALL		0x7fff
 
 #ifdef __KERNEL__
diff -Nru a/include/linux/sunrpc/name_lookup.h b/include/linux/sunrpc/name_lookup.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/sunrpc/name_lookup.h	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,38 @@
+
+/*
+ * map between user/group name and id for a given 'client' 
+ */
+
+struct name_ent {
+	char name[20];
+};
+static inline int name_get_user(int uid, struct name_ent **namep)
+{
+	struct name_ent *n = kmalloc(sizeof(*n),GFP_KERNEL);
+	if (n) sprintf(n->name, "%d",uid);
+	*namep = n;
+	return n ? 0 : -ENOMEM;
+}
+static inline int name_get_group(int uid, struct name_ent **namep)
+{
+	struct name_ent *n = kmalloc(sizeof(*n),GFP_KERNEL);
+	if (n) sprintf(n->name, "%d",uid);
+	*namep = n;
+	return n ? 0 : -ENOMEM;
+}
+static inline int name_get_uid(char *name, int name_len, int *uidp)
+{
+	*uidp = simple_strtoul(name, NULL, 0);
+	return 0;
+}
+
+static inline int name_get_gid(char *name, int name_len, int *gidp)
+{
+	*gidp = simple_strtoul(name, NULL, 0);
+	return 0;
+}
+
+static inline void name_put(struct name_ent *ent) 
+{
+	kfree(ent);
+}
diff -Nru a/include/linux/sunrpc/stats.h b/include/linux/sunrpc/stats.h
--- a/include/linux/sunrpc/stats.h	Fri Oct 11 21:22:58 2002
+++ b/include/linux/sunrpc/stats.h	Fri Oct 11 21:22:58 2002
@@ -57,6 +57,8 @@
 					int *, void *);
 void			svc_proc_zero(struct svc_program *);
 
+extern struct proc_dir_entry	*proc_net_rpc;
+
 #else
 
 static inline void svc_proc_unregister(const char *p) {}
diff -Nru a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
--- a/include/linux/sunrpc/svc.h	Fri Oct 11 21:22:59 2002
+++ b/include/linux/sunrpc/svc.h	Fri Oct 11 21:22:59 2002
@@ -98,8 +98,10 @@
 
 	struct svc_serv *	rq_server;	/* RPC service definition */
 	struct svc_procedure *	rq_procinfo;	/* procedure info */
+	struct auth_ops *	rq_authop;	/* authentication flavour */
 	struct svc_cred		rq_cred;	/* auth info */
 	struct sk_buff *	rq_skbuff;	/* fast recv inet buffer */
+	struct svc_deferred_req*rq_deferred;	/* deferred request we are replaying */
 	struct svc_buf		rq_defbuf;	/* default buffer */
 	struct svc_buf		rq_argbuf;	/* argument buffer */
 	struct svc_buf		rq_resbuf;	/* result buffer */
@@ -108,10 +110,10 @@
 	u32			rq_vers;	/* program version */
 	u32			rq_proc;	/* procedure number */
 	u32			rq_prot;	/* IP protocol */
-	unsigned short		rq_verfed  : 1,	/* reply has verifier */
+	unsigned short
 				rq_userset : 1,	/* auth->setuser OK */
-				rq_secure  : 1,	/* secure port */
-				rq_auth    : 1;	/* check client */
+				rq_secure  : 1;	/* secure port */
+
 
 	void *			rq_argp;	/* decoded arguments */
 	void *			rq_resp;	/* xdr'd results */
@@ -120,15 +122,28 @@
 						 * reserved for this request
 						 */
 
+	struct cache_req	rq_chandle;	/* handle passed to caches for 
+						 * request delaying 
+						 */
 	/* Catering to nfsd */
-	struct svc_client *	rq_client;	/* RPC peer info */
+	struct auth_domain *	rq_client;	/* RPC peer info */
 	struct svc_cacherep *	rq_cacherep;	/* cache info */
 	struct knfsd_fh *	rq_reffh;	/* Referrence filehandle, used to
 						 * determine what device number
 						 * to report (real or virtual)
 						 */
 
-	wait_queue_head_t	rq_wait;	/* synchronozation */
+	wait_queue_head_t	rq_wait;	/* synchronization */
+};
+
+struct svc_deferred_req {
+	struct svc_serv		*serv;
+	u32			prot;	/* protocol (UDP or TCP) */
+	struct sockaddr_in	addr;
+	struct svc_sock		*svsk;	/* where reply must go */
+	struct cache_deferred_req handle;
+	int			argslen;
+	u32			args[0];
 };
 
 /*
@@ -141,6 +156,7 @@
 	unsigned int		pg_nvers;	/* number of versions */
 	struct svc_version **	pg_vers;	/* version array */
 	char *			pg_name;	/* service name */
+	char *			pg_class;	/* class name: services sharing authentication */
 	struct svc_stat *	pg_stats;	/* rpc statistics */
 };
 
diff -Nru a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
--- a/include/linux/sunrpc/svcauth.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/sunrpc/svcauth.h	Fri Oct 11 21:22:55 2002
@@ -12,9 +12,9 @@
 #ifdef __KERNEL__
 
 #include <linux/sunrpc/msg_prot.h>
+#include <linux/sunrpc/cache.h>
 
 struct svc_cred {
-	rpc_authflavor_t	cr_flavor;
 	uid_t			cr_uid;
 	gid_t			cr_gid;
 	gid_t			cr_groups[NGROUPS];
@@ -22,27 +22,98 @@
 
 struct svc_rqst;		/* forward decl */
 
-void	svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
-int	svc_auth_register(rpc_authflavor_t flavor,
-				void (*)(struct svc_rqst *,u32 *,u32 *));
-void	svc_auth_unregister(rpc_authflavor_t flavor);
+/* Authentication is done in the context of a domain.
+ * For a server, a domain represents a group of clients using
+ * a common mechanism for authentication and having a common mapping
+ * between local identity (uid) and network identity.  All clients
+ * in a domain have similar general access rights.  Each domain can
+ * contain multiple principals which will have different specific right
+ * based on normal Discretionary Access Control.
+ *
+ * For a client, a domain represents a number of servers which all
+ * use a common authentication mechanism and network identity name space.
+ *
+ * A domain is created by an authentication flavour module based on name
+ * only.  Userspace then fills in detail on demand.
+ *
+ * The creation of a domain typically implies creation of one or
+ * more caches for storing domain specific information.
+ */
+struct auth_domain {
+	struct	cache_head	h;
+	char			*name;
+	int			flavour;
+};
 
-#if 0
 /*
- * Decoded AUTH_UNIX data. This is different from what's in the RPC lib.
+ * Each authentication flavour registers an auth_ops
+ * structure.
+ * name is simply the name.
+ * flavour gives the auth flavour. It determines where the flavour is registered
+ * accept() is given a request and should verify it.
+ *   It should inspect the authenticator and verifier, and possibly the data.
+ *    If there is a problem with the authentication *authp should be set.
+ *    The return value of accept() can indicate:
+ *      OK - authorised. client and credential are set in rqstp.
+ *           reqbuf points to arguments
+ *           resbuf points to good place for results.  verfier
+ *             is (probably) already in place.  Certainly space is
+ *	       reserved for it.
+ *      DROP - simply drop the request. It may have been deferred
+ *      GARBAGE - rpc garbage_args error
+ *      SYSERR - rpc system_err error
+ *      DENIED - authp holds reason for denial.
+ *
+ *   accept is passed the proc number so that it can accept NULL rpc requests
+ *   even if it cannot authenticate the client (as is sometimes appropriate).
+ *
+ * release() is given a request after the procedure has been run.
+ *  It should sign/encrypt the results if needed
+ * It should return:
+ *    OK - the resbuf is ready to be sent
+ *    DROP - the reply should be quitely dropped
+ *    DENIED - authp holds a reason for MSG_DENIED
+ *    SYSERR - rpc system_err
+ *
+ * domain_release()
+ *   This call releases a domain.
  */
-#define NGRPS		16
-struct authunix_parms {
-	u32		aup_stamp;
-	u32		aup_uid;
-	u32		aup_gid;
-	u32		aup_len;
-	u32		aup_gids[NGRPS];
+struct auth_ops {
+	char *	name;
+	int	flavour;
+	int	(*accept)(struct svc_rqst *rq, u32 *authp, int proc);
+	int	(*release)(struct svc_rqst *rq);
+	void	(*domain_release)(struct auth_domain *);
 };
+extern struct auth_ops	*authtab[RPC_AUTH_MAXFLAVOR];
+
+#define	SVC_GARBAGE	1
+#define	SVC_SYSERR	2
+#define	SVC_VALID	3
+#define	SVC_NEGATIVE	4
+#define	SVC_OK		5
+#define	SVC_DROP	6
+#define	SVC_DENIED	7
+#define	SVC_PENDING	8
+
+
+extern int	svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp, int proc);
+extern int	svc_authorise(struct svc_rqst *rqstp);
+extern int	svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
+extern void	svc_auth_unregister(rpc_authflavor_t flavor);
+
+extern struct auth_domain *unix_domain_find(char *name);
+extern void auth_domain_put(struct auth_domain *item);
+extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
+extern struct auth_domain *auth_domain_lookup(struct auth_domain *item, int set);
+extern struct auth_domain *auth_domain_find(char *name);
+extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
+extern int auth_unix_forget_old(struct auth_domain *dom);
+extern void svcauth_unix_purge(void);
 
-struct svc_authops *	auth_getops(rpc_authflavor_t flavor);
-#endif
+extern int name_hash(char *name, int size);
 
+extern struct cache_detail auth_domain_cache, ip_map_cache;
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
--- a/include/linux/sunrpc/svcsock.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/sunrpc/svcsock.h	Fri Oct 11 21:22:55 2002
@@ -31,8 +31,12 @@
 #define	SK_QUED		5			/* on serv->sk_sockets */
 #define	SK_DEAD		6			/* socket closed */
 #define	SK_CHNGBUF	7			/* need to change snd/rcv buffer sizes */
+#define	SK_DEFERRED	8			/* request on sk_deferred */
 
 	int			sk_reserved;	/* space on outq that is reserved */
+
+	struct list_head	sk_deferred;	/* deferred requests that need to
+						 * be revisted */
 
 	int			(*sk_recvfrom)(struct svc_rqst *rqstp);
 	int			(*sk_sendto)(struct svc_rqst *rqstp);
diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Fri Oct 11 21:23:02 2002
+++ b/include/linux/sunrpc/xprt.h	Fri Oct 11 21:23:02 2002
@@ -146,6 +146,7 @@
 	unsigned long		sockstate;	/* Socket state */
 	unsigned char		shutdown   : 1,	/* being shut down */
 				nocong	   : 1,	/* no congestion control */
+				resvport   : 1, /* use a reserved port */
 				stream     : 1;	/* TCP */
 
 	/*
diff -Nru a/include/linux/threads.h b/include/linux/threads.h
--- a/include/linux/threads.h	Fri Oct 11 21:22:51 2002
+++ b/include/linux/threads.h	Fri Oct 11 21:22:51 2002
@@ -8,10 +8,16 @@
  * /proc/sys/kernel/threads-max.
  */
  
+/*
+ * Maximum supported processors that can run under SMP.  This value is
+ * set via configure setting.  The maximum is equal to the size of the
+ * bitmasks used on that platform, i.e. 32 or 64.  Setting this smaller
+ * saves quite a bit of memory.
+ */
 #ifdef CONFIG_SMP
-#define NR_CPUS	32		/* Max processors that can be running in SMP */
+#define NR_CPUS		CONFIG_NR_CPUS
 #else
-#define NR_CPUS 1
+#define NR_CPUS		1
 #endif
 
 #define MIN_THREADS_LEFT_FOR_ROOT 4
diff -Nru a/include/linux/types.h b/include/linux/types.h
--- a/include/linux/types.h	Fri Oct 11 21:22:55 2002
+++ b/include/linux/types.h	Fri Oct 11 21:22:55 2002
@@ -117,13 +117,11 @@
 #endif
 
 /*
- * transition to 64-bit sector_t, possibly making it an option...
+ * The type used for indexing onto a disc or disc partition.
+ * If required, asm/types.h can override it and define
+ * HAVE_SECTOR_T
  */
-#undef BLK_64BIT_SECTOR
-
-#ifdef BLK_64BIT_SECTOR
-typedef u64 sector_t;
-#else
+#ifndef HAVE_SECTOR_T
 typedef unsigned long sector_t;
 #endif
 
diff -Nru a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
--- a/include/linux/ufs_fs.h	Fri Oct 11 21:23:03 2002
+++ b/include/linux/ufs_fs.h	Fri Oct 11 21:23:03 2002
@@ -785,7 +785,7 @@
 
 static inline struct ufs_sb_info *UFS_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static inline struct ufs_inode_info *UFS_I(struct inode *inode)
diff -Nru a/include/linux/uinput.h b/include/linux/uinput.h
--- a/include/linux/uinput.h	Fri Oct 11 21:22:54 2002
+++ b/include/linux/uinput.h	Fri Oct 11 21:22:54 2002
@@ -29,9 +29,9 @@
 #define UINPUT_MINOR		223
 #define UINPUT_NAME		"uinput"
 #define UINPUT_BUFFER_SIZE	16
-#define U_MAX_NAME_SIZE		50
 
-#define UIST_CREATED		1
+/* state flags => bit index for {set|clear|test}_bit ops */
+#define UIST_CREATED		0
 
 struct uinput_device {
 	struct input_dev	*dev;
diff -Nru a/include/math-emu/op-1.h b/include/math-emu/op-1.h
--- a/include/math-emu/op-1.h	Fri Oct 11 21:22:54 2002
+++ b/include/math-emu/op-1.h	Fri Oct 11 21:22:54 2002
@@ -25,7 +25,7 @@
 #ifndef    __MATH_EMU_OP_1_H__
 #define    __MATH_EMU_OP_1_H__
 
-#define _FP_FRAC_DECL_1(X)	_FP_W_TYPE X##_f
+#define _FP_FRAC_DECL_1(X)	_FP_W_TYPE X##_f=0
 #define _FP_FRAC_COPY_1(D,S)	(D##_f = S##_f)
 #define _FP_FRAC_SET_1(X,I)	(X##_f = I)
 #define _FP_FRAC_HIGH_1(X)	(X##_f)
diff -Nru a/include/math-emu/soft-fp.h b/include/math-emu/soft-fp.h
--- a/include/math-emu/soft-fp.h	Fri Oct 11 21:23:04 2002
+++ b/include/math-emu/soft-fp.h	Fri Oct 11 21:23:04 2002
@@ -154,11 +154,11 @@
 
 #define _FP_CLS_COMBINE(x,y)	(((x) << 2) | (y))
 
-#include "op-1.h"
-#include "op-2.h"
-#include "op-4.h"
-#include "op-8.h"
-#include "op-common.h"
+#include <math-emu/op-1.h>
+#include <math-emu/op-2.h>
+#include <math-emu/op-4.h>
+#include <math-emu/op-8.h>
+#include <math-emu/op-common.h>
 
 /* Sigh.  Silly things longlong.h needs.  */
 #define UWtype		_FP_W_TYPE
diff -Nru a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
--- a/include/net/bluetooth/rfcomm.h	Fri Oct 11 21:22:54 2002
+++ b/include/net/bluetooth/rfcomm.h	Fri Oct 11 21:22:54 2002
@@ -268,6 +268,7 @@
 struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
 void   rfcomm_session_del(struct rfcomm_session *s);
 void   rfcomm_session_close(struct rfcomm_session *s, int err);
+void   rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
 
 static inline void rfcomm_session_hold(struct rfcomm_session *s)
 {
@@ -290,7 +291,7 @@
 	u8          rc_channel;
 };
 
-#define rfcomm_pi(sk)   ((struct rfcomm_pinfo *) &sk->protinfo)
+#define rfcomm_pi(sk)   ((struct rfcomm_pinfo *) sk->protinfo)
 
 struct rfcomm_pinfo {
 	struct rfcomm_dlc   *dlc;
diff -Nru a/include/net/dn.h b/include/net/dn.h
--- a/include/net/dn.h	Fri Oct 11 21:22:53 2002
+++ b/include/net/dn.h	Fri Oct 11 21:22:53 2002
@@ -211,7 +211,6 @@
 extern void dn_stop_fast_timer(struct sock *sk);
 
 extern dn_address decnet_address;
-extern unsigned char decnet_ether_address[6];
 extern int decnet_debug_level;
 extern int decnet_time_wait;
 extern int decnet_dn_count;
diff -Nru a/include/net/dn_dev.h b/include/net/dn_dev.h
--- a/include/net/dn_dev.h	Fri Oct 11 21:22:50 2002
+++ b/include/net/dn_dev.h	Fri Oct 11 21:22:50 2002
@@ -57,7 +57,7 @@
  * up() - Called to initialize device, return value can veto use of
  *        device with DECnet.
  * down() - Called to turn device off when it goes down
- * timer3() - Called when timer 3 goes off
+ * timer3() - Called once for each ifaddr when timer 3 goes off
  * 
  * sysctl - Hook for sysctl things
  *
@@ -78,7 +78,7 @@
 	int ctl_name;             /* Index for sysctl                   */
 	int  (*up)(struct net_device *);
 	void (*down)(struct net_device *);
-	void (*timer3)(struct net_device *);
+	void (*timer3)(struct net_device *, struct dn_ifaddr *ifa);
 	void *sysctl;
 };
 
@@ -167,7 +167,9 @@
 extern void dn_dev_up(struct net_device *);
 extern void dn_dev_down(struct net_device *);
 
-extern struct net_device *decnet_default_device;
+extern int dn_dev_set_default(struct net_device *dev, int force);
+extern struct net_device *dn_dev_get_default(void);
+extern int dn_dev_bind_default(dn_address *addr);
 
 static __inline__ int dn_dev_islocal(struct net_device *dev, dn_address addr)
 {
diff -Nru a/include/net/dn_route.h b/include/net/dn_route.h
--- a/include/net/dn_route.h	Fri Oct 11 21:22:51 2002
+++ b/include/net/dn_route.h	Fri Oct 11 21:22:51 2002
@@ -96,7 +96,7 @@
 	dev_queue_xmit(skb);
 }
 
-static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst)
+static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst, char *src)
 {
 	struct net_device *dev = skb->dev;
 
@@ -104,7 +104,7 @@
 		dst = NULL;
 
 	if (!dev->hard_header || (dev->hard_header(skb, dev, ETH_P_DNA_RT,
-			dst, NULL, skb->len) >= 0))
+			dst, src, skb->len) >= 0))
 		dn_rt_send(skb);
 	else
 		kfree_skb(skb);
diff -Nru a/include/net/irda/crc.h b/include/net/irda/crc.h
--- a/include/net/irda/crc.h	Fri Oct 11 21:22:55 2002
+++ b/include/net/irda/crc.h	Fri Oct 11 21:22:55 2002
@@ -28,6 +28,6 @@
 }
 
 /* Recompute the FCS with len bytes appended. */
-unsigned short crc_calc( __u16 fcs, __u8 const *buf, size_t len);
+unsigned short irda_calc_crc16( __u16 fcs, __u8 const *buf, size_t len);
 
 #endif
diff -Nru a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h
--- a/include/net/irda/ircomm_tty.h	Fri Oct 11 21:22:55 2002
+++ b/include/net/irda/ircomm_tty.h	Fri Oct 11 21:22:55 2002
@@ -48,7 +48,9 @@
 /* This is used as an initial value to max_header_size before the proper
  * value is filled in (5 for ttp, 4 for lmp). This allow us to detect
  * the state of the underlying connection. - Jean II */
-#define IRCOMM_TTY_HDR_UNITIALISED	32
+#define IRCOMM_TTY_HDR_UNINITIALISED	16
+/* Same for payload size. See qos.c for the smallest max data size */
+#define IRCOMM_TTY_DATA_UNINITIALISED	(64 - IRCOMM_TTY_HDR_UNINITIALISED)
 
 /*
  * IrCOMM TTY driver state
@@ -83,6 +85,7 @@
 
 	__u32 max_data_size;   /* Max data we can transmit in one packet */
 	__u32 max_header_size; /* The amount of header space we must reserve */
+	__u32 tx_data_size;	/* Max data size of current tx_skb */
 
 	struct iriap_cb *iriap; /* Instance used for querying remote IAS */
 	struct ias_object* obj;
diff -Nru a/include/net/irda/vlsi_ir.h b/include/net/irda/vlsi_ir.h
--- a/include/net/irda/vlsi_ir.h	Fri Oct 11 21:23:00 2002
+++ b/include/net/irda/vlsi_ir.h	Fri Oct 11 21:23:00 2002
@@ -3,9 +3,9 @@
  *
  *	vlsi_ir.h:	VLSI82C147 PCI IrDA controller driver for Linux
  *
- *	Version:	0.3, Sep 30, 2001
+ *	Version:	0.4
  *
- *	Copyright (c) 2001 Martin Diehl
+ *	Copyright (c) 2001-2002 Martin Diehl
  *
  *	This program is free software; you can redistribute it and/or 
  *	modify it under the terms of the GNU General Public License as 
@@ -27,6 +27,26 @@
 #ifndef IRDA_VLSI_FIR_H
 #define IRDA_VLSI_FIR_H
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,4)
+#ifdef CONFIG_PROC_FS
+/* PDE() introduced in 2.5.4 */
+#define PDE(inode) ((inode)->u.generic_ip)
+#endif
+#endif
+
+/*
+ * #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,xx)
+ *
+ * missing pci-dma api call to give streaming dma buffer back to hw
+ * patch floating on lkml - probably present in 2.5.26 or later
+ * otherwise defining it as noop is ok, since the vlsi-ir is only
+ * used on two oldish x86-based notebooks which are cache-coherent
+ */
+#define pci_dma_prep_single(dev, addr, size, direction)	/* nothing */
+/*
+ * #endif
+ */
+
 /* ================================================================ */
 
 /* non-standard PCI registers */
@@ -58,20 +78,20 @@
 
 	/* PLL control */
 
-	CLKCTL_NO_PD		= 0x04,		/* PD# (inverted power down) signal,
-						 * i.e. PLL is powered, if NO_PD set */
+	CLKCTL_PD_INV		= 0x04,		/* PD#: inverted power down signal,
+						 * i.e. PLL is powered, if PD_INV set */
 	CLKCTL_LOCK		= 0x40,		/* (ro) set, if PLL is locked */
 
 	/* clock source selection */
 
-	CLKCTL_EXTCLK		= 0x20,		/* set to select external clock input */
-	CLKCTL_XCKSEL		= 0x10,		/* set to indicate 40MHz EXTCLK, not 48MHz */
+	CLKCTL_EXTCLK		= 0x20,		/* set to select external clock input, not PLL */
+	CLKCTL_XCKSEL		= 0x10,		/* set to indicate EXTCLK is 40MHz, not 48MHz */
 
 	/* IrDA block control */
 
 	CLKCTL_CLKSTP		= 0x80,		/* set to disconnect from selected clock source */
 	CLKCTL_WAKE		= 0x08		/* set to enable wakeup feature: whenever IR activity
-						 * is detected, NO_PD gets set and CLKSTP cleared */
+						 * is detected, PD_INV gets set(?) and CLKSTP cleared */
 };
 
 /* ------------------------------------------ */
@@ -82,10 +102,9 @@
 #define DMA_MASK_MSTRPAGE	0x00ffffff
 #define MSTRPAGE_VALUE		(DMA_MASK_MSTRPAGE >> 24)
 
-
 	/* PCI busmastering is somewhat special for this guy - in short:
 	 *
-	 * We select to operate using MSTRPAGE=0 fixed, use ISA DMA
+	 * We select to operate using fixed MSTRPAGE=0, use ISA DMA
 	 * address restrictions to make the PCI BM api aware of this,
 	 * but ensure the hardware is dealing with real 32bit access.
 	 *
@@ -151,7 +170,6 @@
 	IRMISC_UARTSEL_2e8	= 0x03
 };
 
-
 /* ================================================================ */
 
 /* registers mapped to 32 byte PCI IO space */
@@ -350,22 +368,17 @@
 
 #define	  IRENABLE_MASK	    0xff00  /* Read mask */
 
-
 /* ------------------------------------------ */
 
 /* VLSI_PIO_PHYCTL: IR Physical Layer Current Control Register (u16, ro) */
 
-
 /* read-back of the currently applied physical layer status.
  * applied from VLSI_PIO_NPHYCTL at rising edge of IRENABLE_IREN
  * contents identical to VLSI_PIO_NPHYCTL (see below)
  */
 
-
-
 /* ------------------------------------------ */
 
-
 /* VLSI_PIO_NPHYCTL: IR Physical Layer Next Control Register (u16, rw) */
 
 /* latched during IRENABLE_IREN=0 and applied at 0-1 transition
@@ -382,10 +395,10 @@
  *		fixed for all SIR speeds at 40MHz input clock (PLSWID=24 at 48MHz).
  *		IrPHY also allows shorter pulses down to the nominal pulse duration
  *		at 115.2kbaud (minus some tolerance) which is 1.41 usec.
- *		Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by to for 48MHz)
+ *		Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by two for 48MHz)
  *		we get the minimum acceptable PLSWID values according to the VLSI
  *		specification, which provides 1.5 usec pulse width for all speeds (except
- *		for 2.4kbaud getting 6usec). This is well inside IrPHY v1.3 specs and
+ *		for 2.4kbaud getting 6usec). This is fine with IrPHY v1.3 specs and
  *		reduces the transceiver power which drains the battery. At 9.6kbaud for
  *		example this amounts to more than 90% battery power saving!
  *
@@ -399,7 +412,21 @@
  *		PREAMB = 15
  */
 
-#define BWP_TO_PHYCTL(B,W,P)	((((B)&0x3f)<<10) | (((W)&0x1f)<<5) | (((P)&0x1f)<<0))
+#define PHYCTL_BAUD_SHIFT	10
+#define PHYCTL_BAUD_MASK	0xfc00
+#define PHYCTL_PLSWID_SHIFT	5
+#define PHYCTL_PLSWID_MASK	0x03e0
+#define PHYCTL_PREAMB_SHIFT	0
+#define PHYCTL_PREAMB_MASK	0x001f
+
+#define PHYCTL_TO_BAUD(bwp)	(((bwp)&PHYCTL_BAUD_MASK)>>PHYCTL_BAUD_SHIFT)
+#define PHYCTL_TO_PLSWID(bwp)	(((bwp)&PHYCTL_PLSWID_MASK)>>PHYCTL_PLSWID_SHIFT)
+#define PHYCTL_TO_PREAMB(bwp)	(((bwp)&PHYCTL_PREAMB_MASK)>>PHYCTL_PREAMB_SHIFT)
+
+#define BWP_TO_PHYCTL(b,w,p)	((((b)<<PHYCTL_BAUD_SHIFT)&PHYCTL_BAUD_MASK) \
+				 | (((w)<<PHYCTL_PLSWID_SHIFT)&PHYCTL_PLSWID_MASK) \
+				 | (((p)<<PHYCTL_PREAMB_SHIFT)&PHYCTL_PREAMB_MASK))
+
 #define BAUD_BITS(br)		((115200/(br))-1)
 
 static inline unsigned
@@ -417,7 +444,6 @@
 	return (tmp>0) ? (tmp-1) : 0;
 }
 
-
 #define PHYCTL_SIR(br,ws,cs)	BWP_TO_PHYCTL(BAUD_BITS(br),calc_width_bits((br),(ws),(cs)),0)
 #define PHYCTL_MIR(cs)		BWP_TO_PHYCTL(0,((cs)?9:10),1)
 #define PHYCTL_FIR		BWP_TO_PHYCTL(0,0,15)
@@ -445,42 +471,61 @@
 
 /* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) */
 
-/* specifies the maximum legth (up to 4k - or (4k-1)? - bytes), which a
- * received frame may have - i.e. the size of the corresponding
- * receive buffers. For simplicity we use the same length for
- * receive and submit buffers and increase transfer buffer size
- * byond IrDA-MTU = 2048 so we have sufficient space left when
- * packet size increases during wrapping due to XBOFs and CE's.
- * Even for receiving unwrapped frames we need >MAX_PACKET_LEN
- * space since the controller appends FCS/CRC (2 or 4 bytes)
- * so we use 2*IrDA-MTU for both directions and cover even the
- * worst case, where all data bytes have to be escaped when wrapping.
- * well, this wastes some memory - anyway, later we will
- * either map skb's directly or use pci_pool allocator...
- */
- 
-#define IRDA_MTU	2048		/* seems to be undefined elsewhere */
- 
-#define XFER_BUF_SIZE		(2*IRDA_MTU)
+/* maximum acceptable length for received packets */
 
-#define MAX_PACKET_LENGTH	(XFER_BUF_SIZE-1) /* register uses only [11:0] */
+/* hw imposed limitation - register uses only [11:0] */
+#define MAX_PACKET_LENGTH	0x0fff
 
+/* IrLAP I-field (apparently not defined elsewhere) */
+#define IRDA_MTU		2048
 
-/* ------------------------------------------ */
+/* complete packet consists of A(1)+C(1)+I(<=IRDA_MTU) */
+#define IRLAP_SKB_ALLOCSIZE	(1+1+IRDA_MTU)
+
+/* the buffers we use to exchange frames with the hardware need to be
+ * larger than IRLAP_SKB_ALLOCSIZE because we may have up to 4 bytes FCS
+ * appended and, in SIR mode, a lot of frame wrapping bytes. The worst
+ * case appears to be a SIR packet with I-size==IRDA_MTU and all bytes
+ * requiring to be escaped to provide transparency. Furthermore, the peer
+ * might ask for quite a number of additional XBOFs:
+ *	up to 115+48 XBOFS		 163
+ *	regular BOF			   1
+ *	A-field				   1
+ *	C-field				   1
+ *	I-field, IRDA_MTU, all escaped	4096
+ *	FCS (16 bit at SIR, escaped)	   4
+ *	EOF				   1
+ * AFAICS nothing in IrLAP guarantees A/C field not to need escaping
+ * (f.e. 0xc0/0xc1 - i.e. BOF/EOF - are legal values there) so in the
+ * worst case we have 4269 bytes total frame size.
+ * However, the VLSI uses 12 bits only for all buffer length values,
+ * which limits the maximum useable buffer size <= 4095.
+ * Note this is not a limitation in the receive case because we use
+ * the SIR filtering mode where the hw unwraps the frame and only the
+ * bare packet+fcs is stored into the buffer - in contrast to the SIR
+ * tx case where we have to pass frame-wrapped packets to the hw.
+ * If this would ever become an issue in real life, the only workaround
+ * I see would be using the legacy UART emulation in SIR mode.
+ */
 
+#define XFER_BUF_SIZE		MAX_PACKET_LENGTH
+
+/* ------------------------------------------ */
 
 /* VLSI_PIO_RCVBCNT: Receive Byte Count Register (u16, ro) */
 
-/* recive packet counter gets incremented on every non-filtered
+/* receive packet counter gets incremented on every non-filtered
  * byte which was put in the receive fifo and reset for each
  * new packet. Used to decide whether we are just in the middle
  * of receiving
  */
 
+/* better apply the [11:0] mask when reading, as some docs say the
+ * reserved [15:12] would return 1 when reading - which is wrong AFAICS
+ */
 #define RCVBCNT_MASK	0x0fff
 
-/* ================================================================ */
-
+/******************************************************************/
 
 /* descriptors for rx/tx ring
  *
@@ -494,10 +539,10 @@
  *
  * Attention: Writing addr overwrites status!
  *
- * ### FIXME: we depend on endianess here
+ * ### FIXME: depends on endianess (but there ain't no non-i586 ob800 ;-)
  */
 
-struct ring_descr {
+struct ring_descr_hw {
 	volatile u16	rd_count;	/* tx/rx count [11:0] */
 	u16		reserved;
 	union {
@@ -505,60 +550,168 @@
 		struct {
 			u8		addr_res[3];
 			volatile u8	status;		/* descriptor status */
-		} rd_s;
-	} rd_u;
-};
+		} rd_s __attribute__((packed));
+	} rd_u __attribute((packed));
+} __attribute__ ((packed));
 
 #define rd_addr		rd_u.addr
 #define rd_status	rd_u.rd_s.status
 
-
 /* ring descriptor status bits */
 
-#define RD_STAT_ACTIVE		0x80	/* descriptor owned by hw (both TX,RX) */
+#define RD_ACTIVE		0x80	/* descriptor owned by hw (both TX,RX) */
 
 /* TX ring descriptor status */
 
-#define	TX_STAT_DISCRC		0x40	/* do not send CRC (for SIR) */
-#define	TX_STAT_BADCRC		0x20	/* force a bad CRC */
-#define	TX_STAT_PULSE		0x10	/* send indication pulse after this frame (MIR/FIR) */
-#define	TX_STAT_FRCEUND		0x08	/* force underrun */
-#define	TX_STAT_CLRENTX		0x04	/* clear ENTX after this frame */
-#define	TX_STAT_UNDRN		0x01	/* TX fifo underrun (probably PCI problem) */
+#define	RD_TX_DISCRC		0x40	/* do not send CRC (for SIR) */
+#define	RD_TX_BADCRC		0x20	/* force a bad CRC */
+#define	RD_TX_PULSE		0x10	/* send indication pulse after this frame (MIR/FIR) */
+#define	RD_TX_FRCEUND		0x08	/* force underrun */
+#define	RD_TX_CLRENTX		0x04	/* clear ENTX after this frame */
+#define	RD_TX_UNDRN		0x01	/* TX fifo underrun (probably PCI problem) */
 
 /* RX ring descriptor status */
 
-#define RX_STAT_PHYERR		0x40	/* physical encoding error */
-#define RX_STAT_CRCERR		0x20	/* CRC error (MIR/FIR) */
-#define RX_STAT_LENGTH		0x10	/* frame exceeds buffer length */
-#define RX_STAT_OVER		0x08	/* RX fifo overrun (probably PCI problem) */
-#define RX_STAT_SIRBAD		0x04	/* EOF missing: BOF follows BOF (SIR, filtered) */
-
+#define RD_RX_PHYERR		0x40	/* physical encoding error */
+#define RD_RX_CRCERR		0x20	/* CRC error (MIR/FIR) */
+#define RD_RX_LENGTH		0x10	/* frame exceeds buffer length */
+#define RD_RX_OVER		0x08	/* RX fifo overrun (probably PCI problem) */
+#define RD_RX_SIRBAD		0x04	/* EOF missing: BOF follows BOF (SIR, filtered) */
 
-#define RX_STAT_ERROR		0x7c	/* any error in frame */
+#define RD_RX_ERROR		0x7c	/* any error in received frame */
 
+/* the memory required to hold the 2 descriptor rings */
+#define HW_RING_AREA_SIZE	(2 * MAX_RING_DESCR * sizeof(struct ring_descr_hw))
 
-/* ------------------------------------------ */
+/******************************************************************/
 
-/* contains the objects we've put into the ring descriptors
- * static buffers for now - probably skb's later
+/* sw-ring descriptors consists of a bus-mapped transfer buffer with
+ * associated skb and a pointer to the hw entry descriptor
  */
 
-struct ring_entry {
-	struct sk_buff	*skb;
-	void		*data;
+struct ring_descr {
+	struct ring_descr_hw	*hw;
+	struct sk_buff		*skb;
+	void			*buf;
 };
 
+/* wrappers for operations on hw-exposed ring descriptors
+ * access to the hw-part of the descriptors must use these.
+ */
+
+static inline int rd_is_active(struct ring_descr *rd)
+{
+	return ((rd->hw->rd_status & RD_ACTIVE) != 0);
+}
+
+static inline void rd_activate(struct ring_descr *rd)
+{
+	rd->hw->rd_status |= RD_ACTIVE;
+}
+
+static inline void rd_set_status(struct ring_descr *rd, u8 s)
+{
+	rd->hw->rd_status = s;	 /* may pass ownership to the hardware */
+}
+
+static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s)
+{
+	/* order is important for two reasons:
+	 *  - overlayed: writing addr overwrites status
+	 *  - we want to write status last so we have valid address in
+	 *    case status has RD_ACTIVE set
+	 */
+
+	if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) {
+		BUG();
+		return;
+	}
+
+	a &= DMA_MASK_MSTRPAGE;  /* clear highbyte to make sure we won't write
+				  * to status - just in case MSTRPAGE_VALUE!=0
+				  */
+	rd->hw->rd_addr = a;
+	wmb();
+	rd_set_status(rd, s);	 /* may pass ownership to the hardware */
+}
+
+static inline void rd_set_count(struct ring_descr *rd, u16 c)
+{
+	rd->hw->rd_count = c;
+}
+
+static inline u8 rd_get_status(struct ring_descr *rd)
+{
+	return rd->hw->rd_status;
+}
+
+static inline dma_addr_t rd_get_addr(struct ring_descr *rd)
+{
+	dma_addr_t	a;
+
+	a = (rd->hw->rd_addr & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24);
+	return a;
+}
+
+static inline u16 rd_get_count(struct ring_descr *rd)
+{
+	return rd->hw->rd_count;
+}
+
+/******************************************************************/
+
+/* sw descriptor rings for rx, tx:
+ *
+ * operations follow producer-consumer paradigm, with the hw
+ * in the middle doing the processing.
+ * ring size must be power of two.
+ *
+ * producer advances r->tail after inserting for processing
+ * consumer advances r->head after removing processed rd
+ * ring is empty if head==tail / full if (tail+1)==head
+ */
 
 struct vlsi_ring {
+	struct pci_dev		*pdev;
+	int			dir;
+	unsigned		len;
 	unsigned		size;
 	unsigned		mask;
-	unsigned		head, tail;
-	struct ring_descr	*hw;
-	struct ring_entry	buf[MAX_RING_DESCR];
+	atomic_t		head, tail;
+	struct ring_descr	*rd;
 };
 
-/* ------------------------------------------ */
+/* ring processing helpers */
+
+static inline struct ring_descr *ring_last(struct vlsi_ring *r)
+{
+	int t;
+
+	t = atomic_read(&r->tail) & r->mask;
+	return (((t+1) & r->mask) == (atomic_read(&r->head) & r->mask)) ? NULL : &r->rd[t];
+}
+
+static inline struct ring_descr *ring_put(struct vlsi_ring *r)
+{
+	atomic_inc(&r->tail);
+	return ring_last(r);
+}
+
+static inline struct ring_descr *ring_first(struct vlsi_ring *r)
+{
+	int h;
+
+	h = atomic_read(&r->head) & r->mask;
+	return (h == (atomic_read(&r->tail) & r->mask)) ? NULL : &r->rd[h];
+}
+
+static inline struct ring_descr *ring_get(struct vlsi_ring *r)
+{
+	atomic_inc(&r->head);
+	return ring_first(r);
+}
+
+/******************************************************************/
 
 /* our private compound VLSI-PCI-IRDA device information */
 
@@ -575,13 +728,38 @@
 
 	dma_addr_t		busaddr;
 	void			*virtaddr;
-	struct vlsi_ring	tx_ring, rx_ring;
+	struct vlsi_ring	*tx_ring, *rx_ring;
 
 	struct timeval		last_rx;
 
 	spinlock_t		lock;
-	
+	struct semaphore	sem;
+
+	u32			cfg_space[64/sizeof(u32)];
+	u8			resume_ok;	
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry	*proc_entry;
+#endif
+
 } vlsi_irda_dev_t;
+
+/********************************************************/
+
+/* the remapped error flags we use for returning from frame
+ * post-processing in vlsi_process_tx/rx() after it was completed
+ * by the hardware. These functions either return the >=0 number
+ * of transfered bytes in case of success or the negative (-)
+ * of the or'ed error flags.
+ */
+
+#define VLSI_TX_DROP		0x0001
+#define VLSI_TX_FIFO		0x0002
+
+#define VLSI_RX_DROP		0x0100
+#define VLSI_RX_OVER		0x0200
+#define VLSI_RX_LENGTH  	0x0400
+#define VLSI_RX_FRAME		0x0800
+#define VLSI_RX_CRC		0x1000
 
 /********************************************************/
 
diff -Nru a/include/net/protocol.h b/include/net/protocol.h
--- a/include/net/protocol.h	Fri Oct 11 21:22:56 2002
+++ b/include/net/protocol.h	Fri Oct 11 21:22:56 2002
@@ -30,7 +30,7 @@
 #include <linux/ipv6.h>
 #endif
 
-#define MAX_INET_PROTOS	32		/* Must be a power of 2		*/
+#define MAX_INET_PROTOS	256		/* Must be a power of 2		*/
 
 
 /* This is used to register protocols. */
@@ -38,11 +38,6 @@
 {
 	int			(*handler)(struct sk_buff *skb);
 	void			(*err_handler)(struct sk_buff *skb, u32 info);
-	struct inet_protocol	*next;
-	unsigned char		protocol;
-	unsigned char		copy:1;
-	void			*data;
-	const char		*name;
 };
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -54,11 +49,6 @@
 			       struct inet6_skb_parm *opt,
 			       int type, int code, int offset,
 			       __u32 info);
-	struct inet6_protocol *next;
-	unsigned char	protocol;
-	unsigned char	copy:1;
-	void		*data;
-	const char	*name;
 };
 
 #endif
@@ -93,14 +83,14 @@
 extern struct list_head inetsw6[SOCK_MAX];
 #endif
 
-extern void	inet_add_protocol(struct inet_protocol *prot);
-extern int	inet_del_protocol(struct inet_protocol *prot);
+extern int	inet_add_protocol(struct inet_protocol *prot, unsigned char num);
+extern int	inet_del_protocol(struct inet_protocol *prot, unsigned char num);
 extern void	inet_register_protosw(struct inet_protosw *p);
 extern void	inet_unregister_protosw(struct inet_protosw *p);
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-extern void	inet6_add_protocol(struct inet6_protocol *prot);
-extern int	inet6_del_protocol(struct inet6_protocol *prot);
+extern int	inet6_add_protocol(struct inet6_protocol *prot, unsigned char num);
+extern int	inet6_del_protocol(struct inet6_protocol *prot, unsigned char num);
 extern void	inet6_register_protosw(struct inet_protosw *p);
 extern void	inet6_unregister_protosw(struct inet_protosw *p);
 #endif
diff -Nru a/include/net/raw.h b/include/net/raw.h
--- a/include/net/raw.h	Fri Oct 11 21:23:04 2002
+++ b/include/net/raw.h	Fri Oct 11 21:23:04 2002
@@ -37,6 +37,6 @@
 				    unsigned long raddr, unsigned long laddr,
 				    int dif);
 
-extern struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
+extern void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
 
 #endif	/* _RAW_H */
diff -Nru a/include/net/rawv6.h b/include/net/rawv6.h
--- a/include/net/rawv6.h	Fri Oct 11 21:22:56 2002
+++ b/include/net/rawv6.h	Fri Oct 11 21:22:56 2002
@@ -7,9 +7,7 @@
 extern struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
 extern rwlock_t raw_v6_lock;
 
-extern struct sock * ipv6_raw_deliver(struct sk_buff *skb,
-				      int nexthdr);
-
+extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
 
 extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
 				    struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
--- a/include/net/sctp/sctp.h	Fri Oct 11 21:22:55 2002
+++ b/include/net/sctp/sctp.h	Fri Oct 11 21:22:55 2002
@@ -198,7 +198,6 @@
 #define sctp_release_sock(sk) release_sock(sk)
 #define sctp_bh_lock_sock(sk) bh_lock_sock(sk)
 #define sctp_bh_unlock_sock(sk) bh_unlock_sock(sk)
-#define __sctp_sock_busy(sk) ((sk)->lock.users)
 #define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk)
 #define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk)
 
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Fri Oct 11 21:23:02 2002
+++ b/include/net/sock.h	Fri Oct 11 21:23:02 2002
@@ -70,15 +70,16 @@
  * between user contexts and software interrupt processing, whereas the
  * mini-semaphore synchronizes multiple users amongst themselves.
  */
+struct sock_iocb;
 typedef struct {
 	spinlock_t		slock;
-	unsigned int		users;
+	struct sock_iocb	*owner;
 	wait_queue_head_t	wq;
 } socket_lock_t;
 
 #define sock_lock_init(__sk) \
 do {	spin_lock_init(&((__sk)->lock.slock)); \
-	(__sk)->lock.users = 0; \
+	(__sk)->lock.owner = NULL; \
 	init_waitqueue_head(&((__sk)->lock.wq)); \
 } while(0)
 
@@ -308,12 +309,13 @@
  */
 extern void __lock_sock(struct sock *sk);
 extern void __release_sock(struct sock *sk);
+#define sock_owned_by_user(sk)	(NULL != (sk)->lock.owner)
 #define lock_sock(__sk) \
 do {	might_sleep(); \
 	spin_lock_bh(&((__sk)->lock.slock)); \
-	if ((__sk)->lock.users != 0) \
+	if ((__sk)->lock.owner != NULL) \
 		__lock_sock(__sk); \
-	(__sk)->lock.users = 1; \
+	(__sk)->lock.owner = (void *)1; \
 	spin_unlock_bh(&((__sk)->lock.slock)); \
 } while(0)
 
@@ -321,7 +323,7 @@
 do {	spin_lock_bh(&((__sk)->lock.slock)); \
 	if ((__sk)->backlog.tail != NULL) \
 		__release_sock(__sk); \
-	(__sk)->lock.users = 0; \
+	(__sk)->lock.owner = NULL; \
         if (waitqueue_active(&((__sk)->lock.wq))) wake_up(&((__sk)->lock.wq)); \
 	spin_unlock_bh(&((__sk)->lock.slock)); \
 } while(0)
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h	Fri Oct 11 21:22:53 2002
+++ b/include/net/tcp.h	Fri Oct 11 21:22:53 2002
@@ -1348,7 +1348,7 @@
 		if (tp->ucopy.memory > sk->rcvbuf) {
 			struct sk_buff *skb1;
 
-			if (sk->lock.users) BUG();
+			if (sock_owned_by_user(sk)) BUG();
 
 			while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) {
 				sk->backlog_rcv(sk, skb1);
diff -Nru a/init/Makefile b/init/Makefile
--- a/init/Makefile	Fri Oct 11 21:22:55 2002
+++ b/init/Makefile	Fri Oct 11 21:22:55 2002
@@ -17,4 +17,4 @@
 
 $(objtree)/include/linux/compile.h: FORCE
 	@echo -n '  Generating $@'
-	@$(srctree)/scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
+	@sh $(srctree)/scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
diff -Nru a/ipc/msg.c b/ipc/msg.c
--- a/ipc/msg.c	Fri Oct 11 21:22:50 2002
+++ b/ipc/msg.c	Fri Oct 11 21:22:50 2002
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/list.h>
+#include <linux/security.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -89,6 +90,7 @@
 static int newque (key_t key, int msgflg)
 {
 	int id;
+	int retval;
 	struct msg_queue *msq;
 
 	msq  = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
@@ -98,8 +100,16 @@
 	msq->q_perm.mode = (msgflg & S_IRWXUGO);
 	msq->q_perm.key = key;
 
+	msq->q_perm.security = NULL;
+	retval = security_ops->msg_queue_alloc_security(msq);
+	if (retval) {
+		kfree(msq);
+		return retval;
+	}
+
 	id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
 	if(id == -1) {
+		security_ops->msg_queue_free_security(msq);
 		kfree(msq);
 		return -ENOSPC;
 	}
@@ -271,6 +281,7 @@
 		free_msg(msg);
 	}
 	atomic_sub(msq->q_cbytes, &msg_bytes);
+	security_ops->msg_queue_free_security(msq);
 	kfree(msq);
 }
 
diff -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c	Fri Oct 11 21:22:55 2002
+++ b/ipc/sem.c	Fri Oct 11 21:22:55 2002
@@ -63,6 +63,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/security.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -115,6 +116,7 @@
 static int newary (key_t key, int nsems, int semflg)
 {
 	int id;
+	int retval;
 	struct sem_array *sma;
 	int size;
 
@@ -133,8 +135,16 @@
 	sma->sem_perm.mode = (semflg & S_IRWXUGO);
 	sma->sem_perm.key = key;
 
+	sma->sem_perm.security = NULL;
+	retval = security_ops->sem_alloc_security(sma);
+	if (retval) {
+		ipc_free(sma, size);
+		return retval;
+	}
+
 	id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
 	if(id == -1) {
+		security_ops->sem_free_security(sma);
 		ipc_free(sma, size);
 		return -ENOSPC;
 	}
@@ -417,6 +427,7 @@
 
 	used_sems -= sma->sem_nsems;
 	size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
+	security_ops->sem_free_security(sma);
 	ipc_free(sma, size);
 }
 
diff -Nru a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c	Fri Oct 11 21:22:58 2002
+++ b/ipc/shm.c	Fri Oct 11 21:22:58 2002
@@ -24,6 +24,7 @@
 #include <linux/mman.h>
 #include <linux/proc_fs.h>
 #include <linux/shmem_fs.h>
+#include <linux/security.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
@@ -115,6 +116,7 @@
 	shm_unlock(shp->id);
 	shmem_lock(shp->shm_file, 0);
 	fput (shp->shm_file);
+	security_ops->shm_free_security(shp);
 	kfree (shp);
 }
 
@@ -185,6 +187,13 @@
 	shp->shm_perm.key = key;
 	shp->shm_flags = (shmflg & S_IRWXUGO);
 
+	shp->shm_perm.security = NULL;
+	error = security_ops->shm_alloc_security(shp);
+	if (error) {
+		kfree(shp);
+		return error;
+	}
+
 	sprintf (name, "SYSV%08x", key);
 	file = shmem_file_setup(name, size, VM_ACCOUNT);
 	error = PTR_ERR(file);
@@ -213,6 +222,7 @@
 no_id:
 	fput(file);
 no_file:
+	security_ops->shm_free_security(shp);
 	kfree(shp);
 	return error;
 }
diff -Nru a/ipc/util.c b/ipc/util.c
--- a/ipc/util.c	Fri Oct 11 21:22:55 2002
+++ b/ipc/util.c	Fri Oct 11 21:22:55 2002
@@ -19,6 +19,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/highuid.h>
+#include <linux/security.h>
 
 #if defined(CONFIG_SYSVIPC)
 
@@ -263,7 +264,7 @@
 	    !capable(CAP_IPC_OWNER))
 		return -1;
 
-	return 0;
+	return security_ops->ipc_permission(ipcp, flag);
 }
 
 /*
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Fri Oct 11 21:22:53 2002
+++ b/kernel/fork.c	Fri Oct 11 21:22:53 2002
@@ -165,12 +165,14 @@
 	 * of memory.
 	 */
 	max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8;
-
 	/*
-	 * we need to allow at least 10 threads to boot a system
+	 * we need to allow at least 20 threads to boot a system
 	 */
-	init_task.rlim[RLIMIT_NPROC].rlim_cur = max(10, max_threads/2);
-	init_task.rlim[RLIMIT_NPROC].rlim_max = max(10, max_threads/2);
+	if(max_threads < 20)
+		max_threads = 20;
+
+	init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
+	init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
 }
 
 static struct task_struct *dup_task_struct(struct task_struct *orig)
diff -Nru a/kernel/futex.c b/kernel/futex.c
--- a/kernel/futex.c	Fri Oct 11 21:22:55 2002
+++ b/kernel/futex.c	Fri Oct 11 21:22:55 2002
@@ -468,6 +468,7 @@
 static struct file_system_type futex_fs_type = {
 	.name		= "futexfs",
 	.get_sb		= futexfs_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 static int __init init(void)
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Fri Oct 11 21:22:51 2002
+++ b/kernel/ksyms.c	Fri Oct 11 21:22:51 2002
@@ -90,7 +90,6 @@
 
 /* internal kernel memory management */
 EXPORT_SYMBOL(__alloc_pages);
-EXPORT_SYMBOL(alloc_pages_node);
 EXPORT_SYMBOL(__get_free_pages);
 EXPORT_SYMBOL(get_zeroed_page);
 EXPORT_SYMBOL(__page_cache_release);
@@ -304,6 +303,12 @@
 EXPORT_SYMBOL(simple_lookup);
 EXPORT_SYMBOL(simple_dir_operations);
 EXPORT_SYMBOL(simple_dir_inode_operations);
+EXPORT_SYMBOL(simple_link);
+EXPORT_SYMBOL(simple_unlink);
+EXPORT_SYMBOL(simple_rmdir);
+EXPORT_SYMBOL(simple_rename);
+EXPORT_SYMBOL(simple_sync_file);
+EXPORT_SYMBOL(simple_empty);
 EXPORT_SYMBOL(fd_install);
 EXPORT_SYMBOL(put_unused_fd);
 EXPORT_SYMBOL(get_sb_bdev);
@@ -601,6 +606,8 @@
 EXPORT_SYMBOL(init_thread_union);
 
 EXPORT_SYMBOL(tasklist_lock);
+EXPORT_SYMBOL(find_task_by_pid);
+EXPORT_SYMBOL(next_thread);
 #if defined(CONFIG_SMP) && defined(__GENERIC_PER_CPU)
 EXPORT_SYMBOL(__per_cpu_offset);
 #endif
diff -Nru a/kernel/printk.c b/kernel/printk.c
--- a/kernel/printk.c	Fri Oct 11 21:23:05 2002
+++ b/kernel/printk.c	Fri Oct 11 21:23:05 2002
@@ -30,7 +30,7 @@
 
 #include <asm/uaccess.h>
 
-#if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64)
+#if defined(CONFIG_X86_NUMAQ) || defined(CONFIG_IA64)
 #define LOG_BUF_LEN	(65536)
 #elif defined(CONFIG_ARCH_S390)
 #define LOG_BUF_LEN	(131072)
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Fri Oct 11 21:23:03 2002
+++ b/kernel/sched.c	Fri Oct 11 21:23:03 2002
@@ -1953,7 +1953,6 @@
 		BUG();
 #endif
 
-	preempt_disable();
 	rq = task_rq_lock(p, &flags);
 	p->cpus_allowed = new_mask;
 	/*
@@ -1962,7 +1961,7 @@
 	 */
 	if (new_mask & (1UL << task_cpu(p))) {
 		task_rq_unlock(rq, &flags);
-		goto out;
+		return;
 	}
 	/*
 	 * If the task is not on a runqueue (and not running), then
@@ -1971,17 +1970,16 @@
 	if (!p->array && !task_running(rq, p)) {
 		set_task_cpu(p, __ffs(p->cpus_allowed));
 		task_rq_unlock(rq, &flags);
-		goto out;
+		return;
 	}
 	init_completion(&req.done);
 	req.task = p;
 	list_add(&req.list, &rq->migration_queue);
 	task_rq_unlock(rq, &flags);
+
 	wake_up_process(rq->migration_thread);
 
 	wait_for_completion(&req.done);
-out:
-	preempt_enable();
 }
 
 /*
@@ -1999,22 +1997,18 @@
 	sigfillset(&current->blocked);
 	set_fs(KERNEL_DS);
 
-	set_cpus_allowed(current, 1UL << cpu);
-
 	/*
-	 * Migration can happen without a migration thread on the
-	 * target CPU because here we remove the thread from the
-	 * runqueue and the helper thread then moves this thread
-	 * to the target CPU - we'll wake up there.
+	 * Either we are running on the right CPU, or there's a
+	 * a migration thread on the target CPU, guaranteed.
 	 */
-	if (smp_processor_id() != cpu)
-	printk("migration_task %d on cpu=%d\n", cpu, smp_processor_id());
+	set_cpus_allowed(current, 1UL << cpu);
+
 	ret = setscheduler(0, SCHED_FIFO, &param);
 
 	rq = this_rq();
 	rq->migration_thread = current;
 
-	sprintf(current->comm, "migration_CPU%d", smp_processor_id());
+	sprintf(current->comm, "migration/%d", smp_processor_id());
 
 	for (;;) {
 		runqueue_t *rq_src, *rq_dest;
@@ -2055,6 +2049,8 @@
 			if (p->array) {
 				deactivate_task(p, rq_src);
 				activate_task(p, rq_dest);
+				if (p->prio < rq_dest->curr->prio)
+					resched_task(rq_dest->curr);
 			}
 		}
 		double_rq_unlock(rq_src, rq_dest);
diff -Nru a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c	Fri Oct 11 21:22:54 2002
+++ b/kernel/softirq.c	Fri Oct 11 21:22:54 2002
@@ -31,7 +31,7 @@
    - Tasklets: serialized wrt itself.
  */
 
-irq_cpustat_t irq_stat[NR_CPUS];
+irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;
 
 static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;
 
@@ -280,7 +280,7 @@
 	if (smp_processor_id() != cpu)
 		BUG();
 
-	sprintf(current->comm, "ksoftirqd_CPU%d", cpu);
+	sprintf(current->comm, "ksoftirqd/%d", cpu);
 
 	__set_current_state(TASK_INTERRUPTIBLE);
 	mb();
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Fri Oct 11 21:22:54 2002
+++ b/kernel/suspend.c	Fri Oct 11 21:22:54 2002
@@ -393,7 +393,7 @@
 	int i;
 	swp_entry_t entry, prev = { 0 };
 	int nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
-	union diskpage *cur,  *buffer = (union diskpage *)get_free_page(GFP_ATOMIC);
+	union diskpage *cur,  *buffer = (union diskpage *)get_zeroed_page(GFP_ATOMIC);
 	unsigned long address;
 	struct page *page;
 
@@ -554,7 +554,7 @@
 		SetPageNosave(page++);
 		
 	while(nr_copy_pages--) {
-		p->address = get_free_page(GFP_ATOMIC);
+		p->address = get_zeroed_page(GFP_ATOMIC);
 		if(!p->address) {
 			free_suspend_pagedir((unsigned long) pagedir);
 			return NULL;
@@ -923,7 +923,7 @@
 		unsigned long addr;
 
 		do {
-			addr = get_free_page(GFP_ATOMIC);
+			addr = get_zeroed_page(GFP_ATOMIC);
 			if(!addr)
 				return -ENOMEM;
 		} while (does_collide(addr));
@@ -1139,7 +1139,7 @@
 	int error;
 
 	resume_device = name_to_kdev_t(specialfile);
-	scratch_page = get_free_page(GFP_ATOMIC);
+	scratch_page = get_zeroed_page(GFP_ATOMIC);
 	cur = (void *) scratch_page;
 	if (cur) {
 		struct block_device *bdev;
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Fri Oct 11 21:22:53 2002
+++ b/kernel/sysctl.c	Fri Oct 11 21:22:53 2002
@@ -88,8 +88,8 @@
 extern int sysctl_userprocess_debug;
 #endif
 
-#ifdef CONFIG_PPC32
-extern unsigned long zero_paged_on, powersave_nap;
+#if defined(CONFIG_PPC32) && defined(CONFIG_6xx)
+extern unsigned long powersave_nap;
 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp);
 #endif
@@ -190,9 +190,7 @@
 	{KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
 	 0644, NULL, &proc_dointvec},
 #endif
-#ifdef CONFIG_PPC32
-	{KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
-	 0644, NULL, &proc_dointvec},
+#if defined(CONFIG_PPC32) && defined(CONFIG_6xx)
 	{KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_PPC_L2CR, "l2cr", NULL, 0,
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Fri Oct 11 21:22:55 2002
+++ b/kernel/timer.c	Fri Oct 11 21:22:55 2002
@@ -266,29 +266,31 @@
 int del_timer_sync(timer_t *timer)
 {
 	tvec_base_t *base = tvec_bases;
-	int i, ret;
+	int i, ret = 0;
 
-	ret = del_timer(timer);
+del_again:
+	ret += del_timer(timer);
 
-	for (i = 0; i < NR_CPUS; i++) {
+	for (i = 0; i < NR_CPUS; i++, base++) {
 		if (!cpu_online(i))
 			continue;
 		if (base->running_timer == timer) {
 			while (base->running_timer == timer) {
 				cpu_relax();
-				preempt_disable();
-				preempt_enable();
+				preempt_check_resched();
 			}
 			break;
 		}
-		base++;
 	}
+	if (timer_pending(timer))
+		goto del_again;
+
 	return ret;
 }
 #endif
 
 
-static void cascade(tvec_base_t *base, tvec_t *tv)
+static int cascade(tvec_base_t *base, tvec_t *tv)
 {
 	/* cascade all the timers from tv up one level */
 	struct list_head *head, *curr, *next;
@@ -310,7 +312,8 @@
 		curr = next;
 	}
 	INIT_LIST_HEAD(head);
-	tv->index = (tv->index + 1) & TVN_MASK;
+
+	return tv->index = (tv->index + 1) & TVN_MASK;
 }
 
 /***
@@ -322,26 +325,18 @@
  */
 static inline void __run_timers(tvec_base_t *base)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&base->lock, flags);
+	spin_lock_irq(&base->lock);
 	while ((long)(jiffies - base->timer_jiffies) >= 0) {
 		struct list_head *head, *curr;
 
 		/*
 		 * Cascade timers:
 		 */
-		if (!base->tv1.index) {
-			cascade(base, &base->tv2);
-			if (base->tv2.index == 1) {
-				cascade(base, &base->tv3);
-				if (base->tv3.index == 1) {
-					cascade(base, &base->tv4);
-					if (base->tv4.index == 1)
-						cascade(base, &base->tv5);
-				}
-			}
-		}
+		if (!base->tv1.index &&
+			(cascade(base, &base->tv2) == 1) &&
+				(cascade(base, &base->tv3) == 1) &&
+					cascade(base, &base->tv4) == 1)
+			cascade(base, &base->tv5);
 repeat:
 		head = base->tv1.vec + base->tv1.index;
 		curr = head->next;
@@ -360,7 +355,10 @@
 			base->running_timer = timer;
 #endif
 			spin_unlock_irq(&base->lock);
-			fn(data);
+			if (!fn)
+				printk("Bad: timer %p has NULL fn. (data: %08lx)\n", timer, data);
+			else
+				fn(data);
 			spin_lock_irq(&base->lock);
 			goto repeat;
 		}
@@ -370,7 +368,7 @@
 #if CONFIG_SMP
 	base->running_timer = NULL;
 #endif
-	spin_unlock_irqrestore(&base->lock, flags);
+	spin_unlock_irq(&base->lock);
 }
 
 /******************************************************************/
@@ -798,10 +796,18 @@
  * The Alpha uses getxpid, getxuid, and getxgid instead.  Maybe this
  * should be moved into arch/i386 instead?
  */
- 
+
+/**
+ * sys_getpid - return the thread group id of the current process
+ *
+ * Note, despite the name, this returns the tgid not the pid.  The tgid and
+ * the pid are identical unless CLONE_THREAD was specified on clone() in
+ * which case the tgid is the same in all threads of the same group.
+ *
+ * This is SMP safe as current->tgid does not change.
+ */
 asmlinkage long sys_getpid(void)
 {
-	/* This is SMP safe - current->pid doesn't change */
 	return current->tgid;
 }
 
diff -Nru a/lib/brlock.c b/lib/brlock.c
--- a/lib/brlock.c	Fri Oct 11 21:23:02 2002
+++ b/lib/brlock.c	Fri Oct 11 21:23:02 2002
@@ -24,8 +24,9 @@
 {
 	int i;
 
+	preempt_disable();
 	for (i = 0; i < NR_CPUS; i++)
-		write_lock(&__brlock_array[i][idx]);
+		_raw_write_lock(&__brlock_array[i][idx]);
 }
 
 void __br_write_unlock (enum brlock_indices idx)
@@ -33,7 +34,8 @@
 	int i;
 
 	for (i = 0; i < NR_CPUS; i++)
-		write_unlock(&__brlock_array[i][idx]);
+		_raw_write_unlock(&__brlock_array[i][idx]);
+	preempt_enable();
 }
 
 #else /* ! __BRLOCK_USE_ATOMICS */
@@ -48,11 +50,12 @@
 {
 	int i;
 
+	preempt_disable();
 again:
-	spin_lock(&__br_write_locks[idx].lock);
+	_raw_spin_lock(&__br_write_locks[idx].lock);
 	for (i = 0; i < NR_CPUS; i++)
 		if (__brlock_array[i][idx] != 0) {
-			spin_unlock(&__br_write_locks[idx].lock);
+			_raw_spin_unlock(&__br_write_locks[idx].lock);
 			barrier();
 			cpu_relax();
 			goto again;
diff -Nru a/lib/radix-tree.c b/lib/radix-tree.c
--- a/lib/radix-tree.c	Fri Oct 11 21:22:54 2002
+++ b/lib/radix-tree.c	Fri Oct 11 21:22:54 2002
@@ -77,7 +77,6 @@
 	return index;
 }
 
-
 /*
  *	Extend a radix tree so it can store key @index.
  */
@@ -109,16 +108,15 @@
 	return 0;
 }
 
-
 /**
- *	radix_tree_reserve    -    reserve space in a radix tree
+ *	radix_tree_insert    -    insert into a radix tree
  *	@root:		radix tree root
  *	@index:		index key
- *	@pslot:		pointer to reserved slot
+ *	@item:		item to insert
  *
- *	Reserve a slot in a radix tree for the key @index.
+ *	Insert an item into the radix tree at position @index.
  */
-int radix_tree_reserve(struct radix_tree_root *root, unsigned long index, void ***pslot)
+int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
 {
 	struct radix_tree_node *node = NULL, *tmp, **slot;
 	unsigned int height, shift;
@@ -158,36 +156,11 @@
 	if (node)
 		node->count++;
 
-	*pslot = (void **)slot;
-	**pslot = RADIX_TREE_SLOT_RESERVED;
+	*slot = item;
 	return 0;
 }
-
-EXPORT_SYMBOL(radix_tree_reserve);
-
-
-/**
- *	radix_tree_insert    -    insert into a radix tree
- *	@root:		radix tree root
- *	@index:		index key
- *	@item:		item to insert
- *
- *	Insert an item into the radix tree at position @index.
- */
-int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
-{
-	void **slot;
-	int error;
-
-	error = radix_tree_reserve(root, index, &slot);
-	if (!error)
-		*slot = item;
-	return error;
-}
-
 EXPORT_SYMBOL(radix_tree_insert);
 
-
 /**
  *	radix_tree_lookup    -    perform lookup operation on a radix tree
  *	@root:		radix tree root
@@ -267,8 +240,8 @@
 out:
 	*next_index = index;
 	return nr_found;
-	
 }
+
 /**
  *	radix_tree_gang_lookup - perform multiple lookup on a radix tree
  *	@root:		radix tree root
@@ -371,7 +344,6 @@
 
 	return 0;
 }
-
 EXPORT_SYMBOL(radix_tree_delete);
 
 static void radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
diff -Nru a/lib/rbtree.c b/lib/rbtree.c
--- a/lib/rbtree.c	Fri Oct 11 21:23:00 2002
+++ b/lib/rbtree.c	Fri Oct 11 21:23:00 2002
@@ -296,6 +296,22 @@
 }
 EXPORT_SYMBOL(rb_erase);
 
+/*
+ * This function returns the first node (in sort order) of the tree.
+ */
+struct rb_node *rb_first(struct rb_root *root)
+{
+	struct rb_node	*n;
+
+	n = root->rb_node;
+	if (!n)
+		return 0;
+	while (n->rb_left)
+		n = n->rb_left;
+	return n;
+}
+EXPORT_SYMBOL(rb_first);
+
 struct rb_node *rb_next(struct rb_node *node)
 {
 	/* If we have a right-hand child, go down and then left as far
diff -Nru a/mm/Makefile b/mm/Makefile
--- a/mm/Makefile	Fri Oct 11 21:23:00 2002
+++ b/mm/Makefile	Fri Oct 11 21:23:00 2002
@@ -2,12 +2,11 @@
 # Makefile for the linux memory manager.
 #
 
-export-objs := shmem.o filemap.o mempool.o page_alloc.o \
-		page-writeback.o
+export-objs := shmem.o filemap.o mempool.o page_alloc.o page-writeback.o
 
 obj-y	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
-	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
+	    page_alloc.o swap_state.o swapfile.o oom_kill.o \
 	    shmem.o highmem.o mempool.o msync.o mincore.o readahead.o \
 	    pdflush.o page-writeback.o rmap.o madvise.o vcache.o \
 	    truncate.o
diff -Nru a/mm/bootmem.c b/mm/bootmem.c
--- a/mm/bootmem.c	Fri Oct 11 21:22:55 2002
+++ b/mm/bootmem.c	Fri Oct 11 21:22:55 2002
@@ -311,6 +311,7 @@
 	return(free_all_bootmem_core(pgdat));
 }
 
+#ifndef CONFIG_DISCONTIGMEM
 unsigned long __init init_bootmem (unsigned long start, unsigned long pages)
 {
 	max_low_pfn = pages;
@@ -334,6 +335,7 @@
 {
 	return(free_all_bootmem_core(&contig_page_data));
 }
+#endif /* !CONFIG_DISCONTIGMEM */
 
 void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
 {
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Fri Oct 11 21:22:55 2002
+++ b/mm/filemap.c	Fri Oct 11 21:22:55 2002
@@ -885,11 +885,12 @@
 }
 
 ssize_t
-generic_file_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t *ppos)
+generic_file_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos)
 {
 	struct iovec local_iov = { .iov_base = buf, .iov_len = count };
 
-	return __generic_file_aio_read(iocb, &local_iov, 1, ppos);
+	BUG_ON(iocb->ki_pos != pos);
+	return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos);
 }
 
 ssize_t
@@ -1643,6 +1644,12 @@
 	pagevec_lru_add(&lru_pvec);
 	current->backing_dev_info = 0;
 	return err;
+}
+
+ssize_t generic_file_aio_write(struct kiocb *iocb, const char *buf,
+			       size_t count, loff_t pos)
+{
+	return generic_file_write(iocb->ki_filp, buf, count, &iocb->ki_pos);
 }
 
 ssize_t generic_file_write(struct file *file, const char *buf,
diff -Nru a/mm/mremap.c b/mm/mremap.c
--- a/mm/mremap.c	Fri Oct 11 21:22:59 2002
+++ b/mm/mremap.c	Fri Oct 11 21:22:59 2002
@@ -194,7 +194,8 @@
 				prev->vm_end = next->vm_end;
 				__vma_unlink(mm, next, prev);
 				spin_unlock(&mm->page_table_lock);
-
+				if (vma == next)
+					vma = prev;
 				mm->map_count--;
 				kmem_cache_free(vm_area_cachep, next);
 			}
diff -Nru a/mm/numa.c b/mm/numa.c
--- a/mm/numa.c	Fri Oct 11 21:23:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,89 +0,0 @@
-/*
- * Written by Kanoj Sarcar, SGI, Aug 1999
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/mmzone.h>
-#include <linux/spinlock.h>
-
-int numnodes = 1;	/* Initialized for UMA platforms */
-
-static bootmem_data_t contig_bootmem_data;
-pg_data_t contig_page_data = { .bdata = &contig_bootmem_data };
-
-#ifndef CONFIG_DISCONTIGMEM
-
-/*
- * This is meant to be invoked by platforms whose physical memory starts
- * at a considerably higher value than 0. Examples are Super-H, ARM, m68k.
- * Should be invoked with paramters (0, 0, unsigned long *[], start_paddr).
- */
-void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
-	unsigned long *zones_size, unsigned long node_start_pfn, 
-	unsigned long *zholes_size)
-{
-	unsigned long size;
-
-	pgdat = &contig_page_data;
-	contig_page_data.node_id = 0;
-	contig_page_data.node_start_pfn = node_start_pfn;
-	calculate_totalpages (&contig_page_data, zones_size, zholes_size);
-	if (pmap == (struct page *)0) {
-		size = (pgdat->node_size + 1) * sizeof(struct page);
-		pmap = (struct page *) alloc_bootmem_node(pgdat, size);
-	}
-	contig_page_data.node_mem_map = pmap;
-	free_area_init_core(&contig_page_data, zones_size, zholes_size);
-	mem_map = contig_page_data.node_mem_map;
-}
-
-#endif /* !CONFIG_DISCONTIGMEM */
-
-struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order)
-{
-#ifdef CONFIG_NUMA
-	return __alloc_pages(gfp_mask, order, NODE_DATA(nid)->node_zonelists + (gfp_mask & GFP_ZONEMASK));
-#else
-	return alloc_pages(gfp_mask, order);
-#endif
-}
-
-#ifdef CONFIG_DISCONTIGMEM
-
-#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
-
-/*
- * Nodes can be initialized parallely, in no particular order.
- */
-void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
-	unsigned long *zones_size, unsigned long node_start_pfn, 
-	unsigned long *zholes_size)
-{
-	int i;
-	unsigned long size;
-
-	pgdat->node_id = nid;
-	pgdat->node_start_pfn = node_start_pfn;
-	calculate_totalpages (pgdat, zones_size, zholes_size);
-	if (pmap == (struct page *)0) {
-		size = (pgdat->node_size + 1) * sizeof(struct page); 
-		pmap = (struct page *) alloc_bootmem_node(pgdat, size);
-	}
-	pgdat->node_mem_map = pmap;
-	free_area_init_core(pgdat, zones_size, zholes_size);
-
-	/*
-	 * Get space for the valid bitmap.
-	 */
-	size = 0;
-	for (i = 0; i < MAX_NR_ZONES; i++)
-		size += zones_size[i];
-	size = LONG_ALIGN((size + 7) >> 3);
-	pgdat->valid_addr_bitmap = (unsigned long *)alloc_bootmem_node(pgdat, size);
-	memset(pgdat->valid_addr_bitmap, 0, size);
-}
-
-#endif /* CONFIG_DISCONTIGMEM */
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Fri Oct 11 21:22:52 2002
+++ b/mm/page_alloc.c	Fri Oct 11 21:22:52 2002
@@ -26,10 +26,12 @@
 #include <linux/blkdev.h>
 #include <linux/slab.h>
 
+struct pglist_data *pgdat_list;
 unsigned long totalram_pages;
 unsigned long totalhigh_pages;
 int nr_swap_pages;
-pg_data_t *pgdat_list;
+int numnodes = 1;
+
 
 /*
  * Used by page_zone() to look up the address of the struct zone whose
@@ -440,6 +442,12 @@
 {
 	struct page * page;
 
+	/*
+	 * get_zeroed_page() returns a 32-bit address, which cannot represent
+	 * a highmem page
+	 */
+	BUG_ON(gfp_mask & __GFP_HIGHMEM);
+
 	page = alloc_pages(gfp_mask, 0);
 	if (page) {
 		void *address = page_address(page);
@@ -772,23 +780,6 @@
 		build_zonelists(NODE_DATA(i));
 }
 
-void __init calculate_totalpages (pg_data_t *pgdat, unsigned long *zones_size,
-	unsigned long *zholes_size)
-{
-	unsigned long realtotalpages, totalpages = 0;
-	int i;
-
-	for (i = 0; i < MAX_NR_ZONES; i++)
-		totalpages += zones_size[i];
-	pgdat->node_size = totalpages;
-
-	realtotalpages = totalpages;
-	if (zholes_size)
-		for (i = 0; i < MAX_NR_ZONES; i++)
-			realtotalpages -= zholes_size[i];
-	printk("On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
-}
-
 /*
  * Helper functions to size the waitqueue hash table.
  * Essentially these want to choose hash table sizes sufficiently
@@ -833,13 +824,46 @@
 
 #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
 
+static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
+		unsigned long *zones_size, unsigned long *zholes_size)
+{
+	unsigned long realtotalpages, totalpages = 0;
+	int i;
+
+	for (i = 0; i < MAX_NR_ZONES; i++)
+		totalpages += zones_size[i];
+	pgdat->node_size = totalpages;
+
+	realtotalpages = totalpages;
+	if (zholes_size)
+		for (i = 0; i < MAX_NR_ZONES; i++)
+			realtotalpages -= zholes_size[i];
+	printk("On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
+}
+
+/*
+ * Get space for the valid bitmap.
+ */
+static void __init calculate_zone_bitmap(struct pglist_data *pgdat,
+		unsigned long *zones_size)
+{
+	unsigned long size = 0;
+	int i;
+
+	for (i = 0; i < MAX_NR_ZONES; i++)
+		size += zones_size[i];
+	size = LONG_ALIGN((size + 7) >> 3);
+	pgdat->valid_addr_bitmap = (unsigned long *)alloc_bootmem_node(pgdat, size);
+	memset(pgdat->valid_addr_bitmap, 0, size);
+}
+
 /*
  * Set up the zone data structures:
  *   - mark all pages reserved
  *   - mark all memory queues empty
  *   - clear the memory bitmaps
  */
-void __init free_area_init_core(pg_data_t *pgdat,
+static void __init free_area_init_core(struct pglist_data *pgdat,
 		unsigned long *zones_size, unsigned long *zholes_size)
 {
 	unsigned long i, j;
@@ -974,7 +998,30 @@
 	}
 }
 
+void __init free_area_init_node(int nid, struct pglist_data *pgdat,
+		struct page *node_mem_map, unsigned long *zones_size,
+		unsigned long node_start_pfn, unsigned long *zholes_size)
+{
+	unsigned long size;
+
+	pgdat->node_id = nid;
+	pgdat->node_start_pfn = node_start_pfn;
+	calculate_zone_totalpages(pgdat, zones_size, zholes_size);
+	if (!node_mem_map) {
+		size = (pgdat->node_size + 1) * sizeof(struct page); 
+		node_mem_map = alloc_bootmem_node(pgdat, size);
+	}
+	pgdat->node_mem_map = node_mem_map;
+
+	free_area_init_core(pgdat, zones_size, zholes_size);
+
+	calculate_zone_bitmap(pgdat, zones_size);
+}
+
 #ifndef CONFIG_DISCONTIGMEM
+static bootmem_data_t contig_bootmem_data;
+struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data };
+
 void __init free_area_init(unsigned long *zones_size)
 {
 	free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, NULL);
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Fri Oct 11 21:22:56 2002
+++ b/mm/shmem.c	Fri Oct 11 21:22:56 2002
@@ -98,7 +98,7 @@
 
 static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb)
 {
-	return sb->u.generic_sbp;
+	return sb->s_fs_info;
 }
 
 static struct super_operations shmem_ops;
@@ -1595,7 +1595,7 @@
 	sbinfo = kmalloc(sizeof(struct shmem_sb_info), GFP_KERNEL);
 	if (!sbinfo)
 		return -ENOMEM;
-	sb->u.generic_sbp = sbinfo;
+	sb->s_fs_info = sbinfo;
 	memset(sbinfo, 0, sizeof(struct shmem_sb_info));
 
 	/*
@@ -1644,14 +1644,14 @@
 	iput(inode);
 failed:
 	kfree(sbinfo);
-	sb->u.generic_sbp = NULL;
+	sb->s_fs_info = NULL;
 	return err;
 }
 
 static void shmem_put_super(struct super_block *sb)
 {
-	kfree(sb->u.generic_sbp);
-	sb->u.generic_sbp = NULL;
+	kfree(sb->s_fs_info);
+	sb->s_fs_info = NULL;
 }
 
 static kmem_cache_t *shmem_inode_cachep;
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Fri Oct 11 21:22:56 2002
+++ b/mm/swap_state.c	Fri Oct 11 21:22:56 2002
@@ -199,16 +199,14 @@
 int move_to_swap_cache(struct page *page, swp_entry_t entry)
 {
 	struct address_space *mapping = page->mapping;
-	void **pslot;
 	int err;
 
 	write_lock(&swapper_space.page_lock);
 	write_lock(&mapping->page_lock);
 
-	err = radix_tree_reserve(&swapper_space.page_tree, entry.val, &pslot);
+	err = radix_tree_insert(&swapper_space.page_tree, entry.val, page);
 	if (!err) {
 		__remove_from_page_cache(page);
-		*pslot = page;
 		___add_to_page_cache(page, &swapper_space, entry.val);
 	}
 
@@ -231,7 +229,6 @@
 		struct address_space *mapping)
 {
 	swp_entry_t entry;
-	void **pslot;
 	int err;
 
 	BUG_ON(!PageLocked(page));
@@ -243,10 +240,9 @@
 	write_lock(&swapper_space.page_lock);
 	write_lock(&mapping->page_lock);
 
-	err = radix_tree_reserve(&mapping->page_tree, index, &pslot);
+	err = radix_tree_insert(&mapping->page_tree, index, page);
 	if (!err) {
 		__delete_from_swap_cache(page);
-		*pslot = page;
 		___add_to_page_cache(page, mapping, index);
 	}
 
diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c
--- a/mm/vmalloc.c	Fri Oct 11 21:22:59 2002
+++ b/mm/vmalloc.c	Fri Oct 11 21:22:59 2002
@@ -203,6 +203,10 @@
 	 * We always allocate a guard page.
 	 */
 	size += PAGE_SIZE;
+	if (unlikely(!size)) {
+		kfree (area);
+		return NULL;
+	}
 
 	write_lock(&vmlist_lock);
 	for (p = &vmlist; (tmp = *p) ;p = &tmp->next) {
diff -Nru a/net/appletalk/aarp.c b/net/appletalk/aarp.c
--- a/net/appletalk/aarp.c	Fri Oct 11 21:22:56 2002
+++ b/net/appletalk/aarp.c	Fri Oct 11 21:22:56 2002
@@ -8,7 +8,7 @@
  *	the generic neighbour discovery code to clean this up.
  *
  *	FIXME:
- *		We ought to handle the retransmits with a single list and a 
+ *		We ought to handle the retransmits with a single list and a
  *	separate fast timer for when it is needed.
  *		Use neighbour discovery code.
  *		Token Ring Support.
@@ -23,7 +23,7 @@
  *		Inside AppleTalk (2nd Ed).
  *	Fixes:
  *		Jaume Grau	-	flush caches on AARP_PROBE
- *		Rob Newberry	-	Added proxy AARP and AARP proc fs, 
+ *		Rob Newberry	-	Added proxy AARP and AARP proc fs,
  *					moved probing from DDP module.
  *		Arnaldo C. Melo -	don't mangle rx packets
  *
@@ -46,7 +46,7 @@
 /* Lists of aarp entries */
 /**
  *	struct aarp_entry - AARP entry
- *	@last_sent - Last time we xmitted the aarp request 
+ *	@last_sent - Last time we xmitted the aarp request
  *	@packet_queue - Queue of frames wait for resolution
  *	@status - Used for proxy AARP
  *	expires_at - Entry expiry time
@@ -76,7 +76,7 @@
 static int unresolved_count;
 
 /* One lock protects it all. */
-static spinlock_t aarp_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t aarp_lock = RW_LOCK_UNLOCKED;
 
 /* Used to walk the list and purge/kick entries.  */
 static struct timer_list aarp_timer;
@@ -97,7 +97,6 @@
  *
  *	Must run under aarp_lock.
  */
- 
 static void __aarp_send_query(struct aarp_entry *a)
 {
 	static unsigned char aarp_eth_multicast[ETH_ALEN] =
@@ -107,7 +106,7 @@
 	int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
 	struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
 	struct atalk_addr *sat = atalk_find_dev_addr(dev);
-	
+
 	if (!skb)
 		return;
 
@@ -115,34 +114,34 @@
 		kfree_skb(skb);
 		return;
 	}
-	
-	/* Set up the buffer */		
+
+	/* Set up the buffer */
 	skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
 	skb->nh.raw      = skb->h.raw = skb_put(skb, sizeof(*eah));
 	skb->protocol    = htons(ETH_P_ATALK);
 	skb->dev	 = dev;
 	eah		 = aarp_hdr(skb);
-	
+
 	/* Set up the ARP */
 	eah->hw_type	 = htons(AARP_HW_TYPE_ETHERNET);
 	eah->pa_type	 = htons(ETH_P_ATALK);
-	eah->hw_len	 = ETH_ALEN;	
+	eah->hw_len	 = ETH_ALEN;
 	eah->pa_len	 = AARP_PA_ALEN;
 	eah->function	 = htons(AARP_REQUEST);
-	
+
 	memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
-	
+
 	eah->pa_src_zero = 0;
 	eah->pa_src_net	 = sat->s_net;
 	eah->pa_src_node = sat->s_node;
-	
+
 	memset(eah->hw_dst, '\0', ETH_ALEN);
-	
+
 	eah->pa_dst_zero = 0;
 	eah->pa_dst_net	 = a->target_addr.s_net;
 	eah->pa_dst_node = a->target_addr.s_node;
-	
-	/* Send it */	
+
+	/* Send it */
 	aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
 	/* Update the sending count */
 	a->xmit_count++;
@@ -156,40 +155,40 @@
 	struct elapaarp *eah;
 	int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length;
 	struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
-	
+
 	if (!skb)
 		return;
-	
+
 	/* Set up the buffer */
 	skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
-	skb->nh.raw      = skb->h.raw = skb_put(skb, sizeof(*eah));	 
+	skb->nh.raw      = skb->h.raw = skb_put(skb, sizeof(*eah));
 	skb->protocol    = htons(ETH_P_ATALK);
 	skb->dev	 = dev;
 	eah		 = aarp_hdr(skb);
-	
+
 	/* Set up the ARP */
 	eah->hw_type	 = htons(AARP_HW_TYPE_ETHERNET);
 	eah->pa_type	 = htons(ETH_P_ATALK);
-	eah->hw_len	 = ETH_ALEN;	
+	eah->hw_len	 = ETH_ALEN;
 	eah->pa_len	 = AARP_PA_ALEN;
 	eah->function	 = htons(AARP_REPLY);
-	
+
 	memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
-	
+
 	eah->pa_src_zero = 0;
 	eah->pa_src_net	 = us->s_net;
 	eah->pa_src_node = us->s_node;
-	
+
 	if (!sha)
 		memset(eah->hw_dst, '\0', ETH_ALEN);
 	else
 		memcpy(eah->hw_dst, sha, ETH_ALEN);
-	
+
 	eah->pa_dst_zero = 0;
 	eah->pa_dst_net	 = them->s_net;
 	eah->pa_dst_node = them->s_node;
-	
-	/* Send it */	
+
+	/* Send it */
 	aarp_dl->request(aarp_dl, skb, sha);
 }
 
@@ -238,7 +237,7 @@
 	/* Send it */
 	aarp_dl->request(aarp_dl, skb, aarp_eth_multicast);
 }
-	
+
 /*
  *	Handle an aarp timer expire
  *
@@ -264,7 +263,6 @@
  *
  *	Must run under the aarp_lock.
  */
- 
 static void __aarp_kick(struct aarp_entry **n)
 {
 	struct aarp_entry *t;
@@ -287,7 +285,6 @@
  *
  *	Must run under the aarp_lock.
  */
- 
 static void __aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
 {
 	struct aarp_entry *t;
@@ -300,13 +297,13 @@
 		} else
 			n = &((*n)->next);
 }
-		
+
 /* Handle the timer event */
 static void aarp_expire_timeout(unsigned long unused)
 {
 	int ct;
 
-	spin_lock_bh(&aarp_lock);
+	write_lock_bh(&aarp_lock);
 
 	for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
 		__aarp_expire_timer(&resolved[ct]);
@@ -315,20 +312,20 @@
 		__aarp_expire_timer(&proxies[ct]);
 	}
 
-	spin_unlock_bh(&aarp_lock);
-	mod_timer(&aarp_timer, jiffies + 
-		  (unresolved_count ? sysctl_aarp_tick_time :
-		   sysctl_aarp_expiry_time));
+	write_unlock_bh(&aarp_lock);
+	mod_timer(&aarp_timer, jiffies +
+			       (unresolved_count ? sysctl_aarp_tick_time :
+				sysctl_aarp_expiry_time));
 }
 
 /* Network device notifier chain handler. */
 static int aarp_device_event(struct notifier_block *this, unsigned long event,
-				void *ptr)
+			     void *ptr)
 {
 	int ct;
 
 	if (event == NETDEV_DOWN) {
-		spin_lock_bh(&aarp_lock);
+		write_lock_bh(&aarp_lock);
 
 		for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
 			__aarp_expire_device(&resolved[ct], ptr);
@@ -336,7 +333,7 @@
 			__aarp_expire_device(&proxies[ct], ptr);
 		}
 
-		spin_unlock_bh(&aarp_lock);
+		write_unlock_bh(&aarp_lock);
 	}
 	return NOTIFY_DONE;
 }
@@ -345,7 +342,6 @@
  *	Create a new aarp entry.  This must use GFP_ATOMIC because it
  *	runs while holding spinlocks.
  */
- 
 static struct aarp_entry *aarp_alloc(void)
 {
 	struct aarp_entry *a = kmalloc(sizeof(*a), GFP_ATOMIC);
@@ -382,13 +378,13 @@
 	int hash = sa->s_node % (AARP_HASH_SIZE - 1);
 	struct aarp_entry *a;
 
-	spin_lock_bh(&aarp_lock);
+	write_lock_bh(&aarp_lock);
 
 	a = __aarp_find_entry(proxies[hash], dev, sa);
 	if (a)
 		a->expires_at = jiffies - 1;
 
-	spin_unlock_bh(&aarp_lock);
+	write_unlock_bh(&aarp_lock);
 }
 
 /* This must run under aarp_lock. */
@@ -429,7 +425,7 @@
 void aarp_probe_network(struct atalk_iface *atif)
 {
 	if (atif->dev->type == ARPHRD_LOCALTLK ||
-	    atif->dev->type == ARPHRD_PPP) 
+	    atif->dev->type == ARPHRD_PPP)
 		aarp_send_probe_phase1(atif);
 	else {
 		unsigned int count;
@@ -440,7 +436,7 @@
 			/* Defer 1/10th */
 			current->state = TASK_INTERRUPTIBLE;
 			schedule_timeout(HZ / 10);
-							
+
 			if (atif->status & ATIF_PROBE_FAIL)
 				break;
 		}
@@ -452,7 +448,7 @@
 	int hash, retval = -EPROTONOSUPPORT;
 	struct aarp_entry *entry;
 	unsigned int count;
-	
+
 	/*
 	 * we don't currently support LocalTalk or PPP for proxy AARP;
 	 * if someone wants to try and add it, have fun
@@ -460,41 +456,41 @@
 	if (atif->dev->type == ARPHRD_LOCALTLK ||
 	    atif->dev->type == ARPHRD_PPP)
 		goto out;
-		
-	/* 
-	 * create a new AARP entry with the flags set to be published -- 
+
+	/*
+	 * create a new AARP entry with the flags set to be published --
 	 * we need this one to hang around even if it's in use
 	 */
 	entry = aarp_alloc();
 	retval = -ENOMEM;
 	if (!entry)
 		goto out;
-	
+
 	entry->expires_at = -1;
 	entry->status = ATIF_PROBE;
 	entry->target_addr.s_node = sa->s_node;
 	entry->target_addr.s_net = sa->s_net;
 	entry->dev = atif->dev;
 
-	spin_lock_bh(&aarp_lock);
+	write_lock_bh(&aarp_lock);
 
 	hash = sa->s_node % (AARP_HASH_SIZE - 1);
 	entry->next = proxies[hash];
 	proxies[hash] = entry;
-	
+
 	for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
 		aarp_send_probe(atif->dev, sa);
 
 		/* Defer 1/10th */
 		current->state = TASK_INTERRUPTIBLE;
-		spin_unlock_bh(&aarp_lock);
+		write_unlock_bh(&aarp_lock);
 		schedule_timeout(HZ / 10);
-		spin_lock_bh(&aarp_lock);
+		write_lock_bh(&aarp_lock);
 
 		if (entry->status & ATIF_PROBE_FAIL)
 			break;
 	}
-	
+
 	if (entry->status & ATIF_PROBE_FAIL) {
 		entry->expires_at = jiffies - 1; /* free the entry */
 		retval = -EADDRINUSE; /* return network full */
@@ -503,42 +499,42 @@
 		retval = 1;
 	}
 
-	spin_unlock_bh(&aarp_lock);
+	write_unlock_bh(&aarp_lock);
 out:
 	return retval;
 }
 
 /* Send a DDP frame */
-int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb,
+int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb,
 		  struct atalk_addr *sa, void *hwaddr)
 {
 	static char ddp_eth_multicast[ETH_ALEN] =
 		{ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
 	int hash;
 	struct aarp_entry *a;
-	
+
 	skb->nh.raw = skb->data;
-	
+
 	/* Check for LocalTalk first */
 	if (dev->type == ARPHRD_LOCALTLK) {
 		struct atalk_addr *at = atalk_find_dev_addr(dev);
 		struct ddpehdr *ddp = (struct ddpehdr *)skb->data;
 		int ft = 2;
-		
+
 		/*
 		 * Compressible ?
-		 * 
+		 *
 		 * IFF: src_net == dest_net == device_net
 		 * (zero matches anything)
 		 */
-		 
+
 		if ((!ddp->deh_snet || at->s_net == ddp->deh_snet) &&
 		    (!ddp->deh_dnet || at->s_net == ddp->deh_dnet)) {
-			skb_pull(skb, sizeof(struct ddpehdr) - 4);
+			skb_pull(skb, sizeof(*ddp) - 4);
 
 			/*
-			 *	The upper two remaining bytes are the port 
-			 *	numbers	we just happen to need. Now put the 
+			 *	The upper two remaining bytes are the port
+			 *	numbers	we just happen to need. Now put the
 			 *	length in the lower two.
 			 */
 			*((__u16 *)skb->data) = htons(skb->len);
@@ -548,14 +544,14 @@
 		 * Nice and easy. No AARP type protocols occur here so we can
 		 * just shovel it out with a 3 byte LLAP header
 		 */
-		 
+
 		skb_push(skb, 3);
 		skb->data[0] = sa->s_node;
 		skb->data[1] = at->s_node;
 		skb->data[2] = ft;
 		skb->dev     = dev;
 		goto sendit;
-	}	
+	}
 
 	/* On a PPP link we neither compress nor aarp.  */
 	if (dev->type == ARPHRD_PPP) {
@@ -563,7 +559,7 @@
 		skb->dev = dev;
 		goto sendit;
 	}
-	 
+
 	/* Non ELAP we cannot do. */
 	if (dev->type != ARPHRD_ETHER)
 		return -1;
@@ -571,7 +567,7 @@
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_ATALK);
 	hash = sa->s_node % (AARP_HASH_SIZE - 1);
-	
+
 	/* Do we have a resolved entry? */
 	if (sa->s_node == ATADDR_BCAST) {
 		/* Send it */
@@ -579,13 +575,13 @@
 		goto sent;
 	}
 
-	spin_lock_bh(&aarp_lock);
+	write_lock_bh(&aarp_lock);
 	a = __aarp_find_entry(resolved[hash], dev, sa);
 
 	if (a) { /* Return 1 and fill in the address */
 		a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10);
 		ddp_dl->request(ddp_dl, skb, a->hwaddr);
-		spin_unlock_bh(&aarp_lock);
+		write_unlock_bh(&aarp_lock);
 		goto sent;
 	}
 
@@ -600,7 +596,7 @@
 	a = aarp_alloc();
 	if (!a) {
 		/* Whoops slipped... good job it's an unreliable protocol 8) */
-		spin_unlock_bh(&aarp_lock);
+		write_unlock_bh(&aarp_lock);
 		return -1;
 	}
 
@@ -627,7 +623,7 @@
 
 	/* Now finally, it is safe to drop the lock. */
 out_unlock:
-	spin_unlock_bh(&aarp_lock);
+	write_unlock_bh(&aarp_lock);
 
 	/* Tell the ddp layer we have taken over for this frame. */
 	return 0;
@@ -647,7 +643,7 @@
  *	Must run under aarp_lock.
  */
 static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a,
-				int hash)
+			    int hash)
 {
 	struct sk_buff *skb;
 
@@ -666,7 +662,7 @@
 						sysctl_aarp_expiry_time * 10;
 				ddp_dl->request(ddp_dl, skb, a->hwaddr);
 			}
-		} else 
+		} else
 			list = &((*list)->next);
 }
 
@@ -723,7 +719,7 @@
 	da.s_node = ea->pa_dst_node;
 	da.s_net  = ea->pa_dst_net;
 
-	spin_lock_bh(&aarp_lock);
+	write_lock_bh(&aarp_lock);
 	a = __aarp_find_entry(proxies[hash], dev, &da);
 
 	if (a && a->status & ATIF_PROBE) {
@@ -736,23 +732,23 @@
 	}
 
 	switch (function) {
-		case AARP_REPLY:	
+		case AARP_REPLY:
 			if (!unresolved_count)	/* Speed up */
 				break;
 
 			/* Find the entry.  */
-			a = __aarp_find_entry(unresolved[hash],dev,&sa);
+			a = __aarp_find_entry(unresolved[hash], dev, &sa);
 			if (!a || dev != a->dev)
 				break;
 
 			/* We can fill one in - this is good. */
-			memcpy(a->hwaddr,ea->hw_src,ETH_ALEN);
-			__aarp_resolved(&unresolved[hash],a,hash);
+			memcpy(a->hwaddr, ea->hw_src, ETH_ALEN);
+			__aarp_resolved(&unresolved[hash], a, hash);
 			if (!unresolved_count)
 				mod_timer(&aarp_timer,
 					  jiffies + sysctl_aarp_expiry_time);
 			break;
-			
+
 		case AARP_REQUEST:
 		case AARP_PROBE:
 
@@ -762,12 +758,12 @@
 			 * simply means we shouldn't cache the querying host,
 			 * as in a probe they are proposing an address not
 			 * using one.
-			 *	
+			 *
 			 * Support for proxy-AARP added. We check if the
 			 * address is one of our proxies before we toss the
 			 * packet out.
 			 */
-			 
+
 			sa.s_node = ea->pa_dst_node;
 			sa.s_net  = ea->pa_dst_net;
 
@@ -787,10 +783,11 @@
 				 * address. So as a precaution flush any
 				 * entries we have for this address.
 				 */
-				struct aarp_entry *a = __aarp_find_entry(
-						resolved[sa.s_node %
-							 (AARP_HASH_SIZE - 1)],
-								skb->dev, &sa);
+				struct aarp_entry *a;
+
+				a = __aarp_find_entry(resolved[sa.s_node %
+							  (AARP_HASH_SIZE - 1)],
+						      skb->dev, &sa);
 
 				/*
 				 * Make it expire next tick - that avoids us
@@ -813,7 +810,7 @@
 
 			sa.s_node = ea->pa_src_node;
 			sa.s_net = ea->pa_src_net;
-			
+
 			/* aarp_my_address has found the address to use for us.
 			*/
 			aarp_send_reply(dev, ma, &sa, ea->hw_src);
@@ -821,7 +818,7 @@
 	}
 
 unlock:
-	spin_unlock_bh(&aarp_lock);
+	write_unlock_bh(&aarp_lock);
 out1:
 	ret = 1;
 out0:
@@ -830,7 +827,7 @@
 }
 
 static struct notifier_block aarp_notifier = {
-	.notifier_call =aarp_device_event,
+	.notifier_call = aarp_device_event,
 };
 
 static unsigned char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 };
@@ -853,7 +850,7 @@
 {
 	int ct;
 
-	spin_lock_bh(&aarp_lock);
+	write_lock_bh(&aarp_lock);
 
 	for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
 		__aarp_expire_device(&resolved[ct], dev);
@@ -861,7 +858,7 @@
 		__aarp_expire_device(&proxies[ct], dev);
 	}
 
-	spin_unlock_bh(&aarp_lock);
+	write_unlock_bh(&aarp_lock);
 }
 
 /* Called from proc fs */
@@ -875,7 +872,7 @@
 			      "address", "device", "hw addr", "last_sent",
 			      "expires");
 
-	spin_lock_bh(&aarp_lock);
+	read_lock_bh(&aarp_lock);
 
 	for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
 		for (entry = resolved[ct]; entry; entry = entry->next) {
@@ -950,11 +947,10 @@
 		}
 	}
 
-	spin_unlock_bh(&aarp_lock);
+	read_unlock_bh(&aarp_lock);
 	return len;
 }
 
-#ifdef MODULE
 /* General module cleanup. Called from cleanup_module() in ddp.c. */
 void aarp_cleanup_module(void)
 {
@@ -962,7 +958,7 @@
 	unregister_netdevice_notifier(&aarp_notifier);
 	unregister_snap_client(aarp_dl);
 }
-#endif  /* MODULE */
+
 #ifdef CONFIG_PROC_FS
 void aarp_register_proc_fs(void)
 {
diff -Nru a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c
--- a/net/appletalk/atalk_proc.c	Fri Oct 11 21:23:03 2002
+++ b/net/appletalk/atalk_proc.c	Fri Oct 11 21:23:03 2002
@@ -30,7 +30,7 @@
 {
 	loff_t l = *pos;
 
-	spin_lock_bh(&atalk_interfaces_lock);
+	read_lock_bh(&atalk_interfaces_lock);
 	return l ? atalk_get_interface_idx(--l) : (void *)1;
 }
 
@@ -53,7 +53,7 @@
 
 static void atalk_seq_interface_stop(struct seq_file *seq, void *v)
 {
-	spin_unlock_bh(&atalk_interfaces_lock);
+	read_unlock_bh(&atalk_interfaces_lock);
 }
 
 static int atalk_seq_interface_show(struct seq_file *seq, void *v)
@@ -154,7 +154,7 @@
 {
 	loff_t l = *pos;
 
-	spin_lock_bh(&atalk_sockets_lock);
+	read_lock_bh(&atalk_sockets_lock);
 	return l ? atalk_get_socket_idx(--l) : (void *)1;
 }
 
@@ -177,7 +177,7 @@
 
 static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
 {
-	spin_unlock_bh(&atalk_sockets_lock);
+	read_unlock_bh(&atalk_sockets_lock);
 }
 
 static int atalk_seq_socket_show(struct seq_file *seq, void *v)
diff -Nru a/net/appletalk/ddp.c b/net/appletalk/ddp.c
--- a/net/appletalk/ddp.c	Fri Oct 11 21:23:05 2002
+++ b/net/appletalk/ddp.c	Fri Oct 11 21:23:05 2002
@@ -73,10 +73,8 @@
 				     struct atalk_addr *sa);
 extern void aarp_proxy_remove(struct net_device *dev, struct atalk_addr *sa);
 
-#ifdef CONFIG_SYSCTL
-extern inline void atalk_register_sysctl(void);
-extern inline void atalk_unregister_sysctl(void);
-#endif /* CONFIG_SYSCTL */
+extern void atalk_register_sysctl(void);
+extern void atalk_unregister_sysctl(void);
 
 struct datalink_proto *ddp_dl, *aarp_dl;
 static struct proto_ops atalk_dgram_ops;
@@ -88,29 +86,29 @@
 \**************************************************************************/
 
 struct sock *atalk_sockets;
-spinlock_t atalk_sockets_lock = SPIN_LOCK_UNLOCKED;
+rwlock_t atalk_sockets_lock = RW_LOCK_UNLOCKED;
 
 extern inline void atalk_insert_socket(struct sock *sk)
 {
-	spin_lock_bh(&atalk_sockets_lock);
+	write_lock_bh(&atalk_sockets_lock);
 	sk->next = atalk_sockets;
 	if (sk->next)
 		atalk_sockets->pprev = &sk->next;
 	atalk_sockets = sk;
 	sk->pprev = &atalk_sockets;
-	spin_unlock_bh(&atalk_sockets_lock);
+	write_unlock_bh(&atalk_sockets_lock);
 }
 
 extern inline void atalk_remove_socket(struct sock *sk)
 {
-	spin_lock_bh(&atalk_sockets_lock);
+	write_lock_bh(&atalk_sockets_lock);
 	if (sk->pprev) {
 		if (sk->next)
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
 	}
-	spin_unlock_bh(&atalk_sockets_lock);
+	write_unlock_bh(&atalk_sockets_lock);
 }
 
 static struct sock *atalk_search_socket(struct sockaddr_at *to,
@@ -118,7 +116,7 @@
 {
 	struct sock *s;
 
-	spin_lock_bh(&atalk_sockets_lock);
+	read_lock_bh(&atalk_sockets_lock);
 	for (s = atalk_sockets; s; s = s->next) {
 		struct atalk_sock *at = at_sk(s);
 
@@ -145,7 +143,7 @@
 			break; 
 		}
 	}
-	spin_unlock_bh(&atalk_sockets_lock);
+	read_unlock_bh(&atalk_sockets_lock);
 	return s;
 }
 
@@ -164,7 +162,7 @@
 {
 	struct sock *s;
 
-	spin_lock_bh(&atalk_sockets_lock);
+	write_lock_bh(&atalk_sockets_lock);
 	for (s = atalk_sockets; s; s = s->next) {
 		struct atalk_sock *at = at_sk(s);
 
@@ -183,7 +181,7 @@
 		sk->pprev = &atalk_sockets;
 	}
 
-	spin_unlock_bh(&atalk_sockets_lock);
+	write_unlock_bh(&atalk_sockets_lock);
 	return s;
 }
 
@@ -225,12 +223,12 @@
 *                                                                          *
 \**************************************************************************/
 
-/* Anti-deadlock ordering is router_lock --> iface_lock -DaveM */
+/* Anti-deadlock ordering is atalk_routes_lock --> iface_lock -DaveM */
 struct atalk_route *atalk_routes;
 rwlock_t atalk_routes_lock = RW_LOCK_UNLOCKED;
 
 struct atalk_iface *atalk_interfaces;
-spinlock_t atalk_interfaces_lock = SPIN_LOCK_UNLOCKED;
+rwlock_t atalk_interfaces_lock = RW_LOCK_UNLOCKED;
 
 /* For probing devices or in a routerless network */
 struct atalk_route atrtr_default;
@@ -245,7 +243,7 @@
 	struct atalk_iface **iface = &atalk_interfaces;
 	struct atalk_iface *tmp;
 
-	spin_lock_bh(&atalk_interfaces_lock);
+	write_lock_bh(&atalk_interfaces_lock);
 	while ((tmp = *iface) != NULL) {
 		if (tmp->dev == dev) {
 			*iface = tmp->next;
@@ -255,7 +253,7 @@
 		} else
 			iface = &tmp->next;
 	}
-	spin_unlock_bh(&atalk_interfaces_lock);
+	write_unlock_bh(&atalk_interfaces_lock);
 }
 
 static struct atalk_iface *atif_add_device(struct net_device *dev,
@@ -274,10 +272,10 @@
 	iface->address = *sa;
 	iface->status = 0;
 
-	spin_lock_bh(&atalk_interfaces_lock);
+	write_lock_bh(&atalk_interfaces_lock);
 	iface->next = atalk_interfaces;
 	atalk_interfaces = iface;
-	spin_unlock_bh(&atalk_interfaces_lock);
+	write_unlock_bh(&atalk_interfaces_lock);
 out:
 	return iface;
 out_mem:
@@ -394,7 +392,7 @@
 	 * Return a point-to-point interface only if
 	 * there is no non-ptp interface available.
 	 */
-	spin_lock_bh(&atalk_interfaces_lock);
+	read_lock_bh(&atalk_interfaces_lock);
 	for (iface = atalk_interfaces; iface; iface = iface->next) {
 		if (!fiface && !(iface->dev->flags & IFF_LOOPBACK))
 			fiface = iface;
@@ -411,7 +409,7 @@
 	else
 		retval = NULL;
 out:
-	spin_unlock_bh(&atalk_interfaces_lock);
+	read_unlock_bh(&atalk_interfaces_lock);
 	return retval;
 }
 
@@ -442,7 +440,7 @@
 {
 	struct atalk_iface *iface;
 
-	spin_lock_bh(&atalk_interfaces_lock);
+	read_lock_bh(&atalk_interfaces_lock);
 	for (iface = atalk_interfaces; iface; iface = iface->next) {
 		if ((node == ATADDR_BCAST ||
 		     node == ATADDR_ANYNODE ||
@@ -457,7 +455,7 @@
 		    ntohs(net) <= ntohs(iface->nets.nr_lastnet))
 		        break;
 	}
-	spin_unlock_bh(&atalk_interfaces_lock);
+	read_unlock_bh(&atalk_interfaces_lock);
 	return iface;
 }
 
@@ -574,7 +572,7 @@
 	if (!devhint) {
 		riface = NULL;
 
-		spin_lock_bh(&atalk_interfaces_lock);
+		read_lock_bh(&atalk_interfaces_lock);
 		for (iface = atalk_interfaces; iface; iface = iface->next) {
 			if (!riface &&
 			    ntohs(ga->sat_addr.s_net) >=
@@ -587,7 +585,7 @@
 			    ga->sat_addr.s_node == iface->address.s_node)
 				riface = iface;
 		}		
-		spin_unlock_bh(&atalk_interfaces_lock);
+		read_unlock_bh(&atalk_interfaces_lock);
 
 		retval = -ENETUNREACH;
 		if (!riface)
@@ -1042,7 +1040,7 @@
 	struct sock *s;
 	int retval;
 
-	spin_lock_bh(&atalk_sockets_lock);
+	write_lock_bh(&atalk_sockets_lock);
 
 	for (sat->sat_port = ATPORT_RESERVED;
 	     sat->sat_port < ATPORT_LAST;
@@ -1071,7 +1069,7 @@
 
 	retval = -EBUSY;
 out:
-	spin_unlock_bh(&atalk_sockets_lock);
+	write_unlock_bh(&atalk_sockets_lock);
 	return retval;
 }
 
@@ -1831,13 +1829,18 @@
 EXPORT_SYMBOL(atrtr_get_dev);
 EXPORT_SYMBOL(atalk_find_dev_addr);
 
+static char atalk_banner[] __initdata =
+	KERN_INFO "NET4: AppleTalk 0.20 for Linux NET4.0\n";
+static char atalk_err_snap[] __initdata =
+	KERN_CRIT "Unable to register DDP with SNAP.\n";
+
 /* Called by proto.c on kernel start up */
 static int __init atalk_init(void)
 {
 	(void)sock_register(&atalk_family_ops);
 	ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv);
 	if (!ddp_dl)
-		printk(KERN_CRIT "Unable to register DDP with SNAP.\n");
+		printk(atalk_err_snap);
 
 	dev_add_pack(&ltalk_packet_type);
 	dev_add_pack(&ppptalk_packet_type);
@@ -1848,15 +1851,12 @@
 #ifdef CONFIG_PROC_FS
 	aarp_register_proc_fs();
 #endif /* CONFIG_PROC_FS */
-#ifdef CONFIG_SYSCTL
 	atalk_register_sysctl();
-#endif /* CONFIG_SYSCTL */
-	printk(KERN_INFO "NET4: AppleTalk 0.20 for Linux NET4.0\n");
+	printk(atalk_banner);
 	return 0;
 }
 module_init(atalk_init);
 
-#ifdef MODULE
 /*
  * Note on MOD_{INC,DEC}_USE_COUNT:
  *
@@ -1886,7 +1886,6 @@
 	sock_unregister(PF_APPLETALK);
 }
 module_exit(atalk_exit);
-#endif  /* MODULE */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alan Cox <Alan.Cox@linux.org>");
diff -Nru a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c
--- a/net/appletalk/sysctl_net_atalk.c	Fri Oct 11 21:22:54 2002
+++ b/net/appletalk/sysctl_net_atalk.c	Fri Oct 11 21:22:54 2002
@@ -7,14 +7,14 @@
  */
 
 #include <linux/config.h>
-#include <linux/sysctl.h>
 
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
 extern int sysctl_aarp_expiry_time;
 extern int sysctl_aarp_tick_time;
 extern int sysctl_aarp_retransmit_limit;
 extern int sysctl_aarp_resolve_time;
 
-#ifdef CONFIG_SYSCTL
 static struct ctl_table atalk_table[] = {
 	{
 		.ctl_name	= NET_ATALK_AARP_EXPIRY_TIME,
@@ -83,7 +83,7 @@
 	unregister_sysctl_table(atalk_table_header);
 }
 
-#else
+#else /* CONFIG_PROC_FS */
 void atalk_register_sysctl(void)
 {
 }
@@ -91,4 +91,4 @@
 void atalk_unregister_sysctl(void)
 {
 }
-#endif
+#endif /* CONFIG_PROC_FS */ 
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Fri Oct 11 21:23:00 2002
+++ b/net/atm/lec.c	Fri Oct 11 21:23:00 2002
@@ -553,8 +553,8 @@
 }
 
 static struct atmdev_ops lecdev_ops = {
-        close:	lec_atm_close,
-        send:	lec_atm_send
+        .close	= lec_atm_close,
+        .send	= lec_atm_send
 };
 
 static struct atm_dev lecatm_dev = {
diff -Nru a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
--- a/net/atm/mpoa_proc.c	Fri Oct 11 21:23:03 2002
+++ b/net/atm/mpoa_proc.c	Fri Oct 11 21:23:03 2002
@@ -111,7 +111,7 @@
 	unsigned char ip_string[16];
 	if(count == 0)
 	        return 0;
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if(!page)
 	        return -ENOMEM;
 	atm_mpoa_disp_qos((char *)page, &length);
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Fri Oct 11 21:22:55 2002
+++ b/net/atm/proc.c	Fri Oct 11 21:22:55 2002
@@ -496,7 +496,7 @@
 	int length;
 
 	if (count == 0) return 0;
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page) return -ENOMEM;
 	dev = PDE(file->f_dentry->d_inode)->data;
 	if (!dev->ops->proc_read)
@@ -523,7 +523,7 @@
 	info = PDE(file->f_dentry->d_inode)->data;
 
 	if (count == 0) return 0;
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page) return -ENOMEM;
 	length = (*info)(*pos,(char *) page);
 	if (length > count) length = -EINVAL;
diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
--- a/net/bluetooth/af_bluetooth.c	Fri Oct 11 21:22:54 2002
+++ b/net/bluetooth/af_bluetooth.c	Fri Oct 11 21:22:54 2002
@@ -356,11 +356,9 @@
 	remove_proc_entry("bluetooth", NULL);
 }
 
-#ifdef MODULE
-module_init(bluez_init);
+subsys_initcall(bluez_init);
 module_exit(bluez_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
 MODULE_LICENSE("GPL");
-#endif
diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
--- a/net/bluetooth/rfcomm/core.c	Fri Oct 11 21:22:50 2002
+++ b/net/bluetooth/rfcomm/core.c	Fri Oct 11 21:22:50 2002
@@ -42,6 +42,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/net.h>
+#include <linux/proc_fs.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -572,6 +573,15 @@
 	return NULL;
 }
 
+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
+{
+	struct sock *sk = s->sock->sk;
+	if (src)
+		bacpy(src, &bluez_sk(sk)->src);
+	if (dst)
+		bacpy(dst, &bluez_sk(sk)->dst);
+}
+
 /* ---- RFCOMM frame sending ---- */
 static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
 {
@@ -1674,6 +1684,63 @@
 	return 0;
 }
 
+/* ---- Proc fs support ---- */
+static int rfcomm_dlc_dump(char *buf)
+{
+	struct rfcomm_session *s;
+	struct sock *sk;
+	struct list_head *p, *pp;
+	char *ptr = buf;
+
+	rfcomm_lock();
+
+	list_for_each(p, &session_list) {
+		s = list_entry(p, struct rfcomm_session, list);
+		sk = s->sock->sk;
+
+		list_for_each(pp, &s->dlcs) {
+		struct rfcomm_dlc *d;
+			d = list_entry(pp, struct rfcomm_dlc, list);
+
+			ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
+				batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst),
+				d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
+		}
+	}
+	
+	rfcomm_unlock();
+
+	return ptr - buf;
+}
+
+extern int rfcomm_sock_dump(char *buf);
+
+static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+{
+	char *ptr = buf;
+	int len;
+
+	BT_DBG("count %d, offset %ld", count, offset);
+
+	ptr += rfcomm_dlc_dump(ptr);
+	ptr += rfcomm_sock_dump(ptr);
+	len  = ptr - buf;
+
+	if (len <= count + offset)
+		*eof = 1;
+
+	*start = buf + offset;
+	len -= offset;
+
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+/* ---- Initialization ---- */
 int __init rfcomm_init(void)
 {
 	kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
@@ -1684,6 +1751,8 @@
 	rfcomm_init_ttys();
 #endif
 
+	create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
+
 	BT_INFO("BlueZ RFCOMM ver %s", VERSION);
 	BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
 	BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
@@ -1700,6 +1769,8 @@
 	/* Wait until thread is running */
 	while (atomic_read(&running))
 		schedule();
+
+	remove_proc_entry("bluetooth/rfcomm", NULL);
 
 #ifdef CONFIG_BLUEZ_RFCOMM_TTY
 	rfcomm_cleanup_ttys();
diff -Nru a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
--- a/net/bluetooth/rfcomm/sock.c	Fri Oct 11 21:23:00 2002
+++ b/net/bluetooth/rfcomm/sock.c	Fri Oct 11 21:23:00 2002
@@ -43,7 +43,6 @@
 #include <linux/interrupt.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
-#include <linux/proc_fs.h>
 #include <linux/list.h>
 #include <net/sock.h>
 
@@ -61,7 +60,7 @@
 static struct proto_ops rfcomm_sock_ops;
 
 static struct bluez_sock_list rfcomm_sk_list = {
-	lock: RW_LOCK_UNLOCKED
+	.lock = RW_LOCK_UNLOCKED
 };
 
 static void rfcomm_sock_close(struct sock *sk);
@@ -83,7 +82,6 @@
 
 	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
 		rfcomm_dlc_throttle(d);
-	return;
 }
 
 static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
@@ -94,22 +92,26 @@
 
 	BT_DBG("dlc %p state %ld err %d", d, d->state, err);
 
+	bh_lock_sock(sk);
+
 	if (err)
 		sk->err = err;
 	sk->state = d->state;
 
 	parent = bluez_sk(sk)->parent;
-	if (!parent)
+	if (!parent) {
+		if (d->state == BT_CONNECTED)
+			rfcomm_session_getaddr(d->session, &bluez_sk(sk)->src, NULL);
 		sk->state_change(sk);
-	else
+	} else
 		parent->data_ready(parent, 0);
-	return;
+
+	bh_unlock_sock(sk);
 }
 
 static void rfcomm_sk_modem_status(struct rfcomm_dlc *d, int v24_sig)
 {
 	BT_DBG("dlc %p v24_sig 0x%02x", d, v24_sig);
-
 	return;
 }
 
@@ -374,6 +376,7 @@
 
 	sk->state = BT_CONNECT;
 	bacpy(&bluez_sk(sk)->dst, &sa->rc_bdaddr);
+	rfcomm_pi(sk)->channel = sa->rc_channel;
 
 	err = rfcomm_dlc_open(d, &bluez_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
 	if (!err)
@@ -655,7 +658,6 @@
 	return 0;
 }
 
-
 static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
@@ -735,14 +737,16 @@
  */
 int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
 {
-	struct bluez_sock *bsk = bluez_sk(s->sock->sk);
 	struct sock *sk, *parent;
+	bdaddr_t src, dst;
 	int result = 0;
 
 	BT_DBG("session %p channel %d", s, channel);
 
+	rfcomm_session_getaddr(s, &src, &dst);
+
 	/* Check if we have socket listening on channel */
-	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &bsk->src);
+	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
 	if (!parent)
 		return 0;
 
@@ -757,8 +761,8 @@
 		goto done;
 
 	rfcomm_sock_init(sk, parent);
-	bacpy(&bluez_sk(sk)->src, &bsk->src);
-	bacpy(&bluez_sk(sk)->dst, &bsk->dst);
+	bacpy(&bluez_sk(sk)->src, &src);
+	bacpy(&bluez_sk(sk)->dst, &dst);
 	rfcomm_pi(sk)->channel = channel;
 
 	sk->state = BT_CONFIG;
@@ -774,8 +778,9 @@
 }
 
 /* ---- Proc fs support ---- */
-static int rfcomm_sock_dump(char *buf, struct bluez_sock_list *list)
+int rfcomm_sock_dump(char *buf)
 {
+	struct bluez_sock_list *list = &rfcomm_sk_list;
 	struct rfcomm_pinfo *pi;
 	struct sock *sk;
 	char *ptr = buf;
@@ -784,42 +789,16 @@
 
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = rfcomm_pi(sk);
-		ptr += sprintf(ptr, "%s %s %d %d\n",
+		ptr += sprintf(ptr, "sk  %s %s %d %d\n",
 				batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst),
-				sk->state, rfcomm_pi(sk)->channel); 
+				sk->state, rfcomm_pi(sk)->channel);
 	}
 
 	write_unlock_bh(&list->lock);
 
-	ptr += sprintf(ptr, "\n");
-
 	return ptr - buf;
 }
 
-static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-{
-	char *ptr = buf;
-	int len;
-
-	BT_DBG("count %d, offset %ld", count, offset);
-
-	ptr += rfcomm_sock_dump(ptr, &rfcomm_sk_list);
-	len  = ptr - buf;
-
-	if (len <= count + offset)
-		*eof = 1;
-
-	*start = buf + offset;
-	len -= offset;
-
-	if (len > count)
-		len = count;
-	if (len < 0)
-		len = 0;
-
-	return len;
-}
-
 static struct proto_ops rfcomm_sock_ops = {
 	.family		= PF_BLUETOOTH,
 	.release	= rfcomm_sock_release,
@@ -853,15 +832,12 @@
 		return err;
 	}
 
-	create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
 	return 0;
 }
 
 void rfcomm_cleanup_sockets(void)
 {
 	int err;
-
-	remove_proc_entry("bluetooth/rfcomm", NULL);
 
 	/* Unregister socket, protocol and notifier */
 	if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
--- a/net/bluetooth/rfcomm/tty.c	Fri Oct 11 21:22:59 2002
+++ b/net/bluetooth/rfcomm/tty.c	Fri Oct 11 21:22:59 2002
@@ -501,12 +501,6 @@
 #endif
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
-#define __minor MINOR
-#else
-#define __minor minor
-#endif
-
 static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	DECLARE_WAITQUEUE(wait, current);
@@ -514,7 +508,7 @@
 	struct rfcomm_dlc *dlc;
 	int err, id;
 
-        id = __minor(tty->device) - tty->driver.minor_start;
+        id = minor(tty->device) - tty->driver.minor_start;
 
 	BT_DBG("tty %p id %d", tty, id);
 
diff -Nru a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c	Fri Oct 11 21:23:02 2002
+++ b/net/core/sock.c	Fri Oct 11 21:23:02 2002
@@ -861,7 +861,7 @@
 		spin_unlock_bh(&sk->lock.slock);
 		schedule();
 		spin_lock_bh(&sk->lock.slock);
-		if(!sk->lock.users)
+		if(!sock_owned_by_user(sk))
 			break;
 	}
 	current->state = TASK_RUNNING;
diff -Nru a/net/decnet/TODO b/net/decnet/TODO
--- a/net/decnet/TODO	Fri Oct 11 21:22:54 2002
+++ b/net/decnet/TODO	Fri Oct 11 21:22:54 2002
@@ -35,14 +35,11 @@
    file)
 
  o Find all the commonality between DECnet and IPv4 routing code and extract 
-   it into a small library of routines. [probably a project for 2.5.xx]
+   it into a small library of routines. [probably a project for 2.7.xx]
 
  o Test ip_gre tunneling works... it did the last time I tested it and it
    will have to if I'm to test routing properly.
 
- o Hello messages should be generated for each primary address on each
-   interface.
-
  o Add the routing message grabbing netfilter module [written, tested,
    awaiting merge]
 
@@ -54,4 +51,6 @@
  o Add NSP message flow control
 
  o DECnet sendpages() function
+
+ o AIO for DECnet
 
diff -Nru a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
--- a/net/decnet/af_decnet.c	Fri Oct 11 21:22:59 2002
+++ b/net/decnet/af_decnet.c	Fri Oct 11 21:22:59 2002
@@ -100,6 +100,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <linux/slab.h>
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
@@ -131,21 +132,20 @@
 #include <net/dn_fib.h>
 #include <net/dn_neigh.h>
 
-static void dn_keepalive(struct sock *sk);
+struct dn_sock {
+	struct sock sk;
+	struct dn_scp scp;
+};
 
-/*
- * decnet_address is kept in network order, decnet_ether_address is kept
- * as a string of bytes.
- */
-dn_address decnet_address = 0;
-unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 };
+static void dn_keepalive(struct sock *sk);
 
 #define DN_SK_HASH_SHIFT 8
 #define DN_SK_HASH_SIZE (1 << DN_SK_HASH_SHIFT)
 #define DN_SK_HASH_MASK (DN_SK_HASH_SIZE - 1)
 
+static kmem_cache_t *dn_sk_cachep;
 static struct proto_ops dn_proto_ops;
-rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
+static rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
 static struct sock *dn_sk_hash[DN_SK_HASH_SIZE];
 static struct sock *dn_wild_sk;
 
@@ -473,17 +473,16 @@
 	struct sock *sk;
 	struct dn_scp *scp;
 
-	if  ((sk = sk_alloc(PF_DECnet, gfp, 1, NULL)) == NULL) 
+	if  ((sk = sk_alloc(PF_DECnet, gfp, sizeof(struct dn_sock), dn_sk_cachep)) == NULL) 
 		goto no_sock;
-	scp = kmalloc(sizeof(*scp), gfp);
-	if (!scp)
-		goto free_sock;
+
+	scp = (struct dn_scp *)(sk + 1);
+	DN_SK(sk) = scp;
 
 	if (sock) {
 			sock->ops = &dn_proto_ops;
 	}
 	sock_init_data(sock,sk);
-	DN_SK(sk) = scp;
 
 	sk->backlog_rcv = dn_nsp_backlog_rcv;
 	sk->destruct    = dn_destruct;
@@ -544,8 +543,7 @@
 	MOD_INC_USE_COUNT;
 
 	return sk;
-free_sock:
-	sk_free(sk);
+
 no_sock:
 	return NULL;
 }
@@ -771,9 +769,6 @@
 	struct net_device *dev;
 	int rv;
 
-	if (sk->zapped == 0)
-		return -EINVAL;
-
 	if (addr_len != sizeof(struct sockaddr_dn))
 		return -EINVAL;
 
@@ -783,19 +778,30 @@
 	if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2))
 		return -EINVAL;
 
-	if (saddr->sdn_objnum && !capable(CAP_NET_BIND_SERVICE))
-		return -EPERM;
-
 	if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL)
 		return -EINVAL;
 
 	if (saddr->sdn_flags & ~SDF_WILD)
 		return -EINVAL;
 
-	if (saddr->sdn_flags & SDF_WILD) {
-		if (!capable(CAP_NET_BIND_SERVICE))
-			return -EPERM;
-	} else {
+#if 1
+	if ((!capable(CAP_NET_BIND_SERVICE) && saddr->sdn_objnum) ||
+	    (saddr->sdn_flags & SDF_WILD))
+		return -EACCES;
+#else
+	/*
+	 * Maybe put the default actions in the default security ops for
+	 * dn_prot_sock ? Would be nice if the capable call would go there
+	 * too.
+	 */
+	if (security_ops->dn_prot_sock(saddr) &&
+	    !capable(CAP_NET_BIND_SERVICE) || 
+	    saddr->sdn_objnum || (saddr->sdn_flags & SDF_WILD))
+		return -EACCES;
+#endif
+
+
+	if (!(saddr->sdn_flags & SDF_WILD)) {
 		if (dn_ntohs(saddr->sdn_nodeaddrl)) {
 			read_lock(&dev_base_lock);
 			for(dev = dev_base; dev; dev = dev->next) {
@@ -810,12 +816,18 @@
 		}
 	}
 
-
-	memcpy(&scp->addr, saddr, addr_len);
-	sk->zapped = 0;
-
-	if ((rv = dn_hash_sock(sk)) != 0)
-		sk->zapped = 1;
+	rv = -EINVAL;
+	lock_sock(sk);
+	if (sk->zapped != 0) {
+		memcpy(&scp->addr, saddr, addr_len);
+		sk->zapped = 0;
+
+		rv = dn_hash_sock(sk);
+		if (rv) {
+			sk->zapped = 1;
+		}
+	}
+	release_sock(sk);
 
         return rv;
 }
@@ -825,6 +837,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct dn_scp *scp = DN_SK(sk);
+	int rv;
 
 	sk->zapped = 0;
 
@@ -844,13 +857,18 @@
 		scp->accessdata.acc_accl = 0;
 		memset(scp->accessdata.acc_acc, 0, 40);
 	}
+	/* End of compatibility stuff */
 
 	scp->addr.sdn_add.a_len = dn_htons(2);
-	*(dn_address *)scp->addr.sdn_add.a_addr = decnet_address;
-
-	dn_hash_sock(sk);
+	rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr);
+	if (rv == 0) {
+		rv = dn_hash_sock(sk);
+		if (rv) {
+			sk->zapped = 1;
+		}
+	}
 
-	return 0;
+	return rv;
 }
 
 
@@ -1209,6 +1227,7 @@
 		return dn_fib_ioctl(sock, cmd, arg);
 #endif /* CONFIG_DECNET_ROUTER */
 
+#if 0
 	case OSIOCSNETADDR:
 		if (!capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
@@ -1218,7 +1237,6 @@
 		dn_dev_devices_off();
 
 		decnet_address = (unsigned short)arg;
-		dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 
 		dn_dev_devices_on();
 		err = 0;
@@ -1227,6 +1245,7 @@
 	case OSIOCGNETADDR:
 		err = put_user(decnet_address, (unsigned short *)arg);
 		break;
+#endif
         case SIOCGIFCONF:
         case SIOCGIFFLAGS:
         case SIOCGIFBRDADDR:
@@ -2227,38 +2246,24 @@
 #endif
 
 
-#ifdef MODULE
 MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
 MODULE_AUTHOR("Linux DECnet Project Team");
 MODULE_LICENSE("GPL");
 
-static int addr[2] = {0, 0};
 
-MODULE_PARM(addr, "2i");
-MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
-#endif
-
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.20-pre1s (C) 1995-2002 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.40s (C) 1995-2002 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
-#ifdef MODULE
-	if (addr[0] > 63 || addr[0] < 0) {
-		printk(KERN_ERR "DECnet: Area must be between 0 and 63");
-		return 1;
-	}
-
-	if (addr[1] > 1023 || addr[1] < 0) {
-		printk(KERN_ERR "DECnet: Node must be between 0 and 1023");
-		return 1;
-	}
-
-	decnet_address = dn_htons((addr[0] << 10) | addr[1]);
-	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
-#endif
-
         printk(banner);
 
+	dn_sk_cachep = kmem_cache_create("decnet_socket_cache",
+					 sizeof(struct dn_sock),
+					 0, SLAB_HWCACHE_ALIGN,
+					 NULL, NULL);
+	if (!dn_sk_cachep)
+		return -ENOMEM;
+
 	sock_register(&dn_family_ops);
 	dev_add_pack(&dn_dix_packet_type);
 	register_netdevice_notifier(&dn_dev_notifier);
@@ -2288,21 +2293,6 @@
 
 }
 
-#ifndef MODULE
-static int __init decnet_setup(char *str)
-{
-	unsigned short area = simple_strtoul(str, &str, 0);
-	unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
-
-	decnet_address = dn_htons(area << 10 | node);
-	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
-
-	return 1;
-}
-
-__setup("decnet=", decnet_setup);
-#endif
-
 static void __exit decnet_exit(void)
 {
 	sock_unregister(AF_DECnet);
@@ -2323,6 +2313,8 @@
 #endif /* CONFIG_DECNET_ROUTER */
 
 	proc_net_remove("decnet");
+
+	kmem_cache_destroy(dn_sk_cachep);
 }
 
 module_init(decnet_init);
diff -Nru a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
--- a/net/decnet/dn_dev.c	Fri Oct 11 21:22:55 2002
+++ b/net/decnet/dn_dev.c	Fri Oct 11 21:22:55 2002
@@ -23,6 +23,8 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
@@ -52,16 +54,23 @@
 
 extern struct neigh_table dn_neigh_table;
 
-struct net_device *decnet_default_device;
+/*
+ * decnet_address is kept in network order.
+ */
+dn_address decnet_address = 0;
+
+static rwlock_t dndev_lock = RW_LOCK_UNLOCKED;
+static struct net_device *decnet_default_device;
 
 static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
 static void dn_dev_delete(struct net_device *dev);
 static void rtmsg_ifa(int event, struct dn_ifaddr *ifa);
 
 static int dn_eth_up(struct net_device *);
-static void dn_send_brd_hello(struct net_device *dev);
+static void dn_eth_down(struct net_device *);
+static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);
 #if 0
-static void dn_send_ptp_hello(struct net_device *dev);
+static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
 #endif
 
 static struct dn_dev_parms dn_dev_list[] =  {
@@ -75,6 +84,7 @@
 	.name =		"ethernet",
 	.ctl_name =	NET_DECNET_CONF_ETHER,
 	.up =		dn_eth_up,
+	.down = 	dn_eth_down,
 	.timer3 =	dn_send_brd_hello,
 },
 {
@@ -249,6 +259,51 @@
 	}
 }
 
+struct net_device *dn_dev_get_default(void)
+{
+	struct net_device *dev;
+	read_lock(&dndev_lock);
+	dev = decnet_default_device;
+	if (dev) {
+		if (dev->dn_ptr)
+			dev_hold(dev);
+		else
+			dev = NULL;
+	}
+	read_unlock(&dndev_lock);
+	return dev;
+}
+
+int dn_dev_set_default(struct net_device *dev, int force)
+{
+	struct net_device *old = NULL;
+	int rv = -EBUSY;
+	if (!dev->dn_ptr)
+		return -ENODEV;
+	write_lock(&dndev_lock);
+	if (force || decnet_default_device == NULL) {
+		old = decnet_default_device;
+		decnet_default_device = dev;
+		rv = 0;
+	}
+	write_unlock(&dndev_lock);
+	if (old)
+		dev_put(dev);
+	return rv;
+}
+
+static void dn_dev_check_default(struct net_device *dev)
+{
+	write_lock(&dndev_lock);
+	if (dev == decnet_default_device) {
+		decnet_default_device = NULL;
+	} else {
+		dev = NULL;
+	}
+	write_unlock(&dndev_lock);
+	if (dev)
+		dev_put(dev);
+}
 
 static int dn_forwarding_proc(ctl_table *table, int write, 
 				struct file *filep,
@@ -364,9 +419,20 @@
 static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy)
 {
 	struct dn_ifaddr *ifa1 = *ifap;
+	unsigned char mac_addr[6];
+	struct net_device *dev = dn_db->dev;
+
+	ASSERT_RTNL();
 
 	*ifap = ifa1->ifa_next;
 
+	if (dn_db->dev->type == ARPHRD_ETHER) {
+		if (ifa1->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+			dn_dn2eth(mac_addr, ifa1->ifa_local);
+			dev_mc_delete(dev, mac_addr, ETH_ALEN, 0);
+		}
+	}
+
 	rtmsg_ifa(RTM_DELADDR, ifa1);
 
 	if (destroy) {
@@ -379,9 +445,25 @@
 
 static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
 {
-	/*
-	 * FIXME: Duplicate check here.
-	 */
+	struct net_device *dev = dn_db->dev;
+	struct dn_ifaddr *ifa1;
+	unsigned char mac_addr[6];
+
+	ASSERT_RTNL();
+
+	/* Check for duplicates */	
+	for(ifa1 = dn_db->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
+		if (ifa1->ifa_local == ifa->ifa_local)
+			return -EEXIST;
+	}
+
+	if (dev->type == ARPHRD_ETHER) {
+		if (ifa->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+			dn_dn2eth(mac_addr, ifa->ifa_local);
+			dev_mc_add(dev, mac_addr, ETH_ALEN, 0);
+			dev_mc_upload(dev);
+		}
+	}
 
 	ifa->ifa_next = dn_db->ifa_list;
 	dn_db->ifa_list = ifa;
@@ -394,6 +476,7 @@
 static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
 {
 	struct dn_dev *dn_db = dev->dn_ptr;
+	int rv;
 
 	if (dn_db == NULL) {
 		int err;
@@ -407,7 +490,10 @@
 	if (dev->flags & IFF_LOOPBACK)
 		ifa->ifa_scope = RT_SCOPE_HOST;
 
-	return dn_dev_insert_ifa(dn_db, ifa);
+	rv = dn_dev_insert_ifa(dn_db, ifa);
+	if (rv)
+		dn_dev_free_ifa(ifa);
+	return rv;
 }
 
 
@@ -538,6 +624,7 @@
 	struct dn_dev *dn_db;
 	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
 	struct dn_ifaddr *ifa;
+	int rv;
 
 	if (rta[IFA_LOCAL-1] == NULL)
 		return -EINVAL;
@@ -564,7 +651,10 @@
 	else
 		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 
-	return dn_dev_insert_ifa(dn_db, ifa);
+	rv = dn_dev_insert_ifa(dn_db, ifa);
+	if (rv)
+		dn_dev_free_ifa(ifa);
+	return rv;
 }
 
 static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
@@ -651,7 +741,52 @@
 	return skb->len;
 }
 
-static void dn_send_endnode_hello(struct net_device *dev)
+static int dn_dev_get_first(struct net_device *dev, dn_address *addr)
+{
+	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
+	struct dn_ifaddr *ifa;
+	int rv = -ENODEV;
+	if (dn_db == NULL)
+		goto out;
+	ifa = dn_db->ifa_list;
+	if (ifa != NULL) {
+		*addr = ifa->ifa_local;
+		rv = 0;
+	}
+out:
+	return rv;
+}
+
+/* 
+ * Find a default address to bind to.
+ *
+ * This is one of those areas where the initial VMS concepts don't really
+ * map onto the Linux concepts, and since we introduced multiple addresses
+ * per interface we have to cope with slightly odd ways of finding out what
+ * "our address" really is. Mostly its not a problem; for this we just guess
+ * a sensible default. Eventually the routing code will take care of all the
+ * nasties for us I hope.
+ */
+int dn_dev_bind_default(dn_address *addr)
+{
+	struct net_device *dev;
+	int rv;
+	dev = dn_dev_get_default();
+last_chance:
+	if (dev) {
+		read_lock(&dev_base_lock);
+		rv = dn_dev_get_first(dev, addr);
+		read_unlock(&dev_base_lock);
+		dev_put(dev);
+		if (rv == 0 || dev == &loopback_dev)
+			return rv;
+	}
+	dev = &loopback_dev;
+	dev_hold(dev);
+	goto last_chance;
+}
+
+static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
         struct endnode_hello_message *msg;
         struct sk_buff *skb = NULL;
@@ -667,7 +802,7 @@
 
         msg->msgflg  = 0x0D;
         memcpy(msg->tiver, dn_eco_version, 3);
-        memcpy(msg->id, decnet_ether_address, 6);
+	dn_dn2eth(msg->id, ifa->ifa_local);
         msg->iinfo   = DN_RT_INFO_ENDN;
         msg->blksize = dn_htons(dn_db->parms.blksize);
         msg->area    = 0x00;
@@ -689,7 +824,7 @@
 
 	skb->nh.raw = skb->data;
 
-	dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
+	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, msg->id);
 }
 
 
@@ -697,7 +832,7 @@
 
 #define DRDELAY (5 * HZ)
 
-static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db)
+static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
 {
 	/* First check time since device went up */
 	if ((jiffies - dn_db->uptime) < DRDELAY)
@@ -715,13 +850,13 @@
 	if (dn->priority != dn_db->parms.priority)
 		return 0;
 
-	if (dn_ntohs(dn->addr) < dn_ntohs(decnet_address))
+	if (dn_ntohs(dn->addr) < dn_ntohs(ifa->ifa_local))
 		return 1;
 
 	return 0;
 }
 
-static void dn_send_router_hello(struct net_device *dev)
+static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
 	int n;
 	struct dn_dev *dn_db = dev->dn_ptr;
@@ -731,6 +866,7 @@
 	unsigned char *ptr;
 	unsigned char *i1, *i2;
 	unsigned short *pktlen;
+	char *src;
 
 	if (dn_db->parms.blksize < (26 + 7))
 		return;
@@ -753,7 +889,8 @@
 	*ptr++ = 2; /* ECO */
 	*ptr++ = 0;
 	*ptr++ = 0;
-	memcpy(ptr, decnet_ether_address, ETH_ALEN);
+	dn_dn2eth(ptr, ifa->ifa_local);
+	src = ptr;
 	ptr += ETH_ALEN;
 	*ptr++ = dn_db->parms.forwarding == 1 ? 
 			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
@@ -781,34 +918,34 @@
 
 	skb->nh.raw = skb->data;
 
-	if (dn_am_i_a_router(dn, dn_db)) {
+	if (dn_am_i_a_router(dn, dn_db, ifa)) {
 		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
 		if (skb2) {
-			dn_rt_finish_output(skb2, dn_rt_all_end_mcast);
+			dn_rt_finish_output(skb2, dn_rt_all_end_mcast, src);
 		}
 	}
 
-	dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
+	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
 }
 
-static void dn_send_brd_hello(struct net_device *dev)
+static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
 	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
 
 	if (dn_db->parms.forwarding == 0)
-		dn_send_endnode_hello(dev);
+		dn_send_endnode_hello(dev, ifa);
 	else
-		dn_send_router_hello(dev);
+		dn_send_router_hello(dev, ifa);
 }
 #else
-static void dn_send_brd_hello(struct net_device *dev)
+static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
-	dn_send_endnode_hello(dev);
+	dn_send_endnode_hello(dev, ifa);
 }
 #endif
 
 #if 0
-static void dn_send_ptp_hello(struct net_device *dev)
+static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
 	int tdlen = 16;
 	int size = dev->hard_header_len + 2 + 4 + tdlen;
@@ -817,6 +954,7 @@
 	int i;
 	unsigned char *ptr;
 	struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
+	char src[ETH_ALEN];
 
 	if (skb == NULL)
 		return ;
@@ -826,21 +964,15 @@
 	ptr = skb_put(skb, 2 + 4 + tdlen);
 
 	*ptr++ = DN_RT_PKT_HELO;
-	*((dn_address *)ptr) = decnet_address;
+	*((dn_address *)ptr) = ifa->ifa_local;
 	ptr += 2;
 	*ptr++ = tdlen;
 
 	for(i = 0; i < tdlen; i++)
 		*ptr++ = 0252;
 
-	if (dn_am_i_a_router(dn, dn_db)) {
-		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
-		if (skb2) {
-			dn_rt_finish_output(skb2, dn_rt_all_end_mcast);
-		}
-	}
-
-	dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
+	dn_dn2eth(src, ifa->ifa_local);
+	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
 }
 #endif
 
@@ -860,16 +992,31 @@
 	return 0;
 }
 
+static void dn_eth_down(struct net_device *dev)
+{
+	struct dn_dev *dn_db = dev->dn_ptr;
+
+	if (dn_db->parms.forwarding == 0)
+		dev_mc_delete(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
+	else
+		dev_mc_delete(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
+}
+
 static void dn_dev_set_timer(struct net_device *dev);
 
 static void dn_dev_timer_func(unsigned long arg)
 {
 	struct net_device *dev = (struct net_device *)arg;
 	struct dn_dev *dn_db = dev->dn_ptr;
+	struct dn_ifaddr *ifa;
 
 	if (dn_db->t3 <= dn_db->parms.t2) {
-		if (dn_db->parms.timer3)
-			dn_db->parms.timer3(dev);
+		if (dn_db->parms.timer3) {
+			for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) {
+				if (!(ifa->ifa_flags & IFA_F_SECONDARY))
+					dn_db->parms.timer3(dev, ifa);
+			}
+		}
 		dn_db->t3 = dn_db->parms.t3;
 	} else {
 		dn_db->t3 -= dn_db->parms.t2;
@@ -917,8 +1064,6 @@
 	dn_db->dev = dev;
 	init_timer(&dn_db->timer);
 
-	memcpy(dn_db->addr, decnet_ether_address, ETH_ALEN); /* To go... */
-
 	dn_db->uptime = jiffies;
 	if (dn_db->parms.up) {
 		if (dn_db->parms.up(dev) < 0) {
@@ -929,7 +1074,6 @@
 	}
 
 	dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
-	/* dn_db->neigh_parms->neigh_setup = dn_db->parms.neigh_setup; */
 
 	dn_dev_sysctl_register(dev, &dn_db->parms);
 
@@ -945,27 +1089,64 @@
  * the loopback device & ethernet devices with correct
  * MAC addreses automatically. Others must be started
  * specifically.
+ *
+ * FIXME: How should we configure the loopback address ? If we could dispense
+ * with using decnet_address here and for autobind, it will be one less thing
+ * for users to worry about setting up.
  */
+
 void dn_dev_up(struct net_device *dev)
 {
 	struct dn_ifaddr *ifa;
+	dn_address addr = decnet_address;
+	int maybe_default = 0;
+	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
 
 	if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
 		return;
 
-	if (dev->type == ARPHRD_ETHER)
-		if (memcmp(dev->dev_addr, decnet_ether_address, ETH_ALEN) != 0)
+	/*
+	 * Need to ensure that loopback device has a dn_db attached to it
+	 * to allow creation of neighbours against it, even though it might
+	 * not have a local address of its own. Might as well do the same for
+	 * all autoconfigured interfaces.
+	 */
+	if (dn_db == NULL) {
+		int err;
+		dn_db = dn_dev_create(dev, &err);
+		if (dn_db == NULL)
 			return;
+	}
+
+	if (dev->type == ARPHRD_ETHER) {
+		if (memcmp(dev->dev_addr, dn_hiord, 4) != 0)
+			return;
+		addr = dn_htons(dn_eth2dn(dev->dev_addr));
+		maybe_default = 1;
+	}
+
+	if (addr == 0)
+		return;
 
 	if ((ifa = dn_dev_alloc_ifa()) == NULL)
 		return;
 
-	ifa->ifa_local = decnet_address;
+	ifa->ifa_local = addr;
 	ifa->ifa_flags = 0;
 	ifa->ifa_scope = RT_SCOPE_UNIVERSE;
 	strcpy(ifa->ifa_label, dev->name);
 
 	dn_dev_set_ifa(dev, ifa);
+
+	/*
+	 * Automagically set the default device to the first automatically
+	 * configured ethernet card in the system.
+	 */
+	if (maybe_default) {
+		dev_hold(dev);
+		if (dn_dev_set_default(dev, 0))
+			dev_put(dev);
+	}
 }
 
 static void dn_dev_delete(struct net_device *dev)
@@ -976,14 +1157,10 @@
 		return;
 
 	del_timer_sync(&dn_db->timer);
-
 	dn_dev_sysctl_unregister(&dn_db->parms);
-
+	dn_dev_check_default(dev);
 	neigh_ifdown(&dn_neigh_table, dev);
 
-	if (dev == decnet_default_device)
-		decnet_default_device = NULL;
-
 	if (dn_db->parms.down)
 		dn_db->parms.down(dev);
 
@@ -1204,8 +1381,28 @@
 #endif
 };
 
+#ifdef MODULE
+static int addr[2] = {0, 0};
+
+MODULE_PARM(addr, "2i");
+MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
+#endif
+
 void __init dn_dev_init(void)
 {
+#ifdef MODULE
+        if (addr[0] > 63 || addr[0] < 0) {
+                printk(KERN_ERR "DECnet: Area must be between 0 and 63");
+                return;
+        }
+
+        if (addr[1] > 1023 || addr[1] < 0) {
+                printk(KERN_ERR "DECnet: Node must be between 0 and 1023");
+                return;
+        }
+
+        decnet_address = dn_htons((addr[0] << 10) | addr[1]);
+#endif
 
 	dn_dev_devices_on();
 #ifdef CONFIG_DECNET_SIOCGIFCONF
@@ -1247,3 +1444,18 @@
 
 	dn_dev_devices_off();
 }
+
+#ifndef MODULE
+static int __init decnet_setup(char *str)
+{
+        unsigned short area = simple_strtoul(str, &str, 0);
+        unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
+
+        decnet_address = dn_htons(area << 10 | node);
+
+        return 1;
+}
+
+__setup("decnet=", decnet_setup);  
+#endif
+
diff -Nru a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
--- a/net/decnet/dn_neigh.c	Fri Oct 11 21:23:02 2002
+++ b/net/decnet/dn_neigh.c	Fri Oct 11 21:23:02 2002
@@ -181,10 +181,13 @@
 static int dn_neigh_output_packet(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb->dst;
+	struct dn_route *rt = (struct dn_route *)dst;
 	struct neighbour *neigh = dst->neighbour;
 	struct net_device *dev = neigh->dev;
+	char mac_addr[ETH_ALEN];
 
-	if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, NULL, skb->len) >= 0)
+	dn_dn2eth(mac_addr, rt->rt_saddr);
+	if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0)
 		return neigh->ops->queue_xmit(skb);
 
 	if (net_ratelimit())
diff -Nru a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
--- a/net/decnet/dn_nsp_in.c	Fri Oct 11 21:22:55 2002
+++ b/net/decnet/dn_nsp_in.c	Fri Oct 11 21:22:55 2002
@@ -800,8 +800,8 @@
 			printk(KERN_DEBUG "NSP: 0x%02x 0x%02x 0x%04x 0x%04x %d\n",
 				(int)cb->rt_flags, (int)cb->nsp_flags, 
 				(int)cb->src_port, (int)cb->dst_port, 
-				(int)sk->lock.users);
-		if (sk->lock.users == 0)
+				(int)sock_owned_by_user(sk));
+		if (!sock_owned_by_user(sk))
 			ret = dn_nsp_backlog_rcv(sk, skb);
 		else
 			sk_add_backlog(sk, skb);
diff -Nru a/net/decnet/dn_route.c b/net/decnet/dn_route.c
--- a/net/decnet/dn_route.c	Fri Oct 11 21:23:04 2002
+++ b/net/decnet/dn_route.c	Fri Oct 11 21:23:04 2002
@@ -110,7 +110,7 @@
 static unsigned dn_rt_hash_mask;
 
 static struct timer_list dn_route_timer;
-static struct timer_list dn_rt_flush_timer = { function: dn_run_flush };
+static struct timer_list dn_rt_flush_timer = { .function = dn_run_flush };
 int decnet_dst_gc_interval = 2;
 
 static struct dst_ops dn_dst_ops = {
@@ -334,7 +334,7 @@
 	*dst = tmp;
 
 	skb->pkt_type = PACKET_OUTGOING;
-	dn_rt_finish_output(skb, NULL);
+	dn_rt_finish_output(skb, NULL, NULL);
 	return NET_RX_SUCCESS;
 }
 
@@ -380,7 +380,7 @@
 	memcpy(dst_addr, tmp, ETH_ALEN);
 
 	skb->pkt_type = PACKET_OUTGOING;
-	dn_rt_finish_output(skb, tmp);
+	dn_rt_finish_output(skb, dst_addr, src_addr);
 	return NET_RX_SUCCESS;
 }
 
@@ -641,7 +641,9 @@
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	struct dst_entry *dst = skb->dst;
 	struct neighbour *neigh;
+#ifdef CONFIG_NETFILTER
 	struct net_device *dev = skb->dev;
+#endif
 	int err = -EINVAL;
 
 	if ((neigh = dst->neighbour) == NULL)
@@ -711,10 +713,11 @@
 static int dn_route_output_slow(struct dst_entry **pprt, dn_address dst, dn_address src, int flags)
 {
 	struct dn_route *rt = NULL;
-	struct net_device *dev = decnet_default_device;
+	struct net_device *dev = NULL;
 	struct neighbour *neigh = NULL;
 	struct dn_dev *dn_db;
 	unsigned hash;
+
 #ifdef CONFIG_DECNET_ROUTER
 	struct dn_fib_key key;
 	struct dn_fib_res res;
@@ -765,13 +768,25 @@
 			goto got_route;
 	}
 
+	dev = dn_dev_get_default();
 	if (dev == NULL)
 		return -EINVAL;
 
 	dn_db = dev->dn_ptr;
 
-	if (dn_db == NULL)
+	/* Check to see if its one of our own local addresses */
+	if (dn_dev_islocal(dev, dst)) {
+		struct net_device *lo = &loopback_dev;
+		if (lo->dn_ptr) {
+			neigh = __neigh_lookup(&dn_neigh_table, &dst, lo, 1);
+			if (neigh)
+				goto got_route;
+		}
+		if (net_ratelimit())
+			printk("dn_route_output_slow: Dest is local interface address, but loopback device is not up\n");
+		dev_put(dev);
 		return -EINVAL;
+	}
 
 	/* Try default router */
 	if ((neigh = neigh_clone(dn_db->router)) != NULL)
@@ -781,10 +796,12 @@
 	if ((neigh = __neigh_lookup(&dn_neigh_table, &dst, dev, 1)) != NULL)
 		goto got_route;
 
-
+	dev_put(dev);
 	return -EINVAL;
 
 got_route:
+	if (dev)
+		dev_put(dev);
 
 	if ((rt = dst_alloc(&dn_dst_ops)) == NULL) {
 		neigh_release(neigh);
@@ -809,7 +826,7 @@
 	rt->u.dst.output = dn_output;
 	rt->u.dst.input  = dn_rt_bug;
 
-	if (dn_dev_islocal(neigh->dev, rt->rt_daddr))
+	if (neigh->dev->flags & IFF_LOOPBACK)
 		rt->u.dst.input = dn_nsp_rx;
 
 	hash = dn_hash(rt->key.saddr, rt->key.daddr);
diff -Nru a/net/decnet/dn_timer.c b/net/decnet/dn_timer.c
--- a/net/decnet/dn_timer.c	Fri Oct 11 21:22:59 2002
+++ b/net/decnet/dn_timer.c	Fri Oct 11 21:22:59 2002
@@ -57,7 +57,7 @@
 	sock_hold(sk);
 	bh_lock_sock(sk);
 
-	if (sk->lock.users != 0) {
+	if (sock_owned_by_user(sk)) {
 		sk->timer.expires = jiffies + HZ / 10;
 		add_timer(&sk->timer);
 		goto out;
@@ -115,7 +115,7 @@
 	struct dn_scp *scp = DN_SK(sk);
 
 	bh_lock_sock(sk);
-	if (sk->lock.users != 0) {
+	if (sock_owned_by_user(sk)) {
 		scp->delack_timer.expires = jiffies + HZ / 20;
 		add_timer(&scp->delack_timer);
 		goto out;
diff -Nru a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
--- a/net/decnet/sysctl_net_decnet.c	Fri Oct 11 21:22:54 2002
+++ b/net/decnet/sysctl_net_decnet.c	Fri Oct 11 21:22:54 2002
@@ -9,6 +9,7 @@
  *
  *
  * Changes:
+ * Steve Whitehouse - C99 changes and default device handling
  *
  */
 #include <linux/config.h>
@@ -152,7 +153,6 @@
 		dn_dev_devices_off();
 
 		decnet_address = addr;
-		dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 
 		dn_dev_devices_on();
 	}
@@ -187,7 +187,6 @@
 		dn_dev_devices_off();
 
 		decnet_address = dnaddr;
-		dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 
 		dn_dev_devices_on();
 
@@ -218,9 +217,10 @@
 				void **context)
 {
 	size_t len;
-	struct net_device *dev = decnet_default_device;
+	struct net_device *dev;
 	char devname[17];
 	size_t namel;
+	int rv = 0;
 
 	devname[0] = 0;
 
@@ -228,8 +228,11 @@
 		if (get_user(len, oldlenp))
 			return -EFAULT;
 		if (len) {
-			if (dev)
+			dev = dn_dev_get_default();
+			if (dev) {
 				strcpy(devname, dev->name);
+				dev_put(dev);
+			}
 
 			namel = strlen(devname) + 1;
 			if (len > namel) len = namel;	
@@ -251,16 +254,19 @@
 
 		devname[newlen] = 0;
 
-		if ((dev = __dev_get_by_name(devname)) == NULL)
+		dev = dev_get_by_name(devname);
+		if (dev == NULL)
 			return -ENODEV;
 
-		if (dev->dn_ptr == NULL)
-			return -ENODEV;
-
-		decnet_default_device = dev;
+		rv = -ENODEV;
+		if (dev->dn_ptr != NULL) {
+			rv = dn_dev_set_default(dev, 1);
+			if (rv)
+				dev_put(dev);
+		}
 	}
 
-	return 0;
+	return rv;
 }
 
 
@@ -269,7 +275,7 @@
 				void *buffer, size_t *lenp)
 {
 	size_t len;
-	struct net_device *dev = decnet_default_device;
+	struct net_device *dev;
 	char devname[17];
 
 	if (!*lenp || (filp->f_pos && !write)) {
@@ -287,24 +293,32 @@
 		devname[*lenp] = 0;
 		strip_it(devname);
 
-		if ((dev = __dev_get_by_name(devname)) == NULL)
+		dev = dev_get_by_name(devname);
+		if (dev == NULL)
 			return -ENODEV;
 
-		if (dev->dn_ptr == NULL)
+		if (dev->dn_ptr == NULL) {
+			dev_put(dev);
 			return -ENODEV;
+		}
 
-		decnet_default_device = dev;
+		if (dn_dev_set_default(dev, 1)) {
+			dev_put(dev);
+			return -ENODEV;
+		}
 		filp->f_pos += *lenp;
 
 		return 0;
 	}
 
+	dev = dn_dev_get_default();
 	if (dev == NULL) {
 		*lenp = 0;
 		return 0;
 	}
 
 	strcpy(devname, dev->name);
+	dev_put(dev);
 	len = strlen(devname);
 	devname[len++] = '\n';
 
@@ -320,51 +334,125 @@
 }
 
 static ctl_table dn_table[] = {
-	{NET_DECNET_NODE_ADDRESS, "node_address", NULL, 7, 0644, NULL,
-	dn_node_address_handler, dn_node_address_strategy, NULL,
-	NULL, NULL},
-	{NET_DECNET_NODE_NAME, "node_name", node_name, 7, 0644, NULL,
-	&proc_dostring, &sysctl_string, NULL, NULL, NULL},
-	{NET_DECNET_DEFAULT_DEVICE, "default_device", NULL, 16, 0644, NULL,
-	dn_def_dev_handler, dn_def_dev_strategy, NULL, NULL, NULL},
-	{NET_DECNET_TIME_WAIT, "time_wait", &decnet_time_wait,
-	sizeof(int), 0644,
-	NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
-	&min_decnet_time_wait, &max_decnet_time_wait},
-	{NET_DECNET_DN_COUNT, "dn_count", &decnet_dn_count,
-	sizeof(int), 0644,
-	NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
-	&min_state_count, &max_state_count},
-	{NET_DECNET_DI_COUNT, "di_count", &decnet_di_count,
-	sizeof(int), 0644,
-	NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
-	&min_state_count, &max_state_count},
-	{NET_DECNET_DR_COUNT, "dr_count", &decnet_dr_count,
-	sizeof(int), 0644,
-	NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
-	&min_state_count, &max_state_count},
-	{NET_DECNET_DST_GC_INTERVAL, "dst_gc_interval", &decnet_dst_gc_interval,
-	sizeof(int), 0644,
-	NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
-	&min_decnet_dst_gc_interval, &max_decnet_dst_gc_interval},
-	{NET_DECNET_NO_FC_MAX_CWND, "no_fc_max_cwnd", &decnet_no_fc_max_cwnd,
-	sizeof(int), 0644,
-	NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
-	&min_decnet_no_fc_max_cwnd, &max_decnet_no_fc_max_cwnd},
-	{NET_DECNET_DEBUG_LEVEL, "debug", &decnet_debug_level, 
-	sizeof(int), 0644, 
-	NULL, &proc_dointvec, &sysctl_intvec, NULL,
-	NULL, NULL},
+	{
+		.ctl_name = NET_DECNET_NODE_ADDRESS, 
+		.procname = "node_address", 
+		.maxlen = 7, 
+		.mode = 0644, 
+		.proc_handler = dn_node_address_handler,
+		.strategy = dn_node_address_strategy,
+	},
+	{
+		.ctl_name = NET_DECNET_NODE_NAME,
+		.procname = "node_name",
+		.data = node_name, 
+		.maxlen = 7,
+		.mode = 0644,
+		.proc_handler = &proc_dostring,
+		.strategy = &sysctl_string,
+	},
+	{
+		.ctl_name = NET_DECNET_DEFAULT_DEVICE,
+		.procname = "default_device", 
+		.maxlen = 16, 
+		.mode = 0644,
+		.proc_handler = dn_def_dev_handler,
+		.strategy = dn_def_dev_strategy,
+	},
+	{
+		.ctl_name = NET_DECNET_TIME_WAIT,
+		.procname = "time_wait",
+		.data = &decnet_time_wait,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec_minmax,
+		.strategy = &sysctl_intvec,
+		.extra1 = &min_decnet_time_wait,
+		.extra2 = &max_decnet_time_wait
+	},
+	{
+		.ctl_name = NET_DECNET_DN_COUNT,
+		.procname = "dn_count",
+		.data = &decnet_dn_count,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec_minmax,
+		.strategy = &sysctl_intvec,
+		.extra1 = &min_state_count,
+		.extra2 = &max_state_count
+	},
+	{
+		.ctl_name = NET_DECNET_DI_COUNT,
+		.procname = "di_count",
+		.data = &decnet_di_count,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec_minmax,
+		.strategy = &sysctl_intvec,
+		.extra1 = &min_state_count,
+		.extra2 = &max_state_count
+	},
+	{
+		.ctl_name = NET_DECNET_DR_COUNT,
+		.procname = "dr_count",
+		.data = &decnet_dr_count,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec_minmax,
+		.strategy = &sysctl_intvec,
+		.extra1 = &min_state_count,
+		.extra2 = &max_state_count
+	},
+	{
+		.ctl_name = NET_DECNET_DST_GC_INTERVAL,
+		.procname = "dst_gc_interval",
+		.data = &decnet_dst_gc_interval,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec_minmax,
+		.strategy = &sysctl_intvec,
+		.extra1 = &min_decnet_dst_gc_interval,
+		.extra2 = &max_decnet_dst_gc_interval
+	},
+	{
+		.ctl_name = NET_DECNET_NO_FC_MAX_CWND,
+		.procname = "no_fc_max_cwnd",
+		.data = &decnet_no_fc_max_cwnd,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec_minmax,
+		.strategy = &sysctl_intvec,
+		.extra1 = &min_decnet_no_fc_max_cwnd,
+		.extra2 = &max_decnet_no_fc_max_cwnd
+	},
+	{
+		.ctl_name = NET_DECNET_DEBUG_LEVEL,
+		.procname = "debug",
+		.data = &decnet_debug_level,
+		.maxlen = sizeof(int),
+		.mode = 0644,
+		.proc_handler = &proc_dointvec,
+		.strategy = &sysctl_intvec,
+	},
 	{0}
 };
 
 static ctl_table dn_dir_table[] = {
-	{NET_DECNET, "decnet", NULL, 0, 0555, dn_table},
+	{
+		.ctl_name = NET_DECNET, 
+		.procname = "decnet", 
+		.mode = 0555, 
+		.child = dn_table},
 	{0}
 };
 
 static ctl_table dn_root_table[] = {
-	{CTL_NET, "net", NULL, 0, 0555, dn_dir_table},
+	{
+		.ctl_name = CTL_NET, 
+		.procname = "net", 
+		.mode = 0555, 
+		.child = dn_dir_table
+	},
 	{0}
 };
 
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Fri Oct 11 21:22:54 2002
+++ b/net/ipv4/af_inet.c	Fri Oct 11 21:22:54 2002
@@ -1093,6 +1093,25 @@
 	}
 }
 
+#ifdef CONFIG_IP_MULTICAST
+static struct inet_protocol igmp_protocol = {
+	.handler =	igmp_rcv,
+};
+#endif
+
+static struct inet_protocol tcp_protocol = {
+	.handler =	tcp_v4_rcv,
+	.err_handler =	tcp_v4_err,
+};
+
+static struct inet_protocol udp_protocol = {
+	.handler =	udp_rcv,
+	.err_handler =	udp_err,
+};
+
+static struct inet_protocol icmp_protocol = {
+	.handler =	icmp_rcv,
+};
 
 /*
  *	Called by socket.c on kernel startup.  
@@ -1101,7 +1120,6 @@
 static int __init inet_init(void)
 {
 	struct sk_buff *dummy_skb;
-	struct inet_protocol *p;
 	struct inet_protosw *q;
 	struct list_head *r;
 
@@ -1131,16 +1149,19 @@
   	(void)sock_register(&inet_family_ops);
 
 	/*
-	 *	Add all the protocols. 
+	 *	Add all the base protocols.
 	 */
 
-	printk(KERN_INFO "IP Protocols: ");
-	for (p = inet_protocol_base; p;) {
-		struct inet_protocol *tmp = (struct inet_protocol *)p->next;
-		inet_add_protocol(p);
-		printk("%s%s", p->name, tmp ? ", " : "\n");
-		p = tmp;
-	}
+	if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
+		printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
+	if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
+		printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
+	if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
+		printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
+#ifdef CONFIG_IP_MULTICAST
+	if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
+		printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
+#endif
 
 	/* Register the socket-side information for inet_create. */
 	for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c
--- a/net/ipv4/icmp.c	Fri Oct 11 21:23:04 2002
+++ b/net/ipv4/icmp.c	Fri Oct 11 21:23:04 2002
@@ -719,23 +719,10 @@
 	 *	we are OK.
 	 */
 
-	ipprot = (struct inet_protocol *)inet_protos[hash];
-	while (ipprot) {
-		struct inet_protocol *nextip;
+	ipprot = inet_protos[hash];
+	if (ipprot && ipprot->err_handler)
+		ipprot->err_handler(skb, info);
 
-		nextip = (struct inet_protocol *)ipprot->next;
-		/*
-		 *	Pass it off to everyone who wants it.
-		 */
-
-		/* RFC1122: OK. Passes appropriate ICMP errors to the */
-		/* appropriate protocol layer (MUST), as per 3.2.2. */
-
-		if (protocol == ipprot->protocol && ipprot->err_handler)
- 			ipprot->err_handler(skb, info);
-
-		ipprot = nextip;
-  	}
 out:
 	return;
 out_err:
diff -Nru a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
--- a/net/ipv4/ip_gre.c	Fri Oct 11 21:23:02 2002
+++ b/net/ipv4/ip_gre.c	Fri Oct 11 21:23:02 2002
@@ -1259,13 +1259,8 @@
 
 
 static struct inet_protocol ipgre_protocol = {
-  ipgre_rcv,             /* GRE handler          */
-  ipgre_err,             /* TUNNEL error control */
-  0,                    /* next                 */
-  IPPROTO_GRE,          /* protocol ID          */
-  0,                    /* copy                 */
-  NULL,                 /* data                 */
-  "GRE"                 /* name                 */
+	.handler	=	ipgre_rcv,
+	.err_handler	=	ipgre_err,
 };
 
 
@@ -1281,9 +1276,13 @@
 {
 	printk(KERN_INFO "GRE over IPv4 tunneling driver\n");
 
+	if (inet_add_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) {
+		printk(KERN_INFO "ipgre init: can't add protocol\n");
+		return -EAGAIN;
+	}
+
 	ipgre_fb_tunnel_dev.priv = (void*)&ipgre_fb_tunnel;
 	register_netdev(&ipgre_fb_tunnel_dev);
-	inet_add_protocol(&ipgre_protocol);
 	return 0;
 }
 
@@ -1291,7 +1290,7 @@
 
 void cleanup_module(void)
 {
-	if ( inet_del_protocol(&ipgre_protocol) < 0 )
+	if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
 		printk(KERN_INFO "ipgre close: can't remove protocol\n");
 
 	unregister_netdev(&ipgre_fb_tunnel_dev);
diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
--- a/net/ipv4/ip_input.c	Fri Oct 11 21:22:52 2002
+++ b/net/ipv4/ip_input.c	Fri Oct 11 21:22:52 2002
@@ -194,28 +194,6 @@
 	return 0;
 }
 
-/* Handle this out of line, it is rare. */
-static int ip_run_ipprot(struct sk_buff *skb, struct iphdr *iph,
-			 struct inet_protocol *ipprot, int force_copy)
-{
-	int ret = 0;
-
-	do {
-		if (ipprot->protocol == iph->protocol) {
-			struct sk_buff *skb2 = skb;
-			if (ipprot->copy || force_copy)
-				skb2 = skb_clone(skb, GFP_ATOMIC);
-			if(skb2 != NULL) {
-				ret = 1;
-				ipprot->handler(skb2);
-			}
-		}
-		ipprot = (struct inet_protocol *) ipprot->next;
-	} while(ipprot != NULL);
-
-	return ret;
-}
-
 static inline int ip_local_deliver_finish(struct sk_buff *skb)
 {
 	int ihl = skb->nh.iph->ihl*4;
@@ -239,44 +217,31 @@
 	{
 		/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
 		int protocol = skb->nh.iph->protocol;
-		int hash = protocol & (MAX_INET_PROTOS - 1);
-		struct sock *raw_sk = raw_v4_htable[hash];
+		int hash;
+		struct sock *raw_sk;
 		struct inet_protocol *ipprot;
-		int flag;
+
+	resubmit:
+		hash = protocol & (MAX_INET_PROTOS - 1);
+		raw_sk = raw_v4_htable[hash];
 
 		/* If there maybe a raw socket we must check - if not we
 		 * don't care less
 		 */
-		if(raw_sk != NULL)
-			raw_sk = raw_v4_input(skb, skb->nh.iph, hash);
+		if (raw_sk)
+			raw_v4_input(skb, skb->nh.iph, hash);
 
-		ipprot = (struct inet_protocol *) inet_protos[hash];
-		flag = 0;
-		if(ipprot != NULL) {
-			if(raw_sk == NULL &&
-			   ipprot->next == NULL &&
-			   ipprot->protocol == protocol) {
-				int ret;
-
-				/* Fast path... */
-				ret = ipprot->handler(skb);
-
-				return ret;
-			} else {
-				flag = ip_run_ipprot(skb, skb->nh.iph, ipprot, (raw_sk != NULL));
+		if ((ipprot = inet_protos[hash]) != NULL) {
+			int ret = ipprot->handler(skb);
+			if (ret < 0) {
+				protocol = -ret;
+				goto resubmit;
+			}
+		} else {
+			if (!raw_sk) {
+				icmp_send(skb, ICMP_DEST_UNREACH,
+					  ICMP_PROT_UNREACH, 0);
 			}
-		}
-
-		/* All protocols checked.
-		 * If this packet was a broadcast, we may *not* reply to it, since that
-		 * causes (proven, grin) ARP storms and a leakage of memory (i.e. all
-		 * ICMP reply messages get queued up for transmission...)
-		 */
-		if(raw_sk != NULL) {	/* Shift to last raw user */
-			raw_rcv(raw_sk, skb);
-			sock_put(raw_sk);
-		} else if (!flag) {		/* Free and report errors */
-			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);	
 			kfree_skb(skb);
 		}
 	}
diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c
--- a/net/ipv4/ipip.c	Fri Oct 11 21:23:05 2002
+++ b/net/ipv4/ipip.c	Fri Oct 11 21:23:05 2002
@@ -877,10 +877,8 @@
 }
 
 static struct inet_protocol ipip_protocol = {
-	.handler =	ipip_rcv,
-	.err_handler =	ipip_err,
-	.protocol =	IPPROTO_IPIP,
-	.name =		"IPIP"
+	.handler	=	ipip_rcv,
+	.err_handler	=	ipip_err,
 };
 
 static char banner[] __initdata =
@@ -890,15 +888,19 @@
 {
 	printk(banner);
 
+	if (inet_add_protocol(&ipip_protocol, IPPROTO_IPIP) < 0) {
+		printk(KERN_INFO "ipip init: can't add protocol\n");
+		return -EAGAIN;
+	}
+
 	ipip_fb_tunnel_dev.priv = (void*)&ipip_fb_tunnel;
 	register_netdev(&ipip_fb_tunnel_dev);
-	inet_add_protocol(&ipip_protocol);
 	return 0;
 }
 
 static void __exit ipip_fini(void)
 {
-	if ( inet_del_protocol(&ipip_protocol) < 0 )
+	if (inet_del_protocol(&ipip_protocol, IPPROTO_IPIP) < 0)
 		printk(KERN_INFO "ipip close: can't remove protocol\n");
 
 	unregister_netdev(&ipip_fb_tunnel_dev);
diff -Nru a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
--- a/net/ipv4/ipmr.c	Fri Oct 11 21:22:58 2002
+++ b/net/ipv4/ipmr.c	Fri Oct 11 21:22:58 2002
@@ -108,7 +108,7 @@
 static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
 static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
 
-extern struct inet_protocol pim_protocol;
+static struct inet_protocol pim_protocol;
 
 static struct timer_list ipmr_expire_timer;
 
@@ -928,23 +928,28 @@
 #ifdef CONFIG_IP_PIMSM
 		case MRT_PIM:
 		{
-			int v;
+			int v, ret;
 			if(get_user(v,(int *)optval))
 				return -EFAULT;
 			v = (v)?1:0;
 			rtnl_lock();
+			ret = 0;
 			if (v != mroute_do_pim) {
 				mroute_do_pim = v;
 				mroute_do_assert = v;
 #ifdef CONFIG_IP_PIMSM_V2
 				if (mroute_do_pim)
-					inet_add_protocol(&pim_protocol);
+					ret = inet_add_protocol(&pim_protocol,
+								IPPROTO_PIM);
 				else
-					inet_del_protocol(&pim_protocol);
+					ret = inet_del_protocol(&pim_protocol,
+								IPPROTO_PIM);
+				if (ret < 0)
+					ret = -EAGAIN;
 #endif
 			}
 			rtnl_unlock();
-			return 0;
+			return ret;
 		}
 #endif
 		/*
@@ -1727,15 +1732,8 @@
 #endif	
 
 #ifdef CONFIG_IP_PIMSM_V2
-struct inet_protocol pim_protocol = 
-{
-	pim_rcv,		/* PIM handler		*/
-	NULL,			/* PIM error control	*/
-	NULL,			/* next			*/
-	IPPROTO_PIM,		/* protocol ID		*/
-	0,			/* copy			*/
-	NULL,			/* data			*/
-	"PIM"			/* name			*/
+static struct inet_protocol pim_protocol = {
+	.handler	=	pim_rcv,
 };
 #endif
 
diff -Nru a/net/ipv4/protocol.c b/net/ipv4/protocol.c
--- a/net/ipv4/protocol.c	Fri Oct 11 21:22:53 2002
+++ b/net/ipv4/protocol.c	Fri Oct 11 21:22:53 2002
@@ -48,134 +48,52 @@
 #include <net/ipip.h>
 #include <linux/igmp.h>
 
-#define IPPROTO_PREVIOUS NULL
-
-#ifdef CONFIG_IP_MULTICAST
-
-static struct inet_protocol igmp_protocol = {
-	.handler =	igmp_rcv,
-	.next =		IPPROTO_PREVIOUS,
-	.protocol =	IPPROTO_IGMP,
-	.name =		"IGMP"
-};
-
-#undef  IPPROTO_PREVIOUS
-#define IPPROTO_PREVIOUS &igmp_protocol
-
-#endif
-
-static struct inet_protocol tcp_protocol = {
-	.handler =	tcp_v4_rcv,
-	.err_handler =	tcp_v4_err,
-	.next =		IPPROTO_PREVIOUS,
-	.protocol =	IPPROTO_TCP,
-	.name =		"TCP"
-};
-
-#undef  IPPROTO_PREVIOUS
-#define IPPROTO_PREVIOUS &tcp_protocol
-
-static struct inet_protocol udp_protocol = {
-	.handler =	udp_rcv,
-	.err_handler =	udp_err,
-	.next =		IPPROTO_PREVIOUS,
-	.protocol =	IPPROTO_UDP,
-	.name =		"UDP"
-};
-
-#undef  IPPROTO_PREVIOUS
-#define IPPROTO_PREVIOUS &udp_protocol
-
-static struct inet_protocol icmp_protocol = {
-	.handler =	icmp_rcv,
-	.next =		IPPROTO_PREVIOUS,
-	.protocol =	IPPROTO_ICMP,
-	.name =		"ICMP"
-};
-
-#undef  IPPROTO_PREVIOUS
-#define IPPROTO_PREVIOUS &icmp_protocol
-
-
-struct inet_protocol *inet_protocol_base = IPPROTO_PREVIOUS;
-
 struct inet_protocol *inet_protos[MAX_INET_PROTOS];
 
 /*
  *	Add a protocol handler to the hash tables
  */
 
-void inet_add_protocol(struct inet_protocol *prot)
+int inet_add_protocol(struct inet_protocol *prot, unsigned char protocol)
 {
-	unsigned char hash;
-	struct inet_protocol *p2;
+	int hash, ret;
+
+	hash = protocol & (MAX_INET_PROTOS - 1);
 
-	hash = prot->protocol & (MAX_INET_PROTOS - 1);
 	br_write_lock_bh(BR_NETPROTO_LOCK);
-	prot ->next = inet_protos[hash];
-	inet_protos[hash] = prot;
-	prot->copy = 0;
-
-	/*
-	 *	Set the copy bit if we need to. 
-	 */
-	 
-	p2 = (struct inet_protocol *) prot->next;
-	while (p2) {
-		if (p2->protocol == prot->protocol) {
-			prot->copy = 1;
-			break;
-		}
-		p2 = (struct inet_protocol *) p2->next;
+
+	if (inet_protos[hash]) {
+		ret = -1;
+	} else {
+		inet_protos[hash] = prot;
+		ret = 0;
 	}
+
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
+
+	return ret;
 }
 
 /*
  *	Remove a protocol from the hash tables.
  */
  
-int inet_del_protocol(struct inet_protocol *prot)
+int inet_del_protocol(struct inet_protocol *prot, unsigned char protocol)
 {
-	struct inet_protocol *p;
-	struct inet_protocol *lp = NULL;
-	unsigned char hash;
-
-	hash = prot->protocol & (MAX_INET_PROTOS - 1);
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-	if (prot == inet_protos[hash]) {
-		inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
-		br_write_unlock_bh(BR_NETPROTO_LOCK);
-		return 0;
-	}
+	int hash, ret;
 
-	p = (struct inet_protocol *) inet_protos[hash];
+	hash = protocol & (MAX_INET_PROTOS - 1);
 
-	if (p != NULL && p->protocol == prot->protocol)
-		lp = p;
-
-	while (p) {
-		/*
-		 * We have to worry if the protocol being deleted is
-		 * the last one on the list, then we may need to reset
-		 * someone's copied bit.
-		 */
-		if (p->next && p->next == prot) {
-			/*
-			 * if we are the last one with this protocol and
-			 * there is a previous one, reset its copy bit.
-			 */
-			if (prot->copy == 0 && lp != NULL)
-				lp->copy = 0;
-			p->next = prot->next;
-			br_write_unlock_bh(BR_NETPROTO_LOCK);
-			return 0;
-		}
-		if (p->next != NULL && p->next->protocol == prot->protocol) 
-			lp = p->next;
+	br_write_lock_bh(BR_NETPROTO_LOCK);
 
-		p = (struct inet_protocol *) p->next;
+	if (inet_protos[hash] == prot) {
+		inet_protos[hash] = NULL;
+		ret = 0;
+	} else {
+		ret = -1;
 	}
+
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
-	return -1;
+
+	return ret;
 }
diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c	Fri Oct 11 21:22:51 2002
+++ b/net/ipv4/raw.c	Fri Oct 11 21:22:51 2002
@@ -135,13 +135,12 @@
 }
 
 /* IP input processing comes here for RAW socket delivery.
- * This is fun as to avoid copies we want to make no surplus
- * copies.
+ * Caller owns SKB, so we must make clones.
  *
  * RFC 1122: SHOULD pass TOS value up to the transport layer.
  * -> It does. And not only TOS, but all IP header.
  */
-struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
+void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
 {
 	struct sock *sk;
 
@@ -153,28 +152,19 @@
 			     skb->dev->ifindex);
 
 	while (sk) {
-		struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol,
-						      iph->saddr, iph->daddr,
-						      skb->dev->ifindex);
-		if (iph->protocol != IPPROTO_ICMP ||
-		    !icmp_filter(sk, skb)) {
-			struct sk_buff *clone;
+		if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
+			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
-			if (!sknext)
-				break;
-			clone = skb_clone(skb, GFP_ATOMIC);
 			/* Not releasing hash table! */
 			if (clone)
 				raw_rcv(sk, clone);
 		}
-		sk = sknext;
+		sk = __raw_v4_lookup(sk->next, iph->protocol,
+				     iph->saddr, iph->daddr,
+				     skb->dev->ifindex);
 	}
 out:
-	if (sk)
-		sock_hold(sk);
 	read_unlock(&raw_v4_lock);
-
-	return sk;
 }
 
 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Fri Oct 11 21:22:55 2002
+++ b/net/ipv4/tcp.c	Fri Oct 11 21:22:55 2002
@@ -623,7 +623,7 @@
 
 		local_bh_disable();
 		bh_lock_sock(child);
-		BUG_TRAP(!child->lock.users);
+		BUG_TRAP(!sock_owned_by_user(child));
 		sock_hold(child);
 
 		tcp_disconnect(child, O_NONBLOCK);
@@ -2019,7 +2019,7 @@
 	 */
 	local_bh_disable();
 	bh_lock_sock(sk);
-	BUG_TRAP(!sk->lock.users);
+	BUG_TRAP(!sock_owned_by_user(sk));
 
 	sock_hold(sk);
 	sock_orphan(sk);
diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c	Fri Oct 11 21:22:54 2002
+++ b/net/ipv4/tcp_input.c	Fri Oct 11 21:22:54 2002
@@ -2570,7 +2570,7 @@
 		/* Ok. In sequence. In window. */
 		if (tp->ucopy.task == current &&
 		    tp->copied_seq == tp->rcv_nxt && tp->ucopy.len &&
-		    sk->lock.users && !tp->urg_data) {
+		    sock_owned_by_user(sk) && !tp->urg_data) {
 			int chunk = min_t(unsigned int, skb->len,
 							tp->ucopy.len);
 
@@ -3190,7 +3190,7 @@
 {
 	int result;
 
-	if (sk->lock.users) {
+	if (sock_owned_by_user(sk)) {
 		local_bh_enable();
 		result = __tcp_checksum_complete(skb);
 		local_bh_disable();
@@ -3324,7 +3324,7 @@
 			if (tp->ucopy.task == current &&
 			    tp->copied_seq == tp->rcv_nxt &&
 			    len - tcp_header_len <= tp->ucopy.len &&
-			    sk->lock.users) {
+			    sock_owned_by_user(sk)) {
 				__set_current_state(TASK_RUNNING);
 
 				if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) {
@@ -3864,7 +3864,7 @@
 					tmo = tcp_fin_time(tp);
 					if (tmo > TCP_TIMEWAIT_LEN) {
 						tcp_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN);
-					} else if (th->fin || sk->lock.users) {
+					} else if (th->fin || sock_owned_by_user(sk)) {
 						/* Bad case. We could lose such FIN otherwise.
 						 * It is not a big problem, but it looks confusing
 						 * and not so rare event. We still can lose it now,
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Fri Oct 11 21:22:55 2002
+++ b/net/ipv4/tcp_ipv4.c	Fri Oct 11 21:22:55 2002
@@ -1003,7 +1003,7 @@
 	/* If too many ICMPs get dropped on busy
 	 * servers this needs to be solved differently.
 	 */
-	if (sk->lock.users)
+	if (sock_owned_by_user(sk))
 		NET_INC_STATS_BH(LockDroppedIcmps);
 
 	if (sk->state == TCP_CLOSE)
@@ -1022,7 +1022,7 @@
 		/* This is deprecated, but if someone generated it,
 		 * we have no reasons to ignore it.
 		 */
-		if (!sk->lock.users)
+		if (!sock_owned_by_user(sk))
 			tcp_enter_cwr(tp);
 		goto out;
 	case ICMP_PARAMETERPROB:
@@ -1033,7 +1033,7 @@
 			goto out;
 
 		if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
-			if (!sk->lock.users)
+			if (!sock_owned_by_user(sk))
 				do_pmtu_discovery(sk, iph, info);
 			goto out;
 		}
@@ -1050,7 +1050,7 @@
 	switch (sk->state) {
 		struct open_request *req, **prev;
 	case TCP_LISTEN:
-		if (sk->lock.users)
+		if (sock_owned_by_user(sk))
 			goto out;
 
 		req = tcp_v4_search_req(tp, &prev, th->dest,
@@ -1081,7 +1081,7 @@
 	case TCP_SYN_RECV:  /* Cannot happen.
 			       It can f.e. if SYNs crossed.
 			     */
-		if (!sk->lock.users) {
+		if (!sock_owned_by_user(sk)) {
 			TCP_INC_STATS_BH(TcpAttemptFails);
 			sk->err = err;
 
@@ -1111,7 +1111,7 @@
 	 */
 
 	inet = inet_sk(sk);
-	if (!sk->lock.users && inet->recverr) {
+	if (!sock_owned_by_user(sk) && inet->recverr) {
 		sk->err = err;
 		sk->error_report(sk);
 	} else	{ /* Only an error on timeout */
@@ -1778,7 +1778,7 @@
 
 	bh_lock_sock(sk);
 	ret = 0;
-	if (!sk->lock.users) {
+	if (!sock_owned_by_user(sk)) {
 		if (!tcp_prequeue(sk, skb))
 			ret = tcp_v4_do_rcv(sk, skb);
 	} else
diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
--- a/net/ipv4/tcp_minisocks.c	Fri Oct 11 21:22:54 2002
+++ b/net/ipv4/tcp_minisocks.c	Fri Oct 11 21:22:54 2002
@@ -989,7 +989,7 @@
 	int ret = 0;
 	int state = child->state;
 
-	if (child->lock.users == 0) {
+	if (!sock_owned_by_user(child)) {
 		ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len);
 
 		/* Wakeup parent, send SIGIO */
diff -Nru a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
--- a/net/ipv4/tcp_timer.c	Fri Oct 11 21:23:04 2002
+++ b/net/ipv4/tcp_timer.c	Fri Oct 11 21:23:04 2002
@@ -213,7 +213,7 @@
 	struct tcp_opt *tp = tcp_sk(sk);
 
 	bh_lock_sock(sk);
-	if (sk->lock.users) {
+	if (sock_owned_by_user(sk)) {
 		/* Try again later. */
 		tp->ack.blocked = 1;
 		NET_INC_STATS_BH(DelayedACKLocked);
@@ -421,7 +421,7 @@
 	int event;
 
 	bh_lock_sock(sk);
-	if (sk->lock.users) {
+	if (sock_owned_by_user(sk)) {
 		/* Try again later */
 		if (!mod_timer(&tp->retransmit_timer, jiffies + (HZ/20)))
 			sock_hold(sk);
@@ -581,7 +581,7 @@
 
 	/* Only process if socket is not in use. */
 	bh_lock_sock(sk);
-	if (sk->lock.users) {
+	if (sock_owned_by_user(sk)) {
 		/* Try again later. */ 
 		tcp_reset_keepalive_timer (sk, HZ/20);
 		goto out;
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Fri Oct 11 21:23:04 2002
+++ b/net/ipv6/addrconf.c	Fri Oct 11 21:23:04 2002
@@ -152,15 +152,15 @@
 		int type = IPV6_ADDR_MULTICAST;
 
 		switch((st & htonl(0x00FF0000))) {
-			case htonl(0x00010000):
+			case __constant_htonl(0x00010000):
 				type |= IPV6_ADDR_LOOPBACK;
 				break;
 
-			case htonl(0x00020000):
+			case __constant_htonl(0x00020000):
 				type |= IPV6_ADDR_LINKLOCAL;
 				break;
 
-			case htonl(0x00050000):
+			case __constant_htonl(0x00050000):
 				type |= IPV6_ADDR_SITELOCAL;
 				break;
 		};
@@ -786,7 +786,7 @@
 	struct in6_addr addr;
 
 	ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);
-	addrconf_prefix_route(&addr, 10, dev, 0, RTF_ADDRCONF);
+	addrconf_prefix_route(&addr, 64, dev, 0, RTF_ADDRCONF);
 }
 
 static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
@@ -1161,7 +1161,7 @@
 					flag |= IFA_HOST;
 				}
 				if (idev->dev->flags&IFF_POINTOPOINT)
-					plen = 10;
+					plen = 64;
 				else
 					plen = 96;
 
@@ -1211,7 +1211,7 @@
 {
 	struct inet6_ifaddr * ifp;
 
-	ifp = ipv6_add_addr(idev, addr, 10, IFA_LINK, IFA_F_PERMANENT);
+	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
 	if (ifp) {
 		addrconf_dad_start(ifp);
 		in6_ifa_put(ifp);
diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c
--- a/net/ipv6/icmp.c	Fri Oct 11 21:22:55 2002
+++ b/net/ipv6/icmp.c	Fri Oct 11 21:22:55 2002
@@ -70,15 +70,8 @@
 
 static int icmpv6_rcv(struct sk_buff *skb);
 
-static struct inet6_protocol icmpv6_protocol = 
-{
-	icmpv6_rcv,		/* handler		*/
-	NULL,			/* error control	*/
-	NULL,			/* next			*/
-	IPPROTO_ICMPV6,		/* protocol ID		*/
-	0,			/* copy			*/
-	NULL,			/* data			*/
-	"ICMPv6"	       	/* name			*/
+static struct inet6_protocol icmpv6_protocol = {
+	.handler	=	icmpv6_rcv,
 };
 
 struct icmpv6_msg {
@@ -467,15 +460,9 @@
 
 	hash = nexthdr & (MAX_INET_PROTOS - 1);
 
-	for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
-	     ipprot != NULL; 
-	     ipprot=(struct inet6_protocol *)ipprot->next) {
-		if (ipprot->protocol != nexthdr)
-			continue;
-
-		if (ipprot->err_handler)
-			ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
-	}
+	ipprot = inet6_protos[hash];
+	if (ipprot && ipprot->err_handler)
+		ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
 
 	read_lock(&raw_v6_lock);
 	if ((sk = raw_v6_htable[hash]) != NULL) {
@@ -651,7 +638,12 @@
 	sk->sndbuf = SK_WMEM_MAX*2;
 	sk->prot->unhash(sk);
 
-	inet6_add_protocol(&icmpv6_protocol);
+	if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) {
+		printk(KERN_ERR "Failed to register ICMP6 protocol\n");
+		sock_release(icmpv6_socket);
+		icmpv6_socket = NULL;
+		return -EAGAIN;
+	}
 
 	return 0;
 }
@@ -660,7 +652,7 @@
 {
 	sock_release(icmpv6_socket);
 	icmpv6_socket = NULL; /* For safety. */
-	inet6_del_protocol(&icmpv6_protocol);
+	inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
 }
 
 static struct icmp6_err {
diff -Nru a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
--- a/net/ipv6/ip6_input.c	Fri Oct 11 21:23:02 2002
+++ b/net/ipv6/ip6_input.c	Fri Oct 11 21:23:02 2002
@@ -126,7 +126,6 @@
 	struct sock *raw_sk;
 	int nhoff;
 	int nexthdr;
-	int found = 0;
 	u8 hash;
 
 	skb->h.raw = skb->nh.raw + sizeof(struct ipv6hdr);
@@ -164,39 +163,24 @@
 		skb->csum = csum_sub(skb->csum,
 				     csum_partial(skb->nh.raw, skb->h.raw-skb->nh.raw, 0));
 
-	raw_sk = raw_v6_htable[nexthdr&(MAX_INET_PROTOS-1)];
+resubmit:
+	raw_sk = raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)];
 	if (raw_sk)
-		raw_sk = ipv6_raw_deliver(skb, nexthdr);
+		ipv6_raw_deliver(skb, nexthdr);
 
 	hash = nexthdr & (MAX_INET_PROTOS - 1);
-	for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
-	     ipprot != NULL; 
-	     ipprot = (struct inet6_protocol *) ipprot->next) {
-		struct sk_buff *buff = skb;
-
-		if (ipprot->protocol != nexthdr)
-			continue;
-
-		if (ipprot->copy || raw_sk)
-			buff = skb_clone(skb, GFP_ATOMIC);
-
-		if (buff)
-			ipprot->handler(buff);
-		found = 1;
-	}
-
-	if (raw_sk) {
-		rawv6_rcv(raw_sk, skb);
-		sock_put(raw_sk);
-		found = 1;
-	}
-
-	/*
-	 *	not found: send ICMP parameter problem back
-	 */
-	if (!found) {
-		IP6_INC_STATS_BH(Ip6InUnknownProtos);
-		icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
+	if ((ipprot = inet6_protos[hash]) != NULL) {
+		int ret = ipprot->handler(skb);
+		if (ret < 0) {
+			nexthdr = -ret;
+			goto resubmit;
+		}
+	} else {
+		if (!raw_sk) {
+			IP6_INC_STATS_BH(Ip6InUnknownProtos);
+			icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff);
+		}
+		kfree_skb(skb);
 	}
 
 	return 0;
diff -Nru a/net/ipv6/protocol.c b/net/ipv6/protocol.c
--- a/net/ipv6/protocol.c	Fri Oct 11 21:22:54 2002
+++ b/net/ipv6/protocol.c	Fri Oct 11 21:22:54 2002
@@ -42,77 +42,42 @@
 
 struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
 
-void inet6_add_protocol(struct inet6_protocol *prot)
+int inet6_add_protocol(struct inet6_protocol *prot, unsigned char protocol)
 {
-	unsigned char hash;
-	struct inet6_protocol *p2;
+	int ret, hash = protocol & (MAX_INET_PROTOS - 1);
 
-	hash = prot->protocol & (MAX_INET_PROTOS - 1);
 	br_write_lock_bh(BR_NETPROTO_LOCK);
-	prot->next = inet6_protos[hash];
-	inet6_protos[hash] = prot;
-	prot->copy = 0;
-
-	/*
-	 *	Set the copy bit if we need to. 
-	 */
-	 
-	p2 = (struct inet6_protocol *) prot->next;
-	while(p2 != NULL) {
-		if (p2->protocol == prot->protocol) {
-			prot->copy = 1;
-			break;
-		}
-		p2 = (struct inet6_protocol *) p2->next;
+
+	if (inet6_protos[hash]) {
+		ret = -1;
+	} else {
+		inet6_protos[hash] = prot;
+		ret = 0;
 	}
+
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
+
+	return ret;
 }
 
 /*
  *	Remove a protocol from the hash tables.
  */
  
-int inet6_del_protocol(struct inet6_protocol *prot)
+int inet6_del_protocol(struct inet6_protocol *prot, unsigned char protocol)
 {
-	struct inet6_protocol *p;
-	struct inet6_protocol *lp = NULL;
-	unsigned char hash;
+	int ret, hash = protocol & (MAX_INET_PROTOS - 1);
 
-	hash = prot->protocol & (MAX_INET_PROTOS - 1);
 	br_write_lock_bh(BR_NETPROTO_LOCK);
-	if (prot == inet6_protos[hash]) {
-		inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next;
-		br_write_unlock_bh(BR_NETPROTO_LOCK);
-		return(0);
-	}
-
-	p = (struct inet6_protocol *) inet6_protos[hash];
 
-        if (p != NULL && p->protocol == prot->protocol)
-                lp = p;
-
-	while(p != NULL) {
-		/*
-		 * We have to worry if the protocol being deleted is
-		 * the last one on the list, then we may need to reset
-		 * someone's copied bit.
-		 */
-		if (p->next != NULL && p->next == prot) {
-			/*
-			 * if we are the last one with this protocol and
-			 * there is a previous one, reset its copy bit.
-			 */
-			if (prot->copy == 0 && lp != NULL)
-				lp->copy = 0;
-			p->next = prot->next;
-			br_write_unlock_bh(BR_NETPROTO_LOCK);
-			return(0);
-		}
-		if (p->next != NULL && p->next->protocol == prot->protocol) 
-			lp = p->next;
-
-		p = (struct inet6_protocol *) p->next;
+	if (inet6_protos[hash] != prot) {
+		ret = -1;
+	} else {
+		inet6_protos[hash] = NULL;
+		ret = 0;
 	}
+
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
-	return(-1);
+
+	return ret;
 }
diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c	Fri Oct 11 21:22:55 2002
+++ b/net/ipv6/raw.c	Fri Oct 11 21:22:55 2002
@@ -133,12 +133,14 @@
  *	demultiplex raw sockets.
  *	(should consider queueing the skb in the sock receive_queue
  *	without calling rawv6.c)
+ *
+ *	Caller owns SKB so we must make clones.
  */
-struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
+void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
 	struct in6_addr *saddr;
 	struct in6_addr *daddr;
-	struct sock *sk, *sk2;
+	struct sock *sk;
 	__u8 hash;
 
 	saddr = &skb->nh.ipv6h->saddr;
@@ -159,30 +161,18 @@
 
 	sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
 
-	if (sk) {
-		sk2 = sk;
-
-		while ((sk2 = __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
-			struct sk_buff *buff;
-
-			if (nexthdr == IPPROTO_ICMPV6 &&
-			    icmpv6_filter(sk2, skb))
-				continue;
-
-			buff = skb_clone(skb, GFP_ATOMIC);
-			if (buff)
-				rawv6_rcv(sk2, buff);
+	while (sk) {
+		if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
+			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
+
+			/* Not releasing hash table! */
+			if (clone)
+				rawv6_rcv(sk, clone);
 		}
+		sk = __raw_v6_lookup(sk->next, nexthdr, daddr, saddr);
 	}
-
-	if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
-		sk = NULL;
-
 out:
-	if (sk)
-		sock_hold(sk);
 	read_unlock(&raw_v6_lock);
-	return sk;
 }
 
 /* This cleans up af_inet6 a bit. -DaveM */
diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c
--- a/net/ipv6/sit.c	Fri Oct 11 21:23:04 2002
+++ b/net/ipv6/sit.c	Fri Oct 11 21:23:04 2002
@@ -835,19 +835,14 @@
 }
 
 static struct inet_protocol sit_protocol = {
-	ipip6_rcv,
-	ipip6_err,
-	0,
-	IPPROTO_IPV6,
-	0,
-	NULL,
-	"IPv6"
+	.handler	=	ipip6_rcv,
+	.err_handler	=	ipip6_err,
 };
 
 #ifdef MODULE
 void sit_cleanup(void)
 {
-	inet_del_protocol(&sit_protocol);
+	inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
 	unregister_netdev(&ipip6_fb_tunnel_dev);
 }
 #endif
@@ -856,9 +851,13 @@
 {
 	printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n");
 
+	if (inet_add_protocol(&sit_protocol, IPPROTO_IPV6) < 0) {
+		printk(KERN_INFO "sit init: Can't add protocol\n");
+		return -EAGAIN;
+	}
+
 	ipip6_fb_tunnel_dev.priv = (void*)&ipip6_fb_tunnel;
 	strcpy(ipip6_fb_tunnel_dev.name, ipip6_fb_tunnel.parms.name);
 	register_netdev(&ipip6_fb_tunnel_dev);
-	inet_add_protocol(&sit_protocol);
 	return 0;
 }
diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c	Fri Oct 11 21:22:59 2002
+++ b/net/ipv6/tcp_ipv6.c	Fri Oct 11 21:22:59 2002
@@ -731,7 +731,7 @@
 	}
 
 	bh_lock_sock(sk);
-	if (sk->lock.users)
+	if (sock_owned_by_user(sk))
 		NET_INC_STATS_BH(LockDroppedIcmps);
 
 	if (sk->state == TCP_CLOSE)
@@ -749,7 +749,7 @@
 	if (type == ICMPV6_PKT_TOOBIG) {
 		struct dst_entry *dst = NULL;
 
-		if (sk->lock.users)
+		if (sock_owned_by_user(sk))
 			goto out;
 		if ((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE))
 			goto out;
@@ -792,7 +792,7 @@
 	switch (sk->state) {
 		struct open_request *req, **prev;
 	case TCP_LISTEN:
-		if (sk->lock.users)
+		if (sock_owned_by_user(sk))
 			goto out;
 
 		req = tcp_v6_search_req(tp, &prev, th->dest, &hdr->daddr,
@@ -816,7 +816,7 @@
 	case TCP_SYN_SENT:
 	case TCP_SYN_RECV:  /* Cannot happen.
 			       It can, it SYNs are crossed. --ANK */ 
-		if (sk->lock.users == 0) {
+		if (!sock_owned_by_user(sk)) {
 			TCP_INC_STATS_BH(TcpAttemptFails);
 			sk->err = err;
 			sk->error_report(sk);		/* Wake people up to see the error (see connect in sock.c) */
@@ -828,7 +828,7 @@
 		goto out;
 	}
 
-	if (sk->lock.users == 0 && np->recverr) {
+	if (!sock_owned_by_user(sk) && np->recverr) {
 		sk->err = err;
 		sk->error_report(sk);
 	} else {
@@ -1622,7 +1622,7 @@
 
 	bh_lock_sock(sk);
 	ret = 0;
-	if (!sk->lock.users) {
+	if (!sock_owned_by_user(sk)) {
 		if (!tcp_prequeue(sk, skb))
 			ret = tcp_v6_do_rcv(sk, skb);
 	} else
@@ -2156,12 +2156,9 @@
 	.get_port =	tcp_v6_get_port,
 };
 
-static struct inet6_protocol tcpv6_protocol =
-{
-	.handler =	tcp_v6_rcv,
-	.err_handler =	tcp_v6_err,
-	.protocol =	IPPROTO_TCP,
-	.name =		"TCPv6",
+static struct inet6_protocol tcpv6_protocol = {
+	.handler	=	tcp_v6_rcv,
+	.err_handler	=	tcp_v6_err,
 };
 
 extern struct proto_ops inet6_stream_ops;
@@ -2179,6 +2176,7 @@
 void __init tcpv6_init(void)
 {
 	/* register inet6 protocol */
-	inet6_add_protocol(&tcpv6_protocol);
+	if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
+		printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
 	inet6_register_protosw(&tcpv6_protosw);
 }
diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c
--- a/net/ipv6/udp.c	Fri Oct 11 21:22:55 2002
+++ b/net/ipv6/udp.c	Fri Oct 11 21:22:55 2002
@@ -907,10 +907,8 @@
 }
 
 static struct inet6_protocol udpv6_protocol = {
-	.handler =	udpv6_rcv,
-	.err_handler =	udpv6_err,
-	.protocol =	IPPROTO_UDP,
-	.name =		"UDPv6",
+	.handler	=	udpv6_rcv,
+	.err_handler	=	udpv6_err,
 };
 
 #define LINE_LEN 190
@@ -1020,6 +1018,7 @@
 
 void __init udpv6_init(void)
 {
-	inet6_add_protocol(&udpv6_protocol);
+	if (inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP) < 0)
+		printk(KERN_ERR "udpv6_init: Could not register protocol\n");
 	inet6_register_protosw(&udpv6_protosw);
 }
diff -Nru a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c
--- a/net/ipx/ipx_proc.c	Fri Oct 11 21:22:50 2002
+++ b/net/ipx/ipx_proc.c	Fri Oct 11 21:22:50 2002
@@ -315,15 +315,6 @@
 	.release        = seq_release,
 };
 
-static int ipx_proc_perms(struct inode* inode, int op)
-{
-	return 0;
-}
-
-static struct inode_operations ipx_seq_inode = {
-	.permission     = ipx_proc_perms,
-};
-
 static struct proc_dir_entry *ipx_proc_dir;
 
 int __init ipx_proc_init(void)
@@ -335,24 +326,21 @@
 
 	if (!ipx_proc_dir)
 		goto out;
-	p = create_proc_entry("interface", 0, ipx_proc_dir);
+	p = create_proc_entry("interface", S_IRUGO, ipx_proc_dir);
 	if (!p)
 		goto out_interface;
 
 	p->proc_fops = &ipx_seq_interface_fops;
-	p->proc_iops = &ipx_seq_inode;
-	p = create_proc_entry("route", 0, ipx_proc_dir);
+	p = create_proc_entry("route", S_IRUGO, ipx_proc_dir);
 	if (!p)
 		goto out_route;
 
 	p->proc_fops = &ipx_seq_route_fops;
-	p->proc_iops = &ipx_seq_inode;
-	p = create_proc_entry("socket", 0, ipx_proc_dir);
+	p = create_proc_entry("socket", S_IRUGO, ipx_proc_dir);
 	if (!p)
 		goto out_socket;
 
 	p->proc_fops = &ipx_seq_socket_fops;
-	p->proc_iops = &ipx_seq_inode;
 
 	rc = 0;
 out:
diff -Nru a/net/irda/crc.c b/net/irda/crc.c
--- a/net/irda/crc.c	Fri Oct 11 21:22:55 2002
+++ b/net/irda/crc.c	Fri Oct 11 21:22:55 2002
@@ -57,7 +57,7 @@
 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 };
 
-unsigned short crc_calc( __u16 fcs, __u8 const *buf, size_t len) 
+unsigned short irda_calc_crc16( __u16 fcs, __u8 const *buf, size_t len) 
 {
 	while (len--)
                 fcs = irda_fcs(fcs, *buf++);
diff -Nru a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
--- a/net/irda/ircomm/ircomm_param.c	Fri Oct 11 21:22:58 2002
+++ b/net/irda/ircomm/ircomm_param.c	Fri Oct 11 21:22:58 2002
@@ -220,9 +220,16 @@
 
 	/* 
 	 * Now the line is ready for some communication. Check if we are a
-         * server, and send over some initial parameters 
+         * server, and send over some initial parameters.
+	 * Client do it in ircomm_tty_state_setup().
+	 * Note : we may get called from ircomm_tty_getvalue_confirm(),
+	 * therefore before we even have open any socket. And self->client
+	 * is initialised to TRUE only later. So, we check if the link is
+	 * really initialised. - Jean II
 	 */
-	if (!self->client && (self->settings.service_type != IRCOMM_3_WIRE_RAW))
+	if ((self->max_header_size != IRCOMM_TTY_HDR_UNINITIALISED) &&
+	    (!self->client) &&
+	    (self->settings.service_type != IRCOMM_3_WIRE_RAW))
 	{
 		/* Init connection */
 		ircomm_tty_send_initial_parameters(self);
diff -Nru a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
--- a/net/irda/ircomm/ircomm_tty.c	Fri Oct 11 21:22:55 2002
+++ b/net/irda/ircomm/ircomm_tty.c	Fri Oct 11 21:22:55 2002
@@ -421,8 +421,8 @@
 
 		self->line = line;
 		INIT_WORK(&self->tqueue, ircomm_tty_do_softint, self);
-		self->max_header_size = IRCOMM_TTY_HDR_UNITIALISED;
-		self->max_data_size = 64-self->max_header_size;
+		self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED;
+		self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED;
 		self->close_delay = 5*HZ/10;
 		self->closing_wait = 30*HZ;
 
@@ -719,16 +719,26 @@
 
 	/* We may receive packets from the TTY even before we have finished
 	 * our setup. Not cool.
-	 * The problem is that we would allocate a skb with bogus header and
-	 * data size, and when adding data to it later we would get
-	 * confused.
-	 * Better to not accept data until we are properly setup. Use bogus
-	 * header size to check that (safest way to detect it).
+	 * The problem is that we don't know the final header and data size
+	 * to create the proper skb, so any skb we would create would have
+	 * bogus header and data size, so need care.
+	 * We use a bogus header size to safely detect this condition.
+	 * Another problem is that hw_stopped was set to 0 way before it
+	 * should be, so we would drop this skb. It should now be fixed.
+	 * One option is to not accept data until we are properly setup.
+	 * But, I suspect that when it happens, the ppp line discipline
+	 * just "drops" the data, which might screw up connect scripts.
+	 * The second option is to create a "safe skb", with large header
+	 * and small size (see ircomm_tty_open() for values).
+	 * We just need to make sure that when the real values get filled,
+	 * we don't mess up the original "safe skb" (see tx_data_size).
 	 * Jean II */
-	if (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED) {
-		/* TTY will retry */
-		IRDA_DEBUG(2, "%s() : not initialised\n", __FUNCTION__ );
-		return len;
+	if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) {
+		IRDA_DEBUG(1, "%s() : not initialised\n", __FUNCTION__);
+#ifdef IRCOMM_NO_TX_BEFORE_INIT
+		/* We didn't consume anything, TTY will retry */
+		return 0;
+#endif
 	}
 
 	spin_lock_irqsave(&self->spinlock, flags);
@@ -761,8 +771,11 @@
 			 * transmit buffer? Cannot use skb_tailroom, since
 			 * dev_alloc_skb gives us a larger skb than we 
 			 * requested
+			 * Note : use tx_data_size, because max_data_size
+			 * may have changed and we don't want to overwrite
+			 * the skb. - Jean II
 			 */
-			if ((tailroom = (self->max_data_size-skb->len)) > 0) {
+			if ((tailroom = (self->tx_data_size - skb->len)) > 0) {
 				/* Adjust data to tailroom */
 				if (size > tailroom)
 					size = tailroom;
@@ -783,6 +796,9 @@
 			}
 			skb_reserve(skb, self->max_header_size);
 			self->tx_skb = skb;
+			/* Remember skb size because max_data_size may
+			 * change later on - Jean II */
+			self->tx_data_size = self->max_data_size;
 		}
 		
 		/* Copy data */
@@ -825,17 +841,22 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
+#ifdef IRCOMM_NO_TX_BEFORE_INIT
+	/* max_header_size tells us if the channel is initialised or not. */
+	if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED)
+		/* Don't bother us yet */
+		return 0;
+#endif
+
 	/* Check if we are allowed to transmit any data.
 	 * hw_stopped is the regular flow control.
-	 * max_header_size tells us if the channel is initialised or not.
 	 * Jean II */
-	if ((tty->hw_stopped) ||
-	    (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED))
+	if (tty->hw_stopped)
 		ret = 0;
 	else {
 		spin_lock_irqsave(&self->spinlock, flags);
 		if (self->tx_skb)
-			ret = self->max_data_size - self->tx_skb->len;
+			ret = self->tx_data_size - self->tx_skb->len;
 		else
 			ret = self->max_data_size;
 		spin_unlock_irqrestore(&self->spinlock, flags);
diff -Nru a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
--- a/net/irda/ircomm/ircomm_tty_attach.c	Fri Oct 11 21:23:03 2002
+++ b/net/irda/ircomm/ircomm_tty_attach.c	Fri Oct 11 21:23:03 2002
@@ -517,6 +517,23 @@
 	
 	del_timer(&self->watchdog_timer);
 
+	/* Remove LM-IAS object now so it is not reused.
+	 * IrCOMM deals very poorly with multiple incomming connections.
+	 * It should looks a lot more like IrNET, and "dup" a server TSAP
+	 * to the application TSAP (based on various rules).
+	 * This is a cheap workaround allowing multiple clients to
+	 * connect to us. It will not always work.
+	 * Each IrCOMM socket has an IAS entry. Incomming connection will
+	 * pick the first one found. So, when we are fully connected,
+	 * we remove our IAS entries so that the next IAS entry is used.
+	 * We do that for *both* client and server, because a server
+	 * can also create client instances.
+	 * Jean II */
+	if (self->obj) {
+		irias_delete_object(self->obj);
+		self->obj = NULL;
+	}
+
 	/* 
 	 * IrCOMM link is now up, and if we are not using hardware
 	 * flow-control, then declare the hardware as running. Otherwise we
@@ -527,7 +544,7 @@
 		IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __FUNCTION__ );
 		return;
 	} else {
-		IRDA_DEBUG(2, "%s(), starting hardware!\n", __FUNCTION__ );
+		IRDA_DEBUG(1, "%s(), starting hardware!\n", __FUNCTION__ );
 
 		self->tty->hw_stopped = 0;
 	
diff -Nru a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
--- a/net/irda/irlmp_event.c	Fri Oct 11 21:22:54 2002
+++ b/net/irda/irlmp_event.c	Fri Oct 11 21:22:54 2002
@@ -514,10 +514,10 @@
 
 		irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
 
-		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
-
 		/* Start watchdog timer (5 secs for now) */
 		irlmp_start_watchdog_timer(self, 5*HZ);
+
+		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 		break;
 	case LM_CONNECT_INDICATION:
 		if (self->conn_skb) {
@@ -529,8 +529,6 @@
 
 		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
 
-		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
-
 		/* Start watchdog timer
 		 * This is not mentionned in the spec, but there is a rare
 		 * race condition that can get the socket stuck.
@@ -543,10 +541,12 @@
 		 * a backup plan. 1 second is plenty (should be immediate).
 		 * Jean II */
 		irlmp_start_watchdog_timer(self, 1*HZ);
+
+		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %s\n",
-			   __FUNCTION__, irlmp_event[event]);
+		IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
+			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
 		if (skb)
 			dev_kfree_skb(skb);
 		break;
@@ -604,8 +604,8 @@
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			 __FUNCTION__, irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", 
+			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
 		if (skb)
 			dev_kfree_skb(skb);
 		break;
@@ -666,8 +666,8 @@
 		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			    __FUNCTION__, irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
+			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
 		if (skb)
 			dev_kfree_skb(skb);
 		break;
@@ -757,8 +757,8 @@
 		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			    __FUNCTION__, irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
+			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
 		if (skb)
 			dev_kfree_skb(skb);
 		break;
@@ -830,8 +830,8 @@
 		irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			    __FUNCTION__, irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
+			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
 		if (skb)
 			dev_kfree_skb(skb);
 		break;
@@ -889,8 +889,8 @@
 		irlmp_disconnect_indication(self, reason, NULL);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			   __FUNCTION__, irlmp_event[event]);
+		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
+			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
 		if (skb)
 			dev_kfree_skb(skb);
 		break;
diff -Nru a/net/irda/irsyms.c b/net/irda/irsyms.c
--- a/net/irda/irsyms.c	Fri Oct 11 21:23:04 2002
+++ b/net/irda/irsyms.c	Fri Oct 11 21:23:04 2002
@@ -42,6 +42,7 @@
 #include <net/irda/wrapper.h>
 #include <net/irda/timer.h>
 #include <net/irda/parameters.h>
+#include <net/irda/crc.h>
 
 extern struct proc_dir_entry *proc_irda;
 
@@ -163,6 +164,7 @@
 
 EXPORT_SYMBOL(async_wrap_skb);
 EXPORT_SYMBOL(async_unwrap_char);
+EXPORT_SYMBOL(irda_calc_crc16);
 EXPORT_SYMBOL(irda_start_timer);
 EXPORT_SYMBOL(setup_dma);
 EXPORT_SYMBOL(infrared_mode);
diff -Nru a/net/irda/irsysctl.c b/net/irda/irsysctl.c
--- a/net/irda/irsysctl.c	Fri Oct 11 21:22:55 2002
+++ b/net/irda/irsysctl.c	Fri Oct 11 21:22:55 2002
@@ -35,7 +35,7 @@
 #define NET_IRDA 412 /* Random number */
 enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
        DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
-       MAX_TX_DATA_SIZE, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME,
+       MAX_TX_DATA_SIZE, MAX_TX_WINDOW, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME,
        LAP_KEEPALIVE_TIME };
 
 extern int  sysctl_discovery;
@@ -48,6 +48,7 @@
 extern int  sysctl_max_baud_rate;
 extern int  sysctl_min_tx_turn_time;
 extern int  sysctl_max_tx_data_size;
+extern int  sysctl_max_tx_window;
 extern int  sysctl_max_noreply_time;
 extern int  sysctl_warn_noreply_time;
 extern int  sysctl_lap_keepalive_time;
@@ -69,6 +70,8 @@
 static int min_min_tx_turn_time = 0;
 static int max_max_tx_data_size = 2048;		/* See qos.c - IrLAP spec */
 static int min_max_tx_data_size = 64;
+static int max_max_tx_window = 7;		/* See qos.c - IrLAP spec */
+static int min_max_tx_window = 1;
 static int max_max_noreply_time = 40;		/* See qos.c - IrLAP spec */
 static int min_max_noreply_time = 3;
 static int max_warn_noreply_time = 3;		/* 3s == standard */
@@ -125,6 +128,9 @@
 	{ MAX_TX_DATA_SIZE, "max_tx_data_size", &sysctl_max_tx_data_size,
 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
 	  NULL, &min_max_tx_data_size, &max_max_tx_data_size },
+	{ MAX_TX_WINDOW, "max_tx_window", &sysctl_max_tx_window,
+	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+	  NULL, &min_max_tx_window, &max_max_tx_window },
 	{ MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time,
 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
 	  NULL, &min_max_noreply_time, &max_max_noreply_time },
diff -Nru a/net/irda/parameters.c b/net/irda/parameters.c
--- a/net/irda/parameters.c	Fri Oct 11 21:23:00 2002
+++ b/net/irda/parameters.c	Fri Oct 11 21:23:00 2002
@@ -200,11 +200,13 @@
 {
 	irda_param_t p;
 	int n = 0;
+	int extract_len;	/* Real lenght we extract */
 	int err;
 
 	p.pi = pi;     /* In case handler needs to know */
 	p.pl = buf[1]; /* Extract lenght of value */
 	p.pv.i = 0;    /* Clear value */
+	extract_len = p.pl;	/* Default : extract all */
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
@@ -217,18 +219,30 @@
 	/*
 	 * Check that the integer length is what we expect it to be. If the
 	 * handler want a 16 bits integer then a 32 bits is not good enough
+	 * PV_INTEGER means that the handler is flexible.
 	 */
 	if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
 		ERROR("%s: invalid parameter length! "
 		      "Expected %d bytes, but value had %d bytes!\n",
 		      __FUNCTION__, type & PV_MASK, p.pl);
 
-		/* Skip parameter */
-		return p.pl+2;
+		/* Most parameters are bit/byte fields or little endian,
+		 * so it's ok to only extract a subset of it (the subset
+		 * that the handler expect). This is necessary, as some
+		 * broken implementations seems to add extra undefined bits.
+		 * If the parameter is shorter than we expect or is big
+		 * endian, we can't play those tricks. Jean II */
+		if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) {
+			/* Skip parameter */
+			return p.pl+2;
+		} else {
+			/* Extract subset of it, fallthrough */
+			extract_len = type & PV_MASK;
+		}
 	}
 
 
-	switch (p.pl) {
+	switch (extract_len) {
 	case 1:
 		n += irda_param_unpack(buf+2, "b", &p.pv.i);
 		break;
diff -Nru a/net/irda/qos.c b/net/irda/qos.c
--- a/net/irda/qos.c	Fri Oct 11 21:23:03 2002
+++ b/net/irda/qos.c	Fri Oct 11 21:23:03 2002
@@ -70,13 +70,18 @@
  * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header
  * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP
  * payload), that's only 2042 bytes. Oups !
- * I've had trouble trouble transmitting 2048 bytes frames with USB
- * dongles and nsc-ircc at 4 Mb/s, so adjust to 2042... I don't know
- * if this bug applies only for 2048 bytes frames or all negociated
- * frame sizes, but all hardware seem to support "2048 bytes" frames.
- * You can use the sysctl to play with this value anyway.
+ * My nsc-ircc hardware has troubles receiving 2048 bytes frames at 4 Mb/s,
+ * so adjust to 2042... I don't know if this bug applies only for 2048
+ * bytes frames or all negociated frame sizes, but you can use the sysctl
+ * to play with this value anyway.
  * Jean II */
 unsigned sysctl_max_tx_data_size = 2042;
+/*
+ * Maximum transmit window, i.e. number of LAP frames between turn-around.
+ * This allow to override what the peer told us. Some peers are buggy and
+ * don't always support what they tell us.
+ * Jean II */
+unsigned sysctl_max_tx_window = 7;
 
 static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
 static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, 
@@ -184,7 +189,19 @@
 {
 	__u16 msb = 0x8000;
 	int index = 15;   /* Current MSB */
-	
+
+	/* Check for buggy peers.
+	 * Note : there is a small probability that it could be us, but I
+	 * would expect driver authors to catch that pretty early and be
+	 * able to check precisely what's going on. If a end user sees this,
+	 * it's very likely the peer. - Jean II */
+	if (word == 0) {
+		WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
+			 __FUNCTION__);
+		/* The only safe choice (we don't know the array size) */
+		word = 0x1;
+	}
+
 	while (msb) {
 		if (word & msb)
 			break;   /* Found it! */
@@ -335,10 +352,14 @@
 
 	/*
 	 * Make sure the mintt is sensible.
+	 * Main culprit : Ericsson T39. - Jean II
 	 */
 	if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
 		int i;
 
+		WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
+			 __FUNCTION__, sysctl_min_tx_turn_time);
+
 		/* We don't really need bits, but easier this way */
 		i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
 				      8, &qos->min_turn_time.bits);
@@ -398,6 +419,11 @@
 	if (qos->data_size.value > sysctl_max_tx_data_size)
 		/* Allow non discrete adjustement to avoid loosing capacity */
 		qos->data_size.value = sysctl_max_tx_data_size;
+	/*
+	 * Override Tx window if user request it. - Jean II
+	 */
+	if (qos->window_size.value > sysctl_max_tx_window)
+		qos->window_size.value = sysctl_max_tx_window;
 }
 
 /*
diff -Nru a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
--- a/net/llc/llc_c_ac.c	Fri Oct 11 21:23:04 2002
+++ b/net/llc/llc_c_ac.c	Fri Oct 11 21:23:05 2002
@@ -1489,7 +1489,7 @@
 		       __FUNCTION__);
 		kfree_skb(skb);
 	} else {
-		if (!sk->lock.users)
+		if (!sock_owned_by_user(sk))
 			llc_conn_state_process(sk, skb);
 		else {
 			llc_set_backlog_type(skb, LLC_EVENT);
diff -Nru a/net/llc/llc_mac.c b/net/llc/llc_mac.c
--- a/net/llc/llc_mac.c	Fri Oct 11 21:23:03 2002
+++ b/net/llc/llc_mac.c	Fri Oct 11 21:23:03 2002
@@ -140,7 +140,7 @@
 		} else
 			skb->sk = sk;
 		bh_lock_sock(sk);
-		if (!sk->lock.users) {
+		if (!sock_owned_by_user(sk)) {
 			/* rc = */ llc_conn_rcv(sk, skb);
 			rc = 0;
 		} else {
diff -Nru a/net/llc/llc_proc.c b/net/llc/llc_proc.c
--- a/net/llc/llc_proc.c	Fri Oct 11 21:22:53 2002
+++ b/net/llc/llc_proc.c	Fri Oct 11 21:22:53 2002
@@ -182,7 +182,7 @@
 		   timer_pending(&llc->pf_cycle_timer.timer),
 		   timer_pending(&llc->rej_sent_timer.timer),
 		   timer_pending(&llc->busy_state_timer.timer),
-		   !!sk->backlog.tail, sk->lock.users);
+		   !!sk->backlog.tail, sock_owned_by_user(sk));
 out:
 	return 0;
 }
@@ -211,11 +211,6 @@
 	return seq_open(file, &llc_seq_core_ops);
 }
 
-static int llc_proc_perms(struct inode* inode, int op)
-{
-	return 0;
-}
-
 static struct file_operations llc_seq_socket_fops = {
 	.open		= llc_seq_socket_open,
 	.read		= seq_read,
@@ -230,10 +225,6 @@
 	.release	= seq_release,
 };
 
-static struct inode_operations llc_seq_inode = {
-	.permission	= llc_proc_perms,
-};
-
 static struct proc_dir_entry *llc_proc_dir;
 
 int __init llc_proc_init(void)
@@ -245,19 +236,17 @@
 	if (!llc_proc_dir)
 		goto out;
 
-	p = create_proc_entry("socket", 0, llc_proc_dir);
+	p = create_proc_entry("socket", S_IRUGO, llc_proc_dir);
 	if (!p)
 		goto out_socket;
 
 	p->proc_fops = &llc_seq_socket_fops;
-	p->proc_iops = &llc_seq_inode;
 
-	p = create_proc_entry("core", 0, llc_proc_dir);
+	p = create_proc_entry("core", S_IRUGO, llc_proc_dir);
 	if (!p)
 		goto out_core;
 
 	p->proc_fops = &llc_seq_core_fops;
-	p->proc_iops = &llc_seq_inode;
 
 	rc = 0;
 out:
diff -Nru a/net/sched/sch_atm.c b/net/sched/sch_atm.c
--- a/net/sched/sch_atm.c	Fri Oct 11 21:22:58 2002
+++ b/net/sched/sch_atm.c	Fri Oct 11 21:22:58 2002
@@ -668,39 +668,39 @@
 
 static struct Qdisc_class_ops atm_class_ops =
 {
-	atm_tc_graft,			/* graft */
-	atm_tc_leaf,			/* leaf */
-	atm_tc_get,			/* get */
-	atm_tc_put,			/* put */
-	atm_tc_change,			/* change */
-	atm_tc_delete,			/* delete */
-	atm_tc_walk,			/* walk */
-
-	atm_tc_find_tcf,		/* tcf_chain */
-	atm_tc_bind_filter,		/* bind_tcf */
-	atm_tc_put,			/* unbind_tcf */
+	.graft		= atm_tc_graft,
+	.leaf		= atm_tc_leaf,
+	.get		= atm_tc_get,
+	.put		= atm_tc_put,
+	.change		= atm_tc_change,
+	.delete		= atm_tc_delete,
+	.walk		= atm_tc_walk,
+
+	.tcf_chain	= atm_tc_find_tcf,
+	.bind_tcf	= atm_tc_bind_filter,
+	.unbind_tcf	= atm_tc_put,
 
-	atm_tc_dump_class,		/* dump */
+	.dump		= atm_tc_dump_class,
 };
 
 struct Qdisc_ops atm_qdisc_ops =
 {
-	NULL,				/* next */
-	&atm_class_ops,			/* cl_ops */
-	"atm",
-	sizeof(struct atm_qdisc_data),
-
-	atm_tc_enqueue,			/* enqueue */
-	atm_tc_dequeue,			/* dequeue */
-	atm_tc_requeue,			/* requeue */
-	atm_tc_drop,			/* drop */
-
-	atm_tc_init,			/* init */
-	atm_tc_reset,			/* reset */
-	atm_tc_destroy,			/* destroy */
-	NULL,				/* change */
+	.next		= NULL,
+	.cl_ops		= &atm_class_ops,
+	.id		= "atm",
+	.priv_size	= sizeof(struct atm_qdisc_data),
+
+	.enqueue	= atm_tc_enqueue,
+	.dequeue	= atm_tc_dequeue,
+	.requeue	= atm_tc_requeue,
+	.drop		= atm_tc_drop,
+
+	.init		= atm_tc_init,
+	.reset		= atm_tc_reset,
+	.destroy	= atm_tc_destroy,
+	.change		= NULL,
 
-	atm_tc_dump			/* dump */
+	.dump		= atm_tc_dump
 };
 
 
diff -Nru a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
--- a/net/sched/sch_cbq.c	Fri Oct 11 21:22:53 2002
+++ b/net/sched/sch_cbq.c	Fri Oct 11 21:22:53 2002
@@ -2066,39 +2066,39 @@
 
 static struct Qdisc_class_ops cbq_class_ops =
 {
-	cbq_graft,
-	cbq_leaf,
-	cbq_get,
-	cbq_put,
-	cbq_change_class,
-	cbq_delete,
-	cbq_walk,
-
-	cbq_find_tcf,
-	cbq_bind_filter,
-	cbq_unbind_filter,
+	.graft		= cbq_graft,
+	.leaf		= cbq_leaf,
+	.get		= cbq_get,
+	.put		= cbq_put,
+	.change		= cbq_change_class,
+	.delete		= cbq_delete,
+	.walk		= cbq_walk,
+
+	.tcf_chain	= cbq_find_tcf,
+	.bind_tcf	= cbq_bind_filter,
+	.unbind_tcf	= cbq_unbind_filter,
 
-	cbq_dump_class,
+	.dump		= cbq_dump_class,
 };
 
 struct Qdisc_ops cbq_qdisc_ops =
 {
-	NULL,
-	&cbq_class_ops,
-	"cbq",
-	sizeof(struct cbq_sched_data),
-
-	cbq_enqueue,
-	cbq_dequeue,
-	cbq_requeue,
-	cbq_drop,
-
-	cbq_init,
-	cbq_reset,
-	cbq_destroy,
-	NULL /* cbq_change */,
+	.next		= NULL,
+	.cl_ops		= &cbq_class_ops,
+	.id		= "cbq",
+	.priv_size	= sizeof(struct cbq_sched_data),
+
+	.enqueue	= cbq_enqueue,
+	.dequeue	= cbq_dequeue,
+	.requeue	= cbq_requeue,
+	.drop		= cbq_drop,
+
+	.init		= cbq_init,
+	.reset		= cbq_reset,
+	.destroy	= cbq_destroy,
+	.change		= NULL,
 
-	cbq_dump,
+	.dump		= cbq_dump,
 };
 
 #ifdef MODULE
diff -Nru a/net/sched/sch_csz.c b/net/sched/sch_csz.c
--- a/net/sched/sch_csz.c	Fri Oct 11 21:22:59 2002
+++ b/net/sched/sch_csz.c	Fri Oct 11 21:22:59 2002
@@ -1012,40 +1012,40 @@
 
 struct Qdisc_class_ops csz_class_ops =
 {
-	csz_graft,
-	csz_leaf,
+	.graft		= csz_graft,
+	.leaf		= csz_leaf,
 
-	csz_get,
-	csz_put,
-	csz_change,
-	csz_delete,
-	csz_walk,
-
-	csz_find_tcf,
-	csz_bind,
-	csz_put,
+	.get		= csz_get,
+	.put		= csz_put,
+	.change		= csz_change,
+	.delete		= csz_delete,
+	.walk		= csz_walk,
+
+	.tcf_chain	= csz_find_tcf,
+	.bind_tcf	= csz_bind,
+	.unbind_tcf	= csz_put,
 
-	csz_dump_class,
+	.dump		= csz_dump_class,
 };
 
 struct Qdisc_ops csz_qdisc_ops =
 {
-	NULL,
-	&csz_class_ops,
-	"csz",
-	sizeof(struct csz_sched_data),
-
-	csz_enqueue,
-	csz_dequeue,
-	NULL,
-	NULL,
-
-	csz_init,
-	csz_reset,
-	csz_destroy,
-	NULL /* csz_change */,
+	.next		= NULL,
+	.cl_ops		= &csz_class_ops,
+	.id		= "csz",
+	.priv_size	= sizeof(struct csz_sched_data),
+
+	.enqueue	= csz_enqueue,
+	.dequeue	= csz_dequeue,
+	.requeue	= NULL,
+	.drop		= NULL,
+
+	.init		= csz_init,
+	.reset		= csz_reset,
+	.destroy	= csz_destroy,
+	.change		= NULL,
 
-	csz_dump,
+	.dump		= csz_dump,
 };
 
 
diff -Nru a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
--- a/net/sched/sch_dsmark.c	Fri Oct 11 21:22:54 2002
+++ b/net/sched/sch_dsmark.c	Fri Oct 11 21:22:54 2002
@@ -434,39 +434,39 @@
 
 static struct Qdisc_class_ops dsmark_class_ops =
 {
-	dsmark_graft,			/* graft */
-	dsmark_leaf,			/* leaf */
-	dsmark_get,			/* get */
-	dsmark_put,			/* put */
-	dsmark_change,			/* change */
-	dsmark_delete,			/* delete */
-	dsmark_walk,			/* walk */
-
-	dsmark_find_tcf,		/* tcf_chain */
-	dsmark_bind_filter,		/* bind_tcf */
-	dsmark_put,			/* unbind_tcf */
+	.graft		= dsmark_graft,
+	.leaf		= dsmark_leaf,
+	.get		= dsmark_get,
+	.put		= dsmark_put,
+	.change		= dsmark_change,
+	.delete		= dsmark_delete,
+	.walk		= dsmark_walk,
+
+	.tcf_chain	= dsmark_find_tcf,
+	.bind_tcf	= dsmark_bind_filter,
+	.unbind_tcf	= dsmark_put,
 
-	dsmark_dump_class,		/* dump */
+	.dump		= dsmark_dump_class,
 };
 
 struct Qdisc_ops dsmark_qdisc_ops =
 {
-	NULL,				/* next */
-	&dsmark_class_ops,		/* cl_ops */
-	"dsmark",
-	sizeof(struct dsmark_qdisc_data),
-
-	dsmark_enqueue,			/* enqueue */
-	dsmark_dequeue,			/* dequeue */
-	dsmark_requeue,			/* requeue */
-	dsmark_drop,			/* drop */
-
-	dsmark_init,			/* init */
-	dsmark_reset,			/* reset */
-	dsmark_destroy,			/* destroy */
-	NULL,				/* change */
+	.next		= NULL,
+	.cl_ops		= &dsmark_class_ops,
+	.id		= "dsmark",
+	.priv_size	= sizeof(struct dsmark_qdisc_data),
+
+	.enqueue	= dsmark_enqueue,
+	.dequeue	= dsmark_dequeue,
+	.requeue	= dsmark_requeue,
+	.drop		= dsmark_drop,
+
+	.init		= dsmark_init,
+	.reset		= dsmark_reset,
+	.destroy	= dsmark_destroy,
+	.change		= NULL,
 
-	dsmark_dump			/* dump */
+	.dump		= dsmark_dump
 };
 
 #ifdef MODULE
diff -Nru a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
--- a/net/sched/sch_fifo.c	Fri Oct 11 21:22:54 2002
+++ b/net/sched/sch_fifo.c	Fri Oct 11 21:22:54 2002
@@ -170,39 +170,40 @@
 
 struct Qdisc_ops pfifo_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"pfifo",
-	sizeof(struct fifo_sched_data),
-
-	pfifo_enqueue,
-	pfifo_dequeue,
-	pfifo_requeue,
-	fifo_drop,
-
-	fifo_init,
-	fifo_reset,
-	NULL,
-	fifo_init,
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "pfifo",
+	.priv_size	= sizeof(struct fifo_sched_data),
+
+	.enqueue	= pfifo_enqueue,
+	.dequeue	= pfifo_dequeue,
+	.requeue	= pfifo_requeue,
+	.drop		= fifo_drop,
+
+	.init		= fifo_init,
+	.reset		= fifo_reset,
+	.destroy	= NULL,
+	.change		= fifo_init,
 
-	fifo_dump,
+	.dump		= fifo_dump,
 };
 
 struct Qdisc_ops bfifo_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"bfifo",
-	sizeof(struct fifo_sched_data),
-
-	bfifo_enqueue,
-	bfifo_dequeue,
-	bfifo_requeue,
-	fifo_drop,
-
-	fifo_init,
-	fifo_reset,
-	NULL,
-	fifo_init,
-	fifo_dump,
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "bfifo",
+	.priv_size	= sizeof(struct fifo_sched_data),
+
+	.enqueue	= bfifo_enqueue,
+	.dequeue	= bfifo_dequeue,
+	.requeue	= bfifo_requeue,
+	.drop		= fifo_drop,
+
+	.init		= fifo_init,
+	.reset		= fifo_reset,
+	.destroy	= NULL,
+	.change		= fifo_init,
+
+	.dump		= fifo_dump,
 };
diff -Nru a/net/sched/sch_generic.c b/net/sched/sch_generic.c
--- a/net/sched/sch_generic.c	Fri Oct 11 21:22:51 2002
+++ b/net/sched/sch_generic.c	Fri Oct 11 21:22:51 2002
@@ -224,49 +224,48 @@
 
 struct Qdisc_ops noop_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"noop",
-	0,
-
-	noop_enqueue,
-	noop_dequeue,
-	noop_requeue,
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "noop",
+	.priv_size	= 0,
+
+	.enqueue	= noop_enqueue,
+	.dequeue	= noop_dequeue,
+	.requeue	= noop_requeue,
 };
 
 struct Qdisc noop_qdisc =
 {
-	noop_enqueue,
-	noop_dequeue,
-	TCQ_F_BUILTIN,
-	&noop_qdisc_ops,	
+	.enqueue	= noop_enqueue,
+	.dequeue	= noop_dequeue,
+	.flags		= TCQ_F_BUILTIN,
+	.ops		= &noop_qdisc_ops,	
 };
 
 
 struct Qdisc_ops noqueue_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"noqueue",
-	0,
-
-	noop_enqueue,
-	noop_dequeue,
-	noop_requeue,
-
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "noqueue",
+	.priv_size	= 0,
+
+	.enqueue	= noop_enqueue,
+	.dequeue	= noop_dequeue,
+	.requeue	= noop_requeue,
 };
 
 struct Qdisc noqueue_qdisc =
 {
-	NULL,
-	noop_dequeue,
-	TCQ_F_BUILTIN,
-	&noqueue_qdisc_ops,
+	.enqueue	= NULL,
+	.dequeue	= noop_dequeue,
+	.flags		= TCQ_F_BUILTIN,
+	.ops		= &noqueue_qdisc_ops,
 };
 
 
 static const u8 prio2band[TC_PRIO_MAX+1] =
-{ 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 };
+	{ 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 };
 
 /* 3-band FIFO queue: old style, but should be a bit faster than
    generic prio+fifo combination.
@@ -346,18 +345,17 @@
 
 static struct Qdisc_ops pfifo_fast_ops =
 {
-	NULL,
-	NULL,
-	"pfifo_fast",
-	3 * sizeof(struct sk_buff_head),
-
-	pfifo_fast_enqueue,
-	pfifo_fast_dequeue,
-	pfifo_fast_requeue,
-	NULL,
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "pfifo_fast",
+	.priv_size	= 3 * sizeof(struct sk_buff_head),
+
+	.enqueue	= pfifo_fast_enqueue,
+	.dequeue	= pfifo_fast_dequeue,
+	.requeue	= pfifo_fast_requeue,
 
-	pfifo_fast_init,
-	pfifo_fast_reset,
+	.init		= pfifo_fast_init,
+	.reset		= pfifo_fast_reset,
 };
 
 struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops)
diff -Nru a/net/sched/sch_gred.c b/net/sched/sch_gred.c
--- a/net/sched/sch_gred.c	Fri Oct 11 21:23:03 2002
+++ b/net/sched/sch_gred.c	Fri Oct 11 21:23:03 2002
@@ -603,19 +603,22 @@
 
 struct Qdisc_ops gred_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"gred",
-	sizeof(struct gred_sched),
-	gred_enqueue,
-	gred_dequeue,
-	gred_requeue,
-	gred_drop,
-	gred_init,
-	gred_reset,
-	gred_destroy,
-	gred_change, /* change */
-	gred_dump,
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "gred",
+	.priv_size	= sizeof(struct gred_sched),
+
+	.enqueue	= gred_enqueue,
+	.dequeue	= gred_dequeue,
+	.requeue	= gred_requeue,
+	.drop		= gred_drop,
+
+	.init		= gred_init,
+	.reset		= gred_reset,
+	.destroy	= gred_destroy,
+	.change		= gred_change,
+
+	.dump		= gred_dump,
 };
 
 
diff -Nru a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
--- a/net/sched/sch_ingress.c	Fri Oct 11 21:23:03 2002
+++ b/net/sched/sch_ingress.c	Fri Oct 11 21:23:03 2002
@@ -326,39 +326,39 @@
 
 static struct Qdisc_class_ops ingress_class_ops =
 {
-	ingress_graft,			/* graft */
-	ingress_leaf,			/* leaf */
-	ingress_get,			/* get */
-	ingress_put,			/* put */
-	ingress_change,			/* change */
-	NULL,				/* delete */
-	ingress_walk,				/* walk */
-
-	ingress_find_tcf,		/* tcf_chain */
-	ingress_bind_filter,		/* bind_tcf */
-	ingress_put,			/* unbind_tcf */
+	.graft		= ingress_graft,
+	.leaf		= ingress_leaf,
+	.get		= ingress_get,
+	.put		= ingress_put,
+	.change		= ingress_change,
+	.delete		= NULL,
+	.walk		= ingress_walk,
+
+	.tcf_chain	= ingress_find_tcf,
+	.bind_tcf	= ingress_bind_filter,
+	.unbind_tcf	= ingress_put,
 
-	NULL,		/* dump */
+	.dump		= NULL,
 };
 
 struct Qdisc_ops ingress_qdisc_ops =
 {
-	NULL,				/* next */
-	&ingress_class_ops,		/* cl_ops */
-	"ingress",
-	sizeof(struct ingress_qdisc_data),
-
-	ingress_enqueue,		/* enqueue */
-	ingress_dequeue,		/* dequeue */
-	ingress_requeue,		/* requeue */
-	ingress_drop,			/* drop */
-
-	ingress_init,			/* init */
-	ingress_reset,			/* reset */
-	ingress_destroy,		/* destroy */
-	NULL,				/* change */
+	.next		= NULL,
+	.cl_ops		= &ingress_class_ops,
+	.id		= "ingress",
+	.priv_size	= sizeof(struct ingress_qdisc_data),
+
+	.enqueue	= ingress_enqueue,
+	.dequeue	= ingress_dequeue,
+	.requeue	= ingress_requeue,
+	.drop		= ingress_drop,
+
+	.init		= ingress_init,
+	.reset		= ingress_reset,
+	.destroy	= ingress_destroy,
+	.change		= NULL,
 
-	ingress_dump,			/* dump */
+	.dump		= ingress_dump,
 };
 
 
diff -Nru a/net/sched/sch_prio.c b/net/sched/sch_prio.c
--- a/net/sched/sch_prio.c	Fri Oct 11 21:22:56 2002
+++ b/net/sched/sch_prio.c	Fri Oct 11 21:22:56 2002
@@ -365,40 +365,40 @@
 
 static struct Qdisc_class_ops prio_class_ops =
 {
-	prio_graft,
-	prio_leaf,
+	.graft		= prio_graft,
+	.leaf		= prio_leaf,
 
-	prio_get,
-	prio_put,
-	prio_change,
-	prio_delete,
-	prio_walk,
-
-	prio_find_tcf,
-	prio_bind,
-	prio_put,
+	.get		= prio_get,
+	.put		= prio_put,
+	.change		= prio_change,
+	.delete		= prio_delete,
+	.walk		= prio_walk,
+
+	.tcf_chain	= prio_find_tcf,
+	.bind_tcf	= prio_bind,
+	.unbind_tcf	= prio_put,
 
-	prio_dump_class,
+	.dump		= prio_dump_class,
 };
 
 struct Qdisc_ops prio_qdisc_ops =
 {
-	NULL,
-	&prio_class_ops,
-	"prio",
-	sizeof(struct prio_sched_data),
-
-	prio_enqueue,
-	prio_dequeue,
-	prio_requeue,
-	prio_drop,
-
-	prio_init,
-	prio_reset,
-	prio_destroy,
-	prio_tune,
+	next:		NULL,
+	cl_ops:		&prio_class_ops,
+	id:		"prio",
+	priv_size:	sizeof(struct prio_sched_data),
+
+	enqueue:	prio_enqueue,
+	dequeue:	prio_dequeue,
+	requeue:	prio_requeue,
+	drop:		prio_drop,
+
+	init:		prio_init,
+	reset:		prio_reset,
+	destroy:	prio_destroy,
+	change:		prio_tune,
 
-	prio_dump,
+	dump:		prio_dump,
 };
 
 #ifdef MODULE
diff -Nru a/net/sched/sch_red.c b/net/sched/sch_red.c
--- a/net/sched/sch_red.c	Fri Oct 11 21:23:05 2002
+++ b/net/sched/sch_red.c	Fri Oct 11 21:23:05 2002
@@ -463,22 +463,22 @@
 
 struct Qdisc_ops red_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"red",
-	sizeof(struct red_sched_data),
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "red",
+	.priv_size	= sizeof(struct red_sched_data),
 
-	red_enqueue,
-	red_dequeue,
-	red_requeue,
-	red_drop,
+	.enqueue	= red_enqueue,
+	.dequeue	= red_dequeue,
+	.requeue	= red_requeue,
+	.drop		= red_drop,
 
-	red_init,
-	red_reset,
-	red_destroy,
-	red_change,
+	.init		= red_init,
+	.reset		= red_reset,
+	.destroy	= red_destroy,
+	.change		= red_change,
 
-	red_dump,
+	.dump		= red_dump,
 };
 
 
diff -Nru a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
--- a/net/sched/sch_sfq.c	Fri Oct 11 21:23:04 2002
+++ b/net/sched/sch_sfq.c	Fri Oct 11 21:23:04 2002
@@ -470,22 +470,22 @@
 
 struct Qdisc_ops sfq_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"sfq",
-	sizeof(struct sfq_sched_data),
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "sfq",
+	.priv_size	= sizeof(struct sfq_sched_data),
 
-	sfq_enqueue,
-	sfq_dequeue,
-	sfq_requeue,
-	sfq_drop,
+	.enqueue	= sfq_enqueue,
+	.dequeue	= sfq_dequeue,
+	.requeue	= sfq_requeue,
+	.drop		= sfq_drop,
 
-	sfq_init,
-	sfq_reset,
-	sfq_destroy,
-	NULL, /* sfq_change */
+	.init		= sfq_init,
+	.reset		= sfq_reset,
+	.destroy	= sfq_destroy,
+	.change		= NULL,
 
-	sfq_dump,
+	.dump		= sfq_dump,
 };
 
 #ifdef MODULE
diff -Nru a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
--- a/net/sched/sch_tbf.c	Fri Oct 11 21:22:52 2002
+++ b/net/sched/sch_tbf.c	Fri Oct 11 21:22:52 2002
@@ -393,22 +393,22 @@
 
 struct Qdisc_ops tbf_qdisc_ops =
 {
-	NULL,
-	NULL,
-	"tbf",
-	sizeof(struct tbf_sched_data),
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "tbf",
+	.priv_size	= sizeof(struct tbf_sched_data),
 
-	tbf_enqueue,
-	tbf_dequeue,
-	tbf_requeue,
-	tbf_drop,
+	.enqueue	= tbf_enqueue,
+	.dequeue	= tbf_dequeue,
+	.requeue	= tbf_requeue,
+	.drop		= tbf_drop,
 
-	tbf_init,
-	tbf_reset,
-	tbf_destroy,
-	tbf_change,
+	.init		= tbf_init,
+	.reset		= tbf_reset,
+	.destroy	= tbf_destroy,
+	.change		= tbf_change,
 
-	tbf_dump,
+	.dump		= tbf_dump,
 };
 
 
diff -Nru a/net/sched/sch_teql.c b/net/sched/sch_teql.c
--- a/net/sched/sch_teql.c	Fri Oct 11 21:22:54 2002
+++ b/net/sched/sch_teql.c	Fri Oct 11 21:22:54 2002
@@ -440,20 +440,20 @@
 
 static struct teql_master the_master = {
 {
-	NULL,
-	NULL,
-	"",
-	sizeof(struct teql_sched_data),
+	.next		= NULL,
+	.cl_ops		= NULL,
+	.id		= "",
+	.priv_size	= sizeof(struct teql_sched_data),
 
-	teql_enqueue,
-	teql_dequeue,
-	teql_requeue,
-	NULL,
+	.enqueue	= teql_enqueue,
+	.dequeue	= teql_dequeue,
+	.requeue	= teql_requeue,
+	.drop		= NULL,
 
-	teql_qdisc_init,
-	teql_reset,
-	teql_destroy,
-	NULL,
+	.init		= teql_qdisc_init,
+	.reset		= teql_reset,
+	.destroy	= teql_destroy,
+	.dump		= NULL,
 },};
 
 
diff -Nru a/net/sctp/input.c b/net/sctp/input.c
--- a/net/sctp/input.c	Fri Oct 11 21:22:52 2002
+++ b/net/sctp/input.c	Fri Oct 11 21:22:52 2002
@@ -229,7 +229,7 @@
 	 */
 	sctp_bh_lock_sock(sk);
 
-	if (__sctp_sock_busy(sk)) {
+	if (sock_owned_by_user(sk)) {
 		sk_add_backlog(sk, (struct sk_buff *) chunk);
 	} else {
 		sctp_backlog_rcv(sk, (struct sk_buff *) chunk);
diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c
--- a/net/sctp/ipv6.c	Fri Oct 11 21:23:00 2002
+++ b/net/sctp/ipv6.c	Fri Oct 11 21:23:00 2002
@@ -295,11 +295,6 @@
 static struct inet6_protocol sctpv6_protocol = {
 	.handler      = sctp_rcv,
 	.err_handler  = sctp_v6_err,
-	.next         = NULL,
-	.protocol     = IPPROTO_SCTP,
-	.copy         = 0,
-	.data         = NULL,
-	.name         = "SCTPv6"
 };
 
 static sctp_func_t sctp_ipv6_specific = {
@@ -320,10 +315,12 @@
 /* Initialize IPv6 support and register with inet6 stack.  */
 int sctp_v6_init(void)
 {
+	/* Register inet6 protocol. */
+	if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
+		return -EAGAIN;
+
 	/* Add SCTPv6 to inetsw6 linked list. */
 	inet6_register_protosw(&sctpv6_protosw);
-	/* Register inet6 protocol. */
-	inet6_add_protocol(&sctpv6_protocol);
 
 	/* Register the SCTP specfic PF_INET6 functions. */
 	sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific);
@@ -339,6 +336,6 @@
 void sctp_v6_exit(void)
 {
 	list_del(&sctp_ipv6_specific.list);
-	inet6_del_protocol(&sctpv6_protocol);
+	inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
 	inet6_unregister_protosw(&sctpv6_protosw);
 }
diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c
--- a/net/sctp/protocol.c	Fri Oct 11 21:23:00 2002
+++ b/net/sctp/protocol.c	Fri Oct 11 21:23:00 2002
@@ -434,10 +434,8 @@
 
 /* Register with IP layer.  */
 static struct inet_protocol sctp_protocol = {
-	.handler     = sctp_rcv,               /* SCTP input handler.  */
-	.err_handler = sctp_v4_err,            /* SCTP error control   */
-	.protocol    = IPPROTO_SCTP,           /* protocol ID          */
-	.name        = "SCTP"                  /* name                 */
+	.handler     = sctp_rcv,
+	.err_handler = sctp_v4_err,
 };
 
 /* IPv4 address related functions.  */
@@ -485,12 +483,13 @@
 	int i;
 	int status = 0;
 
+	/* Add SCTP to inet_protos hash table.  */
+	if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
+		return -EAGAIN;
+
 	/* Add SCTP to inetsw linked list.  */
 	inet_register_protosw(&sctp_protosw);
 
-	/* Add SCTP to inet_protos hash table.  */
-	inet_add_protocol(&sctp_protocol);
-
 	/* Initialize proc fs directory.  */
 	sctp_proc_init();
 
@@ -626,7 +625,7 @@
 err_ahash_alloc:
 	sctp_dbg_objcnt_exit();
 	sctp_proc_exit();
-	inet_del_protocol(&sctp_protocol);
+	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
 	inet_unregister_protosw(&sctp_protosw);
 	return status;
 }
@@ -656,7 +655,7 @@
 	sctp_dbg_objcnt_exit();
 	sctp_proc_exit();
 
-	inet_del_protocol(&sctp_protocol);
+	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
 	inet_unregister_protosw(&sctp_protosw);
 }
 
diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
--- a/net/sctp/sm_sideeffect.c	Fri Oct 11 21:23:00 2002
+++ b/net/sctp/sm_sideeffect.c	Fri Oct 11 21:23:00 2002
@@ -798,7 +798,7 @@
 	/* Check whether a task is in the sock.  */
 
 	sctp_bh_lock_sock(asoc->base.sk);
-	if (__sctp_sock_busy(asoc->base.sk)) {
+	if (sock_owned_by_user(asoc->base.sk)) {
 		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
 
 		/* Try again later.  */
@@ -837,7 +837,7 @@
 	int error = 0;
 
 	sctp_bh_lock_sock(asoc->base.sk);
-	if (__sctp_sock_busy(asoc->base.sk)) {
+	if (sock_owned_by_user(asoc->base.sk)) {
 		SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n",
 				  __FUNCTION__,
 				  timeout_type);
@@ -911,7 +911,7 @@
 	sctp_association_t *asoc = transport->asoc;
 
 	sctp_bh_lock_sock(asoc->base.sk);
-	if (__sctp_sock_busy(asoc->base.sk)) {
+	if (sock_owned_by_user(asoc->base.sk)) {
 		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
 
 		/* Try again later.  */
diff -Nru a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
--- a/net/sctp/sm_statetable.c	Fri Oct 11 21:22:57 2002
+++ b/net/sctp/sm_statetable.c	Fri Oct 11 21:22:57 2002
@@ -555,7 +555,7 @@
 	 .name = "sctp_sf_cookie_wait_prm_shutdown"}, \
 	/* SCTP_STATE_COOKIE_ECHOED */ \
 	{.fn = sctp_sf_cookie_echoed_prm_shutdown, \
-	 name:"sctp_sf_cookie_echoed_prm_shutdown"},\
+	 .name = "sctp_sf_cookie_echoed_prm_shutdown"},\
 	/* SCTP_STATE_ESTABLISHED */ \
 	{.fn = sctp_sf_do_9_2_prm_shutdown, \
 	 .name = "sctp_sf_do_9_2_prm_shutdown"}, \
diff -Nru a/net/socket.c b/net/socket.c
--- a/net/socket.c	Fri Oct 11 21:22:55 2002
+++ b/net/socket.c	Fri Oct 11 21:22:55 2002
@@ -1684,10 +1684,6 @@
 extern void wanrouter_init(void);
 #endif
 
-#ifdef CONFIG_BLUEZ
-extern void bluez_init(void);
-#endif
-
 void __init sock_init(void)
 {
 	int i;
@@ -1747,10 +1743,6 @@
 #endif
 #ifdef CONFIG_NETFILTER
 	netfilter_init();
-#endif
-
-#ifdef CONFIG_BLUEZ
-	bluez_init();
 #endif
 }
 
diff -Nru a/net/sunrpc/Makefile b/net/sunrpc/Makefile
--- a/net/sunrpc/Makefile	Fri Oct 11 21:22:52 2002
+++ b/net/sunrpc/Makefile	Fri Oct 11 21:22:52 2002
@@ -8,9 +8,9 @@
 
 sunrpc-y := clnt.o xprt.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
-	    svc.o svcsock.o svcauth.o \
+	    svc.o svcsock.o svcauth.o svcauth_unix.o \
 	    pmap_clnt.o timer.o xdr.o \
-	    sunrpc_syms.o
+	    sunrpc_syms.o cache.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
 sunrpc-objs := $(sunrpc-y)
diff -Nru a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
--- a/net/sunrpc/auth_null.c	Fri Oct 11 21:23:06 2002
+++ b/net/sunrpc/auth_null.c	Fri Oct 11 21:23:06 2002
@@ -125,20 +125,20 @@
 }
 
 struct rpc_authops	authnull_ops = {
-	RPC_AUTH_NULL,
+	.au_flavor	= RPC_AUTH_NULL,
 #ifdef RPC_DEBUG
-	"NULL",
+	.au_name	= "NULL",
 #endif
-	nul_create,
-	nul_destroy,
-	nul_create_cred
+	.create		= nul_create,
+	.destroy	= nul_destroy,
+	.crcreate	= nul_create_cred,
 };
 
 static
 struct rpc_credops	null_credops = {
-	nul_destroy_cred,
-	nul_match,
-	nul_marshal,
-	nul_refresh,
-	nul_validate
+	.crdestroy	= nul_destroy_cred,
+	.crmatch	= nul_match,
+	.crmarshal	= nul_marshal,
+	.crrefresh	= nul_refresh,
+	.crvalidate	= nul_validate,
 };
diff -Nru a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
--- a/net/sunrpc/auth_unix.c	Fri Oct 11 21:22:51 2002
+++ b/net/sunrpc/auth_unix.c	Fri Oct 11 21:22:51 2002
@@ -239,20 +239,20 @@
 }
 
 struct rpc_authops	authunix_ops = {
-	RPC_AUTH_UNIX,
+	.au_flavor	= RPC_AUTH_UNIX,
 #ifdef RPC_DEBUG
-	"UNIX",
+	.au_name	= "UNIX",
 #endif
-	unx_create,
-	unx_destroy,
-	unx_create_cred
+	.create		= unx_create,
+	.destroy	= unx_destroy,
+	.crcreate	= unx_create_cred,
 };
 
 static
 struct rpc_credops	unix_credops = {
-	unx_destroy_cred,
-	unx_match,
-	unx_marshal,
-	unx_refresh,
-	unx_validate
+	.crdestroy	= unx_destroy_cred,
+	.crmatch	= unx_match,
+	.crmarshal	= unx_marshal,
+	.crrefresh	= unx_refresh,
+	.crvalidate	= unx_validate,
 };
diff -Nru a/net/sunrpc/cache.c b/net/sunrpc/cache.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/sunrpc/cache.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,927 @@
+/*
+ * net/sunrpc/cache.c
+ *
+ * Generic code for various authentication-related caches
+ * used by sunrpc clients and servers.
+ *
+ * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
+ *
+ * Released under terms in GPL version 2.  See COPYING.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <asm/ioctls.h>
+#include <linux/sunrpc/types.h>
+#include <linux/sunrpc/cache.h>
+#include <linux/sunrpc/stats.h>
+
+#define	 RPCDBG_FACILITY RPCDBG_CACHE
+
+void cache_init(struct cache_head *h)
+{
+	time_t now = CURRENT_TIME;
+	h->next = NULL;
+	h->flags = 0;
+	atomic_set(&h->refcnt, 0);
+	h->expiry_time = now + CACHE_NEW_EXPIRY;
+	h->last_refresh = now;
+}
+
+
+static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
+/*
+ * This is the generic cache management routine for all
+ * the authentication caches.
+ * It checks the currency of a cache item and will (later)
+ * initiate an upcall to fill it if needed.
+ *
+ *
+ * Returns 0 if the cache_head can be used, or cache_puts it and returns
+ * -EAGAIN if upcall is pending,
+ * -ENOENT if cache entry was negative
+ */
+int cache_check(struct cache_detail *detail,
+		    struct cache_head *h, struct cache_req *rqstp)
+{
+	int rv;
+	long refresh_age, age;
+
+	/* First decide return status as best we can */
+	if (!test_bit(CACHE_VALID, &h->flags) ||
+	    h->expiry_time < CURRENT_TIME)
+		rv = -EAGAIN;
+	else if (detail->flush_time > h->last_refresh)
+		rv = -EAGAIN;
+	else {
+		/* entry is valid */
+		if (test_bit(CACHE_NEGATIVE, &h->flags))
+			rv = -ENOENT;
+		else rv = 0;
+	}
+
+	/* now see if we want to start an upcall */
+	refresh_age = (h->expiry_time - h->last_refresh);
+	age = CURRENT_TIME - h->last_refresh;
+
+	if (rqstp == NULL) {
+		if (rv == -EAGAIN)
+			rv = -ENOENT;
+	} else if (rv == -EAGAIN || age > refresh_age/2) {
+		dprintk("Want update, refage=%ld, age=%ld\n", refresh_age, age);
+		if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
+			switch (cache_make_upcall(detail, h)) {
+			case -EINVAL:
+				clear_bit(CACHE_PENDING, &h->flags);
+				if (rv == -EAGAIN) {
+					set_bit(CACHE_NEGATIVE, &h->flags);
+					cache_fresh(detail, h, CURRENT_TIME+CACHE_NEW_EXPIRY);
+					rv = -ENOENT;
+				}
+				break;
+
+			case -EAGAIN:
+				clear_bit(CACHE_PENDING, &h->flags);
+				cache_revisit_request(h);
+				break;
+			}
+		}
+	}
+
+	if (rv == -EAGAIN)
+		cache_defer_req(rqstp, h);
+
+	if (rv && h)
+		detail->cache_put(h, detail);
+	return rv;
+}
+
+static void queue_loose(struct cache_detail *detail, struct cache_head *ch);
+
+void cache_fresh(struct cache_detail *detail,
+		 struct cache_head *head, time_t expiry)
+{
+
+	head->expiry_time = expiry;
+	head->last_refresh = CURRENT_TIME;
+	if (!test_and_set_bit(CACHE_VALID, &head->flags))
+		cache_revisit_request(head);
+	if (test_and_clear_bit(CACHE_PENDING, &head->flags))
+		queue_loose(detail, head);
+}
+
+/*
+ * caches need to be periodically cleaned.
+ * For this we maintain a list of cache_detail and
+ * a current pointer into that list and into the table
+ * for that entry.
+ *
+ * Each time clean_cache is called it finds the next non-empty entry
+ * in the current table and walks the list in that entry
+ * looking for entries that can be removed.
+ *
+ * An entry gets removed if:
+ * - The expiry is before current time
+ * - The last_refresh time is before the flush_time for that cache
+ *
+ * later we might drop old entries with non-NEVER expiry if that table
+ * is getting 'full' for some definition of 'full'
+ *
+ * The question of "how often to scan a table" is an interesting one
+ * and is answered in part by the use of the "nextcheck" field in the
+ * cache_detail.
+ * When a scan of a table begins, the nextcheck field is set to a time
+ * that is well into the future.
+ * While scanning, if an expiry time is found that is earlier than the
+ * current nextcheck time, nextcheck is set to that expiry time.
+ * If the flush_time is ever set to a time earlier than the nextcheck
+ * time, the nextcheck time is then set to that flush_time.
+ *
+ * A table is then only scanned if the current time is at least
+ * the nextcheck time.
+ * 
+ */
+
+static LIST_HEAD(cache_list);
+static spinlock_t cache_list_lock = SPIN_LOCK_UNLOCKED;
+static struct cache_detail *current_detail;
+static int current_index;
+
+struct file_operations cache_file_operations;
+
+void cache_register(struct cache_detail *cd)
+{
+	cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc);
+	if (cd->proc_ent) {
+		struct proc_dir_entry *p;
+		cd->proc_ent->owner = THIS_MODULE;
+		
+		p = create_proc_entry("channel", S_IFREG|S_IRUSR|S_IWUSR,
+				      cd->proc_ent);
+		if (p) {
+			p->proc_fops = &cache_file_operations;
+			p->owner = THIS_MODULE;
+			p->data = cd;
+		}
+	}
+	rwlock_init(&cd->hash_lock);
+	INIT_LIST_HEAD(&cd->queue);
+	spin_lock(&cache_list_lock);
+	cd->nextcheck = 0;
+	cd->entries = 0;
+	atomic_set(&cd->readers, 0);
+	cd->last_close = CURRENT_TIME;
+	list_add(&cd->others, &cache_list);
+	spin_unlock(&cache_list_lock);
+}
+
+int cache_unregister(struct cache_detail *cd)
+{
+	cache_purge(cd);
+	spin_lock(&cache_list_lock);
+	write_lock(&cd->hash_lock);
+	if (cd->entries || atomic_read(&cd->inuse)) {
+		write_unlock(&cd->hash_lock);
+		spin_unlock(&cache_list_lock);
+		return -EBUSY;
+	}
+	if (current_detail == cd)
+		current_detail = NULL;
+	list_del_init(&cd->others);
+	write_unlock(&cd->hash_lock);
+	spin_unlock(&cache_list_lock);
+	if (cd->proc_ent) {
+		cd->proc_ent = NULL;
+		remove_proc_entry(cd->name, proc_net_rpc);
+	}
+	return 0;
+}
+
+struct cache_detail *cache_find(char *name)
+{
+	struct list_head *l;
+
+	spin_lock(&cache_list_lock);
+	list_for_each(l, &cache_list) {
+		struct cache_detail *cd = list_entry(l, struct cache_detail, others);
+		
+		if (strcmp(cd->name, name)==0) {
+			atomic_inc(&cd->inuse);
+			spin_unlock(&cache_list_lock);
+			return cd;
+		}
+	}
+	spin_unlock(&cache_list_lock);
+	return NULL;
+}
+
+/* cache_drop must be called on any cache returned by
+ * cache_find, after it has been used
+ */
+void cache_drop(struct cache_detail *detail)
+{
+	atomic_dec(&detail->inuse);
+}
+
+/* clean cache tries to find something to clean
+ * and cleans it.
+ * It returns 1 if it cleaned something,
+ *            0 if it didn't find anything this time
+ *           -1 if it fell off the end of the list.
+ */
+int cache_clean(void)
+{
+	int rv = 0;
+	struct list_head *next;
+
+	spin_lock(&cache_list_lock);
+
+	/* find a suitable table if we don't already have one */
+	while (current_detail == NULL ||
+	    current_index >= current_detail->hash_size) {
+		if (current_detail)
+			next = current_detail->others.next;
+		else
+			next = cache_list.next;
+		if (next == &cache_list) {
+			current_detail = NULL;
+			spin_unlock(&cache_list_lock);
+			return -1;
+		}
+		current_detail = list_entry(next, struct cache_detail, others);
+		if (current_detail->nextcheck > CURRENT_TIME)
+			current_index = current_detail->hash_size;
+		else {
+			current_index = 0;
+			current_detail->nextcheck = CURRENT_TIME+30*60;
+		}
+	}
+
+	/* find a non-empty bucket in the table */
+	while (current_detail &&
+	       current_index < current_detail->hash_size &&
+	       current_detail->hash_table[current_index] == NULL)
+		current_index++;
+
+	/* find a cleanable entry in the bucket and clean it, or set to next bucket */
+	
+	if (current_detail && current_index < current_detail->hash_size) {
+		struct cache_head *ch, **cp;
+		
+		write_lock(&current_detail->hash_lock);
+
+		/* Ok, now to clean this strand */
+			
+		cp = & current_detail->hash_table[current_index];
+		ch = *cp;
+		for (; ch; cp= & ch->next, ch= *cp) {
+			if (atomic_read(&ch->refcnt))
+				continue;
+			if (ch->expiry_time < CURRENT_TIME
+			    || ch->last_refresh < current_detail->flush_time
+				)
+				break;
+			if (current_detail->nextcheck > ch->expiry_time)
+				current_detail->nextcheck = ch->expiry_time+1;
+		}
+		if (ch) {
+			cache_get(ch);
+			clear_bit(CACHE_HASHED, &ch->flags);
+			*cp = ch->next;
+			ch->next = NULL;
+			current_detail->entries--;
+			rv = 1;
+		}
+		write_unlock(&current_detail->hash_lock);
+		if (ch)
+			current_detail->cache_put(ch, current_detail);
+		else
+			current_index ++;
+	}
+	spin_unlock(&cache_list_lock);
+
+	return rv;
+}
+
+/* 
+ * Clean all caches promptly.  This just calls cache_clean
+ * repeatedly until we are sure that every cache has had a chance to 
+ * be fully cleaned
+ */
+void cache_flush(void)
+{
+	while (cache_clean() != -1)
+		cond_resched();
+	while (cache_clean() != -1)
+		cond_resched();
+}
+
+void cache_purge(struct cache_detail *detail)
+{
+	detail->flush_time = CURRENT_TIME+1;
+	detail->nextcheck = CURRENT_TIME;
+	cache_flush();
+}
+
+
+
+/*
+ * Deferral and Revisiting of Requests.
+ *
+ * If a cache lookup finds a pending entry, we
+ * need to defer the request and revisit it later.
+ * All deferred requests are stored in a hash table,
+ * indexed by "struct cache_head *".
+ * As it may be wasteful to store a whole request
+ * structure, we allow the request to provide a 
+ * deferred form, which must contain a
+ * 'struct cache_deferred_req'
+ * This cache_deferred_req contains a method to allow
+ * it to be revisited when cache info is available
+ */
+
+#define	DFR_HASHSIZE	(PAGE_SIZE/sizeof(struct list_head))
+#define	DFR_HASH(item)	((((long)item)>>4 ^ (((long)item)>>13)) % DFR_HASHSIZE)
+
+#define	DFR_MAX	300	/* ??? */
+
+spinlock_t cache_defer_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(cache_defer_list);
+static struct list_head cache_defer_hash[DFR_HASHSIZE];
+static int cache_defer_cnt;
+
+void cache_defer_req(struct cache_req *req, struct cache_head *item)
+{
+	struct cache_deferred_req *dreq;
+	int hash = DFR_HASH(item);
+
+	dreq = req->defer(req);
+	if (dreq == NULL)
+		return;
+
+	dreq->item = item;
+	dreq->recv_time = CURRENT_TIME;
+
+	spin_lock(&cache_defer_lock);
+
+	list_add(&dreq->recent, &cache_defer_list);
+
+	if (cache_defer_hash[hash].next == NULL)
+		INIT_LIST_HEAD(&cache_defer_hash[hash]);
+	list_add(&dreq->hash, &cache_defer_hash[hash]);
+
+	/* it is in, now maybe clean up */
+	dreq = NULL;
+	if (++cache_defer_cnt > DFR_MAX) {
+		/* too much in the cache, randomly drop
+		 * first or last
+		 */
+		if (net_random()&1) 
+			dreq = list_entry(cache_defer_list.next,
+					  struct cache_deferred_req,
+					  recent);
+		else
+			dreq = list_entry(cache_defer_list.prev,
+					  struct cache_deferred_req,
+					  recent);
+		list_del(&dreq->recent);
+		list_del(&dreq->hash);
+		cache_defer_cnt--;
+	}
+	spin_unlock(&cache_defer_lock);
+
+	if (dreq) {
+		/* there was one too many */
+		dreq->revisit(dreq, 1);
+	}
+	if (test_bit(CACHE_VALID, &item->flags)) {
+		/* must have just been validated... */
+		cache_revisit_request(item);
+	}
+}
+
+void cache_revisit_request(struct cache_head *item)
+{
+	struct cache_deferred_req *dreq;
+	struct list_head pending;
+
+	struct list_head *lp;
+	int hash = DFR_HASH(item);
+
+	INIT_LIST_HEAD(&pending);
+	spin_lock(&cache_defer_lock);
+	
+	lp = cache_defer_hash[hash].next;
+	if (lp) {
+		while (lp != &cache_defer_hash[hash]) {
+			dreq = list_entry(lp, struct cache_deferred_req, hash);
+			lp = lp->next;
+			if (dreq->item == item) {
+				list_del(&dreq->hash);
+				list_move(&dreq->recent, &pending);
+				cache_defer_cnt--;
+			}
+		}
+	}
+	spin_unlock(&cache_defer_lock);
+
+	while (!list_empty(&pending)) {
+		dreq = list_entry(pending.next, struct cache_deferred_req, recent);
+		list_del_init(&dreq->recent);
+		dreq->revisit(dreq, 0);
+	}
+}
+
+/*
+ * communicate with user-space
+ *
+ * We have a magic /proc file - /proc/sunrpc/cache
+ * On read, you get a full request, or block
+ * On write, an update request is processed
+ * Poll works if anything to read, and always allows write
+ *
+ * Implemented by linked list of requests.  Each open file has 
+ * a ->private that also exists in this list.  New request are added
+ * to the end and may wakeup and preceeding readers.
+ * New readers are added to the head.  If, on read, an item is found with
+ * CACHE_UPCALLING clear, we free it from the list.
+ *
+ */
+
+static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(queue_io_sem);
+
+struct cache_queue {
+	struct list_head	list;
+	int			reader;	/* if 0, then request */
+};
+struct cache_request {
+	struct cache_queue	q;
+	struct cache_head	*item;
+	char			* buf;
+	int			len;
+	int			readers;
+};
+struct cache_reader {
+	struct cache_queue	q;
+	int			offset;	/* if non-0, we have a refcnt on next request */
+	char			*page;
+};
+
+static ssize_t
+cache_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+{
+	struct cache_reader *rp = filp->private_data;
+	struct cache_request *rq;
+	struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+	int err;
+
+	if (ppos != &filp->f_pos)
+		return -ESPIPE;
+
+	if (count == 0)
+		return 0;
+
+	down(&queue_io_sem); /* protect against multiple concurrent
+			      * readers on this file */
+ again:
+	spin_lock(&queue_lock);
+	/* need to find next request */
+	while (rp->q.list.next != &cd->queue &&
+	       list_entry(rp->q.list.next, struct cache_queue, list)
+	       ->reader) {
+		struct list_head *next = rp->q.list.next;
+		list_move(&rp->q.list, next);
+	}
+	if (rp->q.list.next == &cd->queue) {
+		spin_unlock(&queue_lock);
+		up(&queue_io_sem);
+		if (rp->offset)
+			BUG();
+		return 0;
+	}
+	rq = container_of(rp->q.list.next, struct cache_request, q.list);
+	if (rq->q.reader) BUG();
+	if (rp->offset == 0)
+		rq->readers++;
+	spin_unlock(&queue_lock);
+
+	if (rp->offset == 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) {
+		err = -EAGAIN;
+		spin_lock(&queue_lock);
+		list_move(&rp->q.list, &rq->q.list);
+		spin_unlock(&queue_lock);
+	} else {
+		if (rp->offset + count > rq->len)
+			count = rq->len - rp->offset;
+		err = -EFAULT;
+		if (copy_to_user(buf, rq->buf + rp->offset, count))
+			goto out;
+		rp->offset += count;
+		if (rp->offset >= rq->len) {
+			rp->offset = 0;
+			spin_lock(&queue_lock);
+			list_move(&rp->q.list, &rq->q.list);
+			spin_unlock(&queue_lock);
+		}
+		err = 0;
+	}
+ out:
+	if (rp->offset == 0) {
+		/* need to release rq */
+		spin_lock(&queue_lock);
+		rq->readers--;
+		if (rq->readers == 0 &&
+		    !test_bit(CACHE_PENDING, &rq->item->flags)) {
+			list_del(&rq->q.list);
+			spin_unlock(&queue_lock);
+			cd->cache_put(rq->item, cd);
+			kfree(rq->buf);
+			kfree(rq);
+		} else
+			spin_unlock(&queue_lock);
+	}
+	if (err == -EAGAIN)
+		goto again;
+	up(&queue_io_sem);
+	return err ? err :  count;
+}
+
+static ssize_t
+cache_write(struct file *filp, const char *buf, size_t count,
+	    loff_t *ppos)
+{
+	int err;
+	struct cache_reader *rp = filp->private_data;
+	struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+
+	if (ppos != &filp->f_pos)
+		return -ESPIPE;
+
+	if (count == 0)
+		return 0;
+	if (count > PAGE_SIZE)
+		return -EINVAL;
+
+	down(&queue_io_sem);
+
+	if (rp->page == NULL) {
+		rp->page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (rp->page == NULL) {
+			up(&queue_io_sem);
+			return -ENOMEM;
+		}
+	}
+
+	if (copy_from_user(rp->page, buf, count)) {
+		up(&queue_io_sem);
+		return -EFAULT;
+	}
+	if (count < PAGE_SIZE)
+		rp->page[count] = '\0';
+	if (cd->cache_parse)
+		err = cd->cache_parse(cd, rp->page, count);
+	else
+		err = -EINVAL;
+
+	up(&queue_io_sem);
+	return err ? err : count;
+}
+
+static DECLARE_WAIT_QUEUE_HEAD(queue_wait);
+
+static unsigned int
+cache_poll(struct file *filp, poll_table *wait)
+{
+	unsigned int mask;
+	struct cache_reader *rp = filp->private_data;
+	struct cache_queue *cq;
+	struct cache_detail *cd = PDE(filp->f_dentry->d_inode)->data;
+
+	poll_wait(filp, &queue_wait, wait);
+
+	/* alway allow write */
+	mask = POLL_OUT | POLLWRNORM;
+	spin_lock(&queue_lock);
+
+	for (cq= &rp->q; &cq->list != &cd->queue;
+	     cq = list_entry(cq->list.next, struct cache_queue, list))
+		if (!cq->reader) {
+			mask |= POLLIN | POLLRDNORM;
+			break;
+		}
+	spin_unlock(&queue_lock);
+	return mask;
+}
+
+static int
+cache_ioctl(struct inode *ino, struct file *filp,
+	    unsigned int cmd, unsigned long arg)
+{
+	int len = 0;
+	struct cache_reader *rp = filp->private_data;
+	struct cache_queue *cq;
+	struct cache_detail *cd = PDE(ino)->data;
+
+	if (cmd != FIONREAD)
+		return -EINVAL;
+	spin_lock(&queue_lock);
+
+	/* only find the length remaining in current request,
+	 * or the length of the next request
+	 */
+	for (cq= &rp->q; &cq->list != &cd->queue;
+	     cq = list_entry(cq->list.next, struct cache_queue, list))
+		if (!cq->reader) {
+			struct cache_request *cr =
+				container_of(cq, struct cache_request, q);
+			len = cr->len - rp->offset;
+			break;
+		}
+	spin_unlock(&queue_lock);
+
+	return put_user(len, (int *)arg);
+}
+
+static int
+cache_open(struct inode *inode, struct file *filp)
+{
+	struct cache_reader *rp;
+	struct cache_detail *cd = PDE(inode)->data;
+
+	rp = kmalloc(sizeof(*rp), GFP_KERNEL);
+	if (!rp)
+		return -ENOMEM;
+	rp->page = NULL;
+	rp->offset = 0;
+	rp->q.reader = 1;
+	atomic_inc(&cd->readers);
+	spin_lock(&queue_lock);
+	list_add(&rp->q.list, &cd->queue);
+	spin_unlock(&queue_lock);
+	filp->private_data = rp;
+	return 0;
+}
+
+static int
+cache_release(struct inode *inode, struct file *filp)
+{
+	struct cache_reader *rp = filp->private_data;
+	struct cache_detail *cd = PDE(inode)->data;
+
+	spin_lock(&queue_lock);
+	if (rp->offset) {
+		struct cache_queue *cq;
+		for (cq= &rp->q; &cq->list != &cd->queue;
+		     cq = list_entry(cq->list.next, struct cache_queue, list))
+			if (!cq->reader) {
+				container_of(cq, struct cache_request, q)
+					->readers--;
+				break;
+			}
+		rp->offset = 0;
+	}
+	list_del(&rp->q.list);
+	spin_unlock(&queue_lock);
+
+	if (rp->page)
+		kfree(rp->page);
+
+	filp->private_data = NULL;
+	kfree(rp);
+
+	cd->last_close = CURRENT_TIME;
+	atomic_dec(&cd->readers);
+	return 0;
+}
+
+
+
+struct file_operations cache_file_operations = {
+	.llseek		= no_llseek,
+	.read		= cache_read,
+	.write		= cache_write,
+	.poll		= cache_poll,
+	.ioctl		= cache_ioctl, /* for FIONREAD */
+	.open		= cache_open,
+	.release	= cache_release,
+};
+
+
+static void queue_loose(struct cache_detail *detail, struct cache_head *ch)
+{
+	struct cache_queue *cq;
+	spin_lock(&queue_lock);
+	list_for_each_entry(cq, &detail->queue, list)
+		if (!cq->reader) {
+			struct cache_request *cr = container_of(cq, struct cache_request, q);
+			if (cr->item != ch)
+				continue;
+			if (cr->readers != 0)
+				break;
+			list_del(&cr->q.list);
+			spin_unlock(&queue_lock);
+			detail->cache_put(cr->item, detail);
+			kfree(cr->buf);
+			kfree(cr);
+			return;
+		}
+	spin_unlock(&queue_lock);
+}
+
+/*
+ * Support routines for text-based upcalls.
+ * Fields are separated by spaces.
+ * Fields are either mangled to quote space tab newline slosh with slosh
+ * or a hexified with a leading \x
+ * Record is terminated with newline.
+ *
+ */
+
+void add_word(char **bpp, int *lp, char *str)
+{
+	char *bp = *bpp;
+	int len = *lp;
+	char c;
+
+	if (len < 0) return;
+
+	while ((c=*str++) && len)
+		switch(c) {
+		case ' ':
+		case '\t':
+		case '\n':
+		case '\\':
+			if (len >= 4) {
+				*bp++ = '\\';
+				*bp++ = '0' + ((c & 0300)>>6);
+				*bp++ = '0' + ((c & 0070)>>3);
+				*bp++ = '0' + ((c & 0007)>>0);
+			}
+			len -= 4;
+			break;
+		default:
+			*bp++ = c;
+			len--;
+		}
+	if (c || len <1) len = -1;
+	else {
+		*bp++ = ' ';
+		len--;
+	}
+	*bpp = bp;
+	*lp = len;
+}
+
+void add_hex(char **bpp, int *lp, char *buf, int blen)
+{
+	char *bp = *bpp;
+	int len = *lp;
+
+	if (len < 0) return;
+
+	if (len > 2) {
+		*bp++ = '\\';
+		*bp++ = 'x';
+		len -= 2;
+		while (blen && len >= 2) {
+			unsigned char c = *buf++;
+			*bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'0');
+			*bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'0');
+			len -= 2;
+			blen--;
+		}
+	}
+	if (blen || len<1) len = -1;
+	else {
+		*bp++ = ' ';
+		len--;
+	}
+	*bpp = bp;
+	*lp = len;
+}
+
+			
+
+/*
+ * register an upcall request to user-space.
+ * Each request is at most one page long.
+ */
+static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h)
+{
+
+	char *buf;
+	struct cache_request *crq;
+	char *bp;
+	int len;
+
+	if (detail->cache_request == NULL)
+		return -EINVAL;
+
+	if (atomic_read(&detail->readers) == 0 &&
+	    detail->last_close < CURRENT_TIME - 60)
+		/* nobody is listening */
+		return -EINVAL;
+
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -EAGAIN;
+
+	crq = kmalloc(sizeof (*crq), GFP_KERNEL);
+	if (!crq) {
+		kfree(buf);
+		return -EAGAIN;
+	}
+
+	bp = buf; len = PAGE_SIZE;
+
+	detail->cache_request(detail, h, &bp, &len);
+
+	if (len < 0) {
+		kfree(buf);
+		kfree(crq);
+		return -EAGAIN;
+	}
+	crq->q.reader = 0;
+	crq->item = cache_get(h);
+	crq->buf = buf;
+	crq->len = PAGE_SIZE - len;
+	crq->readers = 0;
+	spin_lock(&queue_lock);
+	list_add_tail(&crq->q.list, &detail->queue);
+	spin_unlock(&queue_lock);
+	wake_up(&queue_wait);
+	return 0;
+}
+
+/*
+ * parse a message from user-space and pass it
+ * to an appropriate cache
+ * Messages are, like requests, separated into fields by
+ * spaces and dequotes as \xHEXSTRING or embedded \nnn octal
+ *
+ * Message is 
+ *   reply cachename expiry key ... content....
+ *
+ * key and content are both parsed by cache 
+ */
+
+#define isodigit(c) (isdigit(c) && c <= '7')
+int get_word(char **bpp, char *dest, int bufsize)
+{
+	/* return bytes copied, or -1 on error */
+	char *bp = *bpp;
+	int len = 0;
+
+	while (*bp == ' ') bp++;
+
+	if (bp[0] == '\\' && bp[1] == 'x') {
+		/* HEX STRING */
+		bp += 2;
+		while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
+			int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
+			bp++;
+			byte <<= 4;
+			byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
+			*dest++ = byte;
+			bp++;
+			len++;
+		}
+	} else {
+		/* text with \nnn octal quoting */
+		while (*bp != ' ' && *bp && len < bufsize-1) {
+			if (*bp == '\\' &&
+			    isodigit(bp[1]) && (bp[1] <= '3') &&
+			    isodigit(bp[2]) &&
+			    isodigit(bp[3])) {
+				int byte = (*++bp -'0');
+				bp++;
+				byte = (byte << 3) | (*bp++ - '0');
+				byte = (byte << 3) | (*bp++ - '0');
+				*dest++ = byte;
+				len++;
+			} else {
+				*dest++ = *bp++;
+				len++;
+			}
+		}
+		*dest = '\0';
+	}
+
+	*bpp = bp;
+	if (*bp == ' ' || *bp == '\n' || *bp == '\0')
+		return len;
+	return -1;
+}
diff -Nru a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
--- a/net/sunrpc/pmap_clnt.c	Fri Oct 11 21:22:58 2002
+++ b/net/sunrpc/pmap_clnt.c	Fri Oct 11 21:22:58 2002
@@ -243,36 +243,50 @@
 }
 
 static struct rpc_procinfo	pmap_procedures[4] = {
-	{ "pmap_null",
-		(kxdrproc_t) xdr_error,	
-		(kxdrproc_t) xdr_error,	0, 0 },
-	{ "pmap_set",
-		(kxdrproc_t) xdr_encode_mapping,	
-		(kxdrproc_t) xdr_decode_bool, 4, 1 },
-	{ "pmap_unset",
-		(kxdrproc_t) xdr_encode_mapping,	
-		(kxdrproc_t) xdr_decode_bool, 4, 1 },
-	{ "pmap_get",
-		(kxdrproc_t) xdr_encode_mapping,
-		(kxdrproc_t) xdr_decode_port, 4, 1 },
+	{ .p_procname		= "pmap_null",
+	  .p_encode		= (kxdrproc_t) xdr_error,	
+	  .p_decode		= (kxdrproc_t) xdr_error,
+	  .p_bufsiz		= 0,
+	  .p_count		= 0,
+	},
+	{ .p_procname		= "pmap_set",
+	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,	
+	  .p_decode		= (kxdrproc_t) xdr_decode_bool,
+	  .p_bufsiz		= 4,
+	  .p_count		= 1,
+	},
+	{ .p_procname		= "pmap_unset",
+	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,	
+	  .p_decode		= (kxdrproc_t) xdr_decode_bool,
+	  .p_bufsiz		= 4,
+	  .p_count		= 1,
+	},
+	{ .p_procname		= "pmap_get",
+	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,
+	  .p_decode		= (kxdrproc_t) xdr_decode_port,
+	  .p_bufsiz		= 4,
+	  .p_count		= 1,
+	},
 };
 
 static struct rpc_version	pmap_version2 = {
-	2, 4, pmap_procedures
+	.number		= 2,
+	.nrprocs	= 4,
+	.procs		= pmap_procedures
 };
 
 static struct rpc_version *	pmap_version[] = {
 	NULL,
 	NULL,
-	&pmap_version2,
+	&pmap_version2
 };
 
 static struct rpc_stat		pmap_stats;
 
 struct rpc_program	pmap_program = {
-	"portmap",
-	RPC_PMAP_PROGRAM,
-	sizeof(pmap_version)/sizeof(pmap_version[0]),
-	pmap_version,
-	&pmap_stats,
+	.name		= "portmap",
+	.number		= RPC_PMAP_PROGRAM,
+	.nrvers		= sizeof(pmap_version)/sizeof(pmap_version[0]),
+	.version	= pmap_version,
+	.stats		= &pmap_stats,
 };
diff -Nru a/net/sunrpc/stats.c b/net/sunrpc/stats.c
--- a/net/sunrpc/stats.c	Fri Oct 11 21:23:05 2002
+++ b/net/sunrpc/stats.c	Fri Oct 11 21:23:05 2002
@@ -25,7 +25,7 @@
 
 #define RPCDBG_FACILITY	RPCDBG_MISC
 
-static struct proc_dir_entry	*proc_net_rpc = NULL;
+struct proc_dir_entry	*proc_net_rpc = NULL;
 
 /*
  * Get RPC client stats
@@ -183,25 +183,3 @@
 	}
 }
 
-
-static int __init
-init_sunrpc(void)
-{
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
-	rpc_proc_init();
-	return 0;
-}
-
-static void __exit
-cleanup_sunrpc(void)
-{
-#ifdef RPC_DEBUG
-	rpc_unregister_sysctl();
-#endif
-	rpc_proc_exit();
-}
-MODULE_LICENSE("GPL");
-module_init(init_sunrpc);
-module_exit(cleanup_sunrpc);
diff -Nru a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
--- a/net/sunrpc/sunrpc_syms.c	Fri Oct 11 21:23:03 2002
+++ b/net/sunrpc/sunrpc_syms.c	Fri Oct 11 21:23:03 2002
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/uio.h>
 #include <linux/unistd.h>
+#include <linux/init.h>
 
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/clnt.h>
@@ -22,6 +23,7 @@
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/auth.h>
 
+
 /* RPC scheduler */
 EXPORT_SYMBOL(rpc_allocate);
 EXPORT_SYMBOL(rpc_free);
@@ -108,3 +110,33 @@
 EXPORT_SYMBOL(nfsd_debug);
 EXPORT_SYMBOL(nlm_debug);
 #endif
+
+static int __init
+init_sunrpc(void)
+{
+#ifdef RPC_DEBUG
+	rpc_register_sysctl();
+#endif
+#ifdef CONFIG_PROC_FS
+	rpc_proc_init();
+#endif
+	cache_register(&auth_domain_cache);
+	cache_register(&ip_map_cache);
+	return 0;
+}
+
+static void __exit
+cleanup_sunrpc(void)
+{
+	cache_unregister(&auth_domain_cache);
+	cache_unregister(&ip_map_cache);
+#ifdef RPC_DEBUG
+	rpc_unregister_sysctl();
+#endif
+#ifdef CONFIG_PROCFS
+	rpc_proc_exit();
+#endif
+}
+MODULE_LICENSE("GPL");
+module_init(init_sunrpc);
+module_exit(cleanup_sunrpc);
diff -Nru a/net/sunrpc/svc.c b/net/sunrpc/svc.c
--- a/net/sunrpc/svc.c	Fri Oct 11 21:23:04 2002
+++ b/net/sunrpc/svc.c	Fri Oct 11 21:23:04 2002
@@ -262,18 +262,14 @@
 	argp->buf += 5;
 	argp->len -= 5;
 
-	/* Used by nfsd to only allow the NULL procedure for amd. */
-	if (rqstp->rq_auth && !rqstp->rq_client && proc) {
-		auth_stat = rpc_autherr_badcred;
-		goto err_bad_auth;
-	}
-
 	/*
 	 * Decode auth data, and add verifier to reply buffer.
 	 * We do this before anything else in order to get a decent
 	 * auth verifier.
 	 */
-	svc_authenticate(rqstp, &rpc_stat, &auth_stat);
+	if (svc_authenticate(rqstp, &rpc_stat, &auth_stat, proc))
+		/* drop the request, it has probably been deferred */
+		goto dropit;
 
 	if (rpc_stat != rpc_success)
 		goto err_garbage;
@@ -347,10 +343,14 @@
 
 	if (procp->pc_encode == NULL)
 		goto dropit;
-sendit:
+
+ sendit:
+	if (svc_authorise(rqstp))
+		goto dropit;
 	return svc_send(rqstp);
 
-dropit:
+ dropit:
+	svc_authorise(rqstp);	/* doesn't hurt to call this twice */
 	dprintk("svc: svc_process dropit\n");
 	svc_drop(rqstp);
 	return 0;
diff -Nru a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
--- a/net/sunrpc/svcauth.c	Fri Oct 11 21:22:54 2002
+++ b/net/sunrpc/svcauth.c	Fri Oct 11 21:22:54 2002
@@ -13,37 +13,29 @@
 #include <linux/sched.h>
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
-#include <linux/sunrpc/svcauth.h>
 #include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/svcauth.h>
 #include <linux/err.h>
 
 #define RPCDBG_FACILITY	RPCDBG_AUTH
 
-/*
- * Type of authenticator function
- */
-typedef void	(*auth_fn_t)(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
-
-/*
- * Builtin auth flavors
- */
-static void	svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
-static void	svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
 
 /*
  * Table of authenticators
  */
-static auth_fn_t	authtab[RPC_AUTH_MAXFLAVOR] = {
-	svcauth_null,
-	svcauth_unix,
-	NULL,
+extern struct auth_ops svcauth_null;
+extern struct auth_ops svcauth_unix;
+
+static struct auth_ops	*authtab[RPC_AUTH_MAXFLAVOR] = {
+	[0] = &svcauth_null,
+	[1] = &svcauth_unix,
 };
 
-void
-svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
+int
+svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp, int proc)
 {
 	rpc_authflavor_t	flavor;
-	auth_fn_t		func;
+	struct auth_ops		*aops;
 
 	*statp = rpc_success;
 	*authp = rpc_auth_ok;
@@ -52,21 +44,53 @@
 	flavor = ntohl(flavor);
 
 	dprintk("svc: svc_authenticate (%d)\n", flavor);
-	if (flavor >= RPC_AUTH_MAXFLAVOR || !(func = authtab[flavor])) {
+	if (flavor >= RPC_AUTH_MAXFLAVOR || !(aops = authtab[flavor])) {
 		*authp = rpc_autherr_badcred;
-		return;
+		return 0;
+	}
+
+	rqstp->rq_authop = aops;
+	switch (aops->accept(rqstp, authp, proc)) {
+	case SVC_OK:
+		return 0;
+	case SVC_GARBAGE:
+		*statp = rpc_garbage_args;
+		return 0;
+	case SVC_SYSERR:
+		*statp = rpc_system_err;
+		return 0;
+	case SVC_DENIED:
+		return 0;
+	case SVC_DROP:
+		break;
 	}
+	return 1; /* drop the request */
+}
+
+/* A reqeust, which was authenticated, has now executed.
+ * Time to finalise the the credentials and verifier
+ * and release and resources
+ */
+int svc_authorise(struct svc_rqst *rqstp)
+{
+	struct auth_ops *aops = rqstp->rq_authop;
+	int rv = 0;
 
-	rqstp->rq_cred.cr_flavor = flavor;
-	func(rqstp, statp, authp);
+	rqstp->rq_authop = NULL;
+	
+	if (aops) 
+		rv = aops->release(rqstp);
+
+	/* FIXME should I count and release authops */
+	return rv;
 }
 
 int
-svc_auth_register(rpc_authflavor_t flavor, auth_fn_t func)
+svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops)
 {
 	if (flavor >= RPC_AUTH_MAXFLAVOR || authtab[flavor])
 		return -EINVAL;
-	authtab[flavor] = func;
+	authtab[flavor] = aops;
 	return 0;
 }
 
@@ -77,86 +101,91 @@
 		authtab[flavor] = NULL;
 }
 
-static void
-svcauth_null(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
-{
-	struct svc_buf	*argp = &rqstp->rq_argbuf;
-	struct svc_buf	*resp = &rqstp->rq_resbuf;
+/**************************************************
+ * cache for domain name to auth_domain
+ * Entries are only added by flavours which will normally
+ * have a structure that 'inherits' from auth_domain.
+ * e.g. when an IP -> domainname is given to  auth_unix,
+ * and the domain name doesn't exist, it will create a
+ * auth_unix_domain and add it to this hash table.
+ * If it finds the name does exist, but isn't AUTH_UNIX,
+ * it will complain.
+ */
 
-	if ((argp->len -= 3) < 0) {
-		*statp = rpc_garbage_args;
-		return;
-	}
-	if (*(argp->buf)++ != 0) {	/* we already skipped the flavor */
-		dprintk("svc: bad null cred\n");
-		*authp = rpc_autherr_badcred;
-		return;
-	}
-	if (*(argp->buf)++ != RPC_AUTH_NULL || *(argp->buf)++ != 0) {
-		dprintk("svc: bad null verf\n");
-		*authp = rpc_autherr_badverf;
-		return;
+int name_hash(char *name, int size)
+{
+	int hash = 0;
+	while (*name) {
+		hash += *name;
+		name++;
 	}
+	return hash % size;
+}
 
-	/* Signal that mapping to nobody uid/gid is required */
-	rqstp->rq_cred.cr_uid = (uid_t) -1;
-	rqstp->rq_cred.cr_gid = (gid_t) -1;
-	rqstp->rq_cred.cr_groups[0] = NOGROUP;
-
-	/* Put NULL verifier */
-	rqstp->rq_verfed = 1;
-	svc_putu32(resp, RPC_AUTH_NULL);
-	svc_putu32(resp, 0);
-}
-
-static void
-svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
-{
-	struct svc_buf	*argp = &rqstp->rq_argbuf;
-	struct svc_buf	*resp = &rqstp->rq_resbuf;
-	struct svc_cred	*cred = &rqstp->rq_cred;
-	u32		*bufp = argp->buf, slen, i;
-	int		len   = argp->len;
 
-	if ((len -= 3) < 0) {
-		*statp = rpc_garbage_args;
-		return;
-	}
+/*
+ * Auth auth_domain cache is somewhat different to other caches,
+ * largely because the entries are possibly of different types:
+ * each auth flavour has it's own type.
+ * One consequence of this that DefineCacheLookup cannot
+ * allocate a new structure as it cannot know the size.
+ * Notice that the "INIT" code fragment is quite different
+ * from other caches.  When auth_domain_lookup might be
+ * creating a new domain, the new domain is passed in
+ * complete and it is used as-is rather than being copied into
+ * another structure.
+ */
+#define	DN_HASHBITS	6
+#define	DN_HASHMAX	(1<<DN_HASHBITS)
+#define	DN_HASHMASK	(DN_HASHMAX-1)
 
-	bufp++;					/* length */
-	bufp++;					/* time stamp */
-	slen = (ntohl(*bufp++) + 3) >> 2;	/* machname length */
-	if (slen > 64 || (len -= slen + 3) < 0)
-		goto badcred;
-	bufp += slen;				/* skip machname */
-
-	cred->cr_uid = ntohl(*bufp++);		/* uid */
-	cred->cr_gid = ntohl(*bufp++);		/* gid */
-
-	slen = ntohl(*bufp++);			/* gids length */
-	if (slen > 16 || (len -= slen + 2) < 0)
-		goto badcred;
-	for (i = 0; i < NGROUPS && i < slen; i++)
-		cred->cr_groups[i] = ntohl(*bufp++);
-	if (i < NGROUPS)
-		cred->cr_groups[i] = NOGROUP;
-	bufp += (slen - i);
-
-	if (*bufp++ != RPC_AUTH_NULL || *bufp++ != 0) {
-		*authp = rpc_autherr_badverf;
-		return;
-	}
+static struct cache_head	*auth_domain_table[DN_HASHMAX];
+void auth_domain_drop(struct cache_head *item, struct cache_detail *cd)
+{
+	struct auth_domain *dom = container_of(item, struct auth_domain, h);
+	if (cache_put(item,cd))
+		authtab[dom->flavour]->domain_release(dom);
+}
 
-	argp->buf = bufp;
-	argp->len = len;
 
-	/* Put NULL verifier */
-	rqstp->rq_verfed = 1;
-	svc_putu32(resp, RPC_AUTH_NULL);
-	svc_putu32(resp, 0);
+struct cache_detail auth_domain_cache = {
+	.hash_size	= DN_HASHMAX,
+	.hash_table	= auth_domain_table,
+	.name		= "auth.domain",
+	.cache_put	= auth_domain_drop,
+};
+
+void auth_domain_put(struct auth_domain *dom)
+{
+	auth_domain_drop(&dom->h, &auth_domain_cache);
+}
+
+static inline int auth_domain_hash(struct auth_domain *item)
+{
+	return name_hash(item->name, DN_HASHMAX);
+}
+static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item)
+{
+	return strcmp(tmp->name, item->name) == 0;
+}
+DefineCacheLookup(struct auth_domain,
+		  h,
+		  auth_domain_lookup,
+		  (struct auth_domain *item, int set),
+		  /* no setup */,
+		  &auth_domain_cache,
+		  auth_domain_hash(item),
+		  auth_domain_match(tmp, item),
+		  kfree(new); if(!set) return NULL;
+		  new=item; atomic_inc(&new->h.refcnt),
+		  /* no update */
+		  )
 
-	return;
+struct auth_domain *auth_domain_find(char *name)
+{
+	struct auth_domain *rv, ad;
 
-badcred:
-	*authp = rpc_autherr_badcred;
+	ad.name = name;
+	rv = auth_domain_lookup(&ad, 0);
+	return rv;
 }
diff -Nru a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/sunrpc/svcauth_unix.c	Fri Oct 11 21:23:06 2002
@@ -0,0 +1,464 @@
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/sunrpc/types.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/svcauth.h>
+#include <linux/err.h>
+
+#define RPCDBG_FACILITY	RPCDBG_AUTH
+
+
+/*
+ * AUTHUNIX and AUTHNULL credentials are both handled here.
+ * AUTHNULL is treated just like AUTHUNIX except that the uid/gid
+ * are always nobody (-2).  i.e. we do the same IP address checks for
+ * AUTHNULL as for AUTHUNIX, and that is done here.
+ */
+
+
+char *strdup(char *s)
+{
+	char *rv = kmalloc(strlen(s)+1, GFP_KERNEL);
+	if (rv)
+		strcpy(rv, s);
+	return rv;
+}
+
+struct unix_domain {
+	struct auth_domain	h;
+	int	addr_changes;
+	/* other stuff later */
+};
+
+struct auth_domain *unix_domain_find(char *name)
+{
+	struct auth_domain *rv, ud;
+	struct unix_domain *new;
+
+	ud.name = name;
+	
+	rv = auth_domain_lookup(&ud, 0);
+
+ foundit:
+	if (rv && rv->flavour != RPC_AUTH_UNIX) {
+		auth_domain_put(rv);
+		return NULL;
+	}
+	if (rv)
+		return rv;
+
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	cache_init(&new->h.h);
+	atomic_inc(&new->h.h.refcnt);
+	new->h.name = strdup(name);
+	new->h.flavour = RPC_AUTH_UNIX;
+	new->addr_changes = 0;
+	new->h.h.expiry_time = NEVER;
+	new->h.h.flags = 0;
+
+	rv = auth_domain_lookup(&new->h, 2);
+	if (rv == &new->h) {
+		if (atomic_dec_and_test(&new->h.h.refcnt)) BUG();
+	} else {
+		auth_domain_put(&new->h);
+		goto foundit;
+	}
+
+	return rv;
+}
+
+
+/**************************************************
+ * cache for IP address to unix_domain
+ * as needed by AUTH_UNIX
+ */
+#define	IP_HASHBITS	8
+#define	IP_HASHMAX	(1<<IP_HASHBITS)
+#define	IP_HASHMASK	(IP_HASHMAX-1)
+
+struct ip_map {
+	struct cache_head	h;
+	char			*m_class; /* e.g. "nfsd" */
+	struct in_addr		m_addr;
+	struct unix_domain	*m_client;
+	int			m_add_change;
+};
+static struct cache_head	*ip_table[IP_HASHMAX];
+
+void ip_map_put(struct cache_head *item, struct cache_detail *cd)
+{
+	struct ip_map *im = container_of(item, struct ip_map,h);
+	if (cache_put(item, cd)) {
+		auth_domain_put(&im->m_client->h);
+		kfree(im);
+	}
+}
+
+static inline int ip_map_hash(struct ip_map *item)
+{
+	return (name_hash(item->m_class, IP_HASHMAX) ^ item->m_addr.s_addr) & IP_HASHMASK;
+}
+static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp)
+{
+	return strcmp(tmp->m_class, item->m_class) == 0
+		&& tmp->m_addr.s_addr == item->m_addr.s_addr;
+}
+static inline void ip_map_init(struct ip_map *new, struct ip_map *item)
+{
+	new->m_class = strdup(item->m_class);
+	new->m_addr.s_addr = item->m_addr.s_addr;
+}
+static inline void ip_map_update(struct ip_map *new, struct ip_map *item)
+{
+	cache_get(&item->m_client->h.h);
+	new->m_client = item->m_client;
+	new->m_add_change = item->m_add_change;
+}
+
+static void ip_map_request(struct cache_detail *cd,
+				  struct cache_head *h,
+				  char **bpp, int *blen)
+{
+	char text_addr[20];
+	struct ip_map *im = container_of(h, struct ip_map, h);
+	__u32 addr = im->m_addr.s_addr;
+	
+	snprintf(text_addr, 20, "%u.%u.%u.%u",
+		 ntohl(addr) >> 24 & 0xff,
+		 ntohl(addr) >> 16 & 0xff,
+		 ntohl(addr) >>  8 & 0xff,
+		 ntohl(addr) >>  0 & 0xff);
+
+	add_word(bpp, blen, im->m_class);
+	add_word(bpp, blen, text_addr);
+	(*bpp)[-1] = '\n';
+}
+
+static struct ip_map *ip_map_lookup(struct ip_map *, int);
+static int ip_map_parse(struct cache_detail *cd,
+			  char *mesg, int mlen)
+{
+	/* class ipaddress [domainname] */
+	char class[50], buf[50];
+	int len;
+	int b1,b2,b3,b4;
+	char c;
+	struct ip_map ipm, *ipmp;
+	struct auth_domain *dom;
+	time_t expiry;
+
+	if (mesg[mlen-1] != '\n')
+		return -EINVAL;
+	mesg[mlen-1] = 0;
+
+	/* class */
+	len = get_word(&mesg, class, 50);
+	if (len <= 0) return -EINVAL;
+
+	/* ip address */
+	len = get_word(&mesg, buf, 50);
+	if (len <= 0) return -EINVAL;
+
+	if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)
+		return -EINVAL;
+	
+	expiry = get_expiry(&mesg);
+	if (expiry ==0)
+		return -EINVAL;
+
+	/* domainname, or empty for NEGATIVE */
+	len = get_word(&mesg, buf, 50);
+	if (len < 0) return -EINVAL;
+
+	if (len) {
+		dom = unix_domain_find(buf);
+		if (dom == NULL)
+			return -ENOENT;
+	} else
+		dom = NULL;
+
+	ipm.m_class = class;
+	ipm.m_addr.s_addr =
+		htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
+	ipm.h.flags = 0;
+	if (dom)
+		ipm.m_client = container_of(dom, struct unix_domain, h);
+	else
+		set_bit(CACHE_NEGATIVE, &ipm.h.flags);
+	ipm.h.expiry_time = expiry;
+	ipm.m_add_change = ipm.m_client->addr_changes;
+
+	ipmp = ip_map_lookup(&ipm, 1);
+	if (ipmp)
+		ip_map_put(&ipmp->h, &ip_map_cache);
+	if (dom)
+		auth_domain_put(dom);
+	if (!ipmp)
+		return -ENOMEM;
+
+	return 0;
+}
+
+struct cache_detail ip_map_cache = {
+	.hash_size	= IP_HASHMAX,
+	.hash_table	= ip_table,
+	.name		= "auth.unix.ip",
+	.cache_put	= ip_map_put,
+	.cache_request	= ip_map_request,
+	.cache_parse	= ip_map_parse,
+};
+
+static DefineSimpleCacheLookup(ip_map)
+
+
+int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
+{
+	struct unix_domain *udom;
+	struct ip_map ip, *ipmp;
+
+	if (dom->flavour != RPC_AUTH_UNIX)
+		return -EINVAL;
+	udom = container_of(dom, struct unix_domain, h);
+	ip.m_class = "nfsd";
+	ip.m_addr = addr;
+	ip.m_client = udom;
+	ip.m_add_change = udom->addr_changes+1;
+	ip.h.flags = 0;
+	ip.h.expiry_time = NEVER;
+	
+	ipmp = ip_map_lookup(&ip, 1);
+	if (ipmp) {
+		ip_map_put(&ipmp->h, &ip_map_cache);
+		return 0;
+	} else
+		return -ENOMEM;
+}
+
+int auth_unix_forget_old(struct auth_domain *dom)
+{
+	struct unix_domain *udom;
+	
+	if (dom->flavour != RPC_AUTH_UNIX)
+		return -EINVAL;
+	udom = container_of(dom, struct unix_domain, h);
+	udom->addr_changes++;
+	return 0;
+}
+
+struct auth_domain *auth_unix_lookup(struct in_addr addr)
+{
+	struct ip_map key, *ipm;
+	struct auth_domain *rv;
+
+	key.m_class = "nfsd";
+	key.m_addr = addr;
+
+	ipm = ip_map_lookup(&key, 0);
+
+	if (!ipm)
+		return NULL;
+
+	if (test_bit(CACHE_VALID, &ipm->h.flags) &&
+	    (ipm->m_client->addr_changes - ipm->m_add_change) >0)
+		set_bit(CACHE_NEGATIVE, &ipm->h.flags);
+
+	if (!test_bit(CACHE_VALID, &ipm->h.flags))
+		rv = NULL;
+	else if (test_bit(CACHE_NEGATIVE, &ipm->h.flags))
+		rv = NULL;
+	else {
+		rv = &ipm->m_client->h;
+		cache_get(&rv->h);
+	}
+	if (ipm) ip_map_put(&ipm->h, &ip_map_cache);
+	return rv;
+}
+
+void svcauth_unix_purge(void)
+{
+	cache_purge(&ip_map_cache);
+	cache_purge(&auth_domain_cache);
+}
+
+
+static int
+svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
+{
+	struct svc_buf	*argp = &rqstp->rq_argbuf;
+	struct svc_buf	*resp = &rqstp->rq_resbuf;
+	int		rv=0;
+	struct ip_map key, *ipm;
+
+	if ((argp->len -= 3) < 0) {
+		return SVC_GARBAGE;
+	}
+	if (*(argp->buf)++ != 0) {	/* we already skipped the flavor */
+		dprintk("svc: bad null cred\n");
+		*authp = rpc_autherr_badcred;
+		return SVC_DENIED;
+	}
+	if (*(argp->buf)++ != RPC_AUTH_NULL || *(argp->buf)++ != 0) {
+		dprintk("svc: bad null verf\n");
+		*authp = rpc_autherr_badverf;
+		return SVC_DENIED;
+	}
+
+	/* Signal that mapping to nobody uid/gid is required */
+	rqstp->rq_cred.cr_uid = (uid_t) -1;
+	rqstp->rq_cred.cr_gid = (gid_t) -1;
+	rqstp->rq_cred.cr_groups[0] = NOGROUP;
+
+	/* Put NULL verifier */
+	svc_putu32(resp, RPC_AUTH_NULL);
+	svc_putu32(resp, 0);
+
+	key.m_class = rqstp->rq_server->sv_program->pg_class;
+	key.m_addr = rqstp->rq_addr.sin_addr;
+
+	ipm = ip_map_lookup(&key, 0);
+
+	rqstp->rq_client = NULL;
+
+	if (ipm)
+		switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
+		case -EAGAIN:
+			rv = SVC_DROP;
+			break;
+		case -ENOENT:
+			rv = SVC_OK; /* rq_client is NULL */
+			break;
+		case 0:
+			rqstp->rq_client = &ipm->m_client->h;
+			cache_get(&rqstp->rq_client->h);
+			ip_map_put(&ipm->h, &ip_map_cache);
+			rv = SVC_OK;
+			break;
+		default: BUG();
+		}
+	else rv = SVC_DROP;
+
+	if (rqstp->rq_client == NULL && proc != 0)
+		*authp = rpc_autherr_badcred;
+
+	return rv;
+}
+
+static int
+svcauth_null_release(struct svc_rqst *rqstp)
+{
+	if (rqstp->rq_client)
+		auth_domain_put(rqstp->rq_client);
+	rqstp->rq_client = NULL;
+
+	return 0; /* don't drop */
+}
+
+
+struct auth_ops svcauth_null = {
+	.name		= "null",
+	.flavour	= RPC_AUTH_NULL,
+	.accept 	= svcauth_null_accept,
+	.release	= svcauth_null_release,
+};
+
+
+int
+svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp, int proc)
+{
+	struct svc_buf	*argp = &rqstp->rq_argbuf;
+	struct svc_buf	*resp = &rqstp->rq_resbuf;
+	struct svc_cred	*cred = &rqstp->rq_cred;
+	u32		*bufp = argp->buf, slen, i;
+	int		len   = argp->len;
+	int		rv=0;
+	struct ip_map key, *ipm;
+
+	if ((len -= 3) < 0)
+		return SVC_GARBAGE;
+
+	bufp++;					/* length */
+	bufp++;					/* time stamp */
+	slen = XDR_QUADLEN(ntohl(*bufp++));	/* machname length */
+	if (slen > 64 || (len -= slen + 3) < 0)
+		goto badcred;
+	bufp += slen;				/* skip machname */
+
+	cred->cr_uid = ntohl(*bufp++);		/* uid */
+	cred->cr_gid = ntohl(*bufp++);		/* gid */
+
+	slen = ntohl(*bufp++);			/* gids length */
+	if (slen > 16 || (len -= slen + 2) < 0)
+		goto badcred;
+	for (i = 0; i < NGROUPS && i < slen; i++)
+		cred->cr_groups[i] = ntohl(*bufp++);
+	if (i < NGROUPS)
+		cred->cr_groups[i] = NOGROUP;
+	bufp += (slen - i);
+
+	if (*bufp++ != RPC_AUTH_NULL || *bufp++ != 0) {
+		*authp = rpc_autherr_badverf;
+		return SVC_DENIED;
+	}
+
+	argp->buf = bufp;
+	argp->len = len;
+
+	/* Put NULL verifier */
+	svc_putu32(resp, RPC_AUTH_NULL);
+	svc_putu32(resp, 0);
+
+	key.m_class = rqstp->rq_server->sv_program->pg_class;
+	key.m_addr = rqstp->rq_addr.sin_addr;
+
+	ipm = ip_map_lookup(&key, 0);
+
+	rqstp->rq_client = NULL;
+
+	if (ipm)
+		switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
+		case -EAGAIN:
+			rv = SVC_DROP;
+			break;
+		case -ENOENT:
+			rv = SVC_OK; /* rq_client is NULL */
+			break;
+		case 0:
+			rqstp->rq_client = &ipm->m_client->h;
+			cache_get(&rqstp->rq_client->h);
+			ip_map_put(&ipm->h, &ip_map_cache);
+			rv = SVC_OK;
+			break;
+		default: BUG();
+		}
+	else rv = SVC_DROP;
+
+	if (rqstp->rq_client == NULL && proc != 0)
+		goto badcred;
+	return rv;
+
+badcred:
+	*authp = rpc_autherr_badcred;
+	return SVC_DENIED;
+}
+
+int
+svcauth_unix_release(struct svc_rqst *rqstp)
+{
+	/* Verifier (such as it is) is already in place.
+	 */
+	if (rqstp->rq_client)
+		auth_domain_put(rqstp->rq_client);
+	rqstp->rq_client = NULL;
+
+	return 0;
+}
+
+
+struct auth_ops svcauth_unix = {
+	.name		= "unix",
+	.flavour	= RPC_AUTH_UNIX,
+	.accept 	= svcauth_unix_accept,
+	.release	= svcauth_unix_release,
+};
+
diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c	Fri Oct 11 21:22:53 2002
+++ b/net/sunrpc/svcsock.c	Fri Oct 11 21:22:53 2002
@@ -69,6 +69,9 @@
 static int		svc_udp_recvfrom(struct svc_rqst *);
 static int		svc_udp_sendto(struct svc_rqst *);
 
+static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
+static int svc_deferred_recv(struct svc_rqst *rqstp);
+static struct cache_deferred_req *svc_defer(struct cache_req *req);
 
 /*
  * Queue up an idle server thread.  Must have serv->sv_lock held.
@@ -98,13 +101,18 @@
 svc_release_skb(struct svc_rqst *rqstp)
 {
 	struct sk_buff *skb = rqstp->rq_skbuff;
+	struct svc_deferred_req *dr = rqstp->rq_deferred;
 
-	if (!skb)
-		return;
-	rqstp->rq_skbuff = NULL;
+	if (skb) {
+		rqstp->rq_skbuff = NULL;
 
-	dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
-	skb_free_datagram(rqstp->rq_sock->sk_sk, skb);
+		dprintk("svc: service %p, releasing skb %p\n", rqstp, skb);
+		skb_free_datagram(rqstp->rq_sock->sk_sk, skb);
+	}
+	if (dr) {
+		rqstp->rq_deferred = NULL;
+		kfree(dr);
+	}
 }
 
 /*
@@ -119,7 +127,7 @@
 	struct svc_rqst	*rqstp;
 
 	if (!(svsk->sk_flags &
-	      ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)) ))
+	      ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) ))
 		return;
 
 	spin_lock_bh(&serv->sv_lock);
@@ -491,6 +499,9 @@
 				(serv->sv_nrthreads+3) * serv->sv_bufsz,
 				(serv->sv_nrthreads+3) * serv->sv_bufsz);
 
+	if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk)))
+		return svc_deferred_recv(rqstp);
+
 	clear_bit(SK_DATA, &svsk->sk_flags);
 	while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
 		svc_sock_received(svsk);
@@ -526,6 +537,7 @@
 	rqstp->rq_argbuf.base = data;
 	rqstp->rq_argbuf.buf  = data;
 	rqstp->rq_argbuf.len  = (len >> 2);
+	rqstp->rq_argbuf.buflen = (len >> 2);
 	/* rqstp->rq_resbuf      = rqstp->rq_defbuf; */
 	rqstp->rq_prot        = IPPROTO_UDP;
 
@@ -781,6 +793,9 @@
 		test_bit(SK_CONN, &svsk->sk_flags),
 		test_bit(SK_CLOSE, &svsk->sk_flags));
 
+	if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk)))
+		return svc_deferred_recv(rqstp);
+
 	if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
 		svc_delete_socket(svsk);
 		return 0;
@@ -867,14 +882,17 @@
 
 	dprintk("svc: TCP complete record (%d bytes)\n", len);
 
-	/* Position reply write pointer immediately after
-	 * record length */
-	rqstp->rq_resbuf.buf += 1;
+	/* Position reply write pointer immediately args,
+	 * allowing for record length */
+	rqstp->rq_resbuf.base = rqstp->rq_argbuf.base + (len>>2);
+	rqstp->rq_resbuf.buf  = rqstp->rq_resbuf.base + 1;
 	rqstp->rq_resbuf.len  = 1;
+	rqstp->rq_resbuf.buflen= rqstp->rq_argbuf.buflen - (len>>2) - 1;
 
 	rqstp->rq_skbuff      = 0;
 	rqstp->rq_argbuf.buf += 1;
 	rqstp->rq_argbuf.len  = (len >> 2);
+	rqstp->rq_argbuf.buflen = (len >> 2);
 	rqstp->rq_prot	      = IPPROTO_TCP;
 
 	/* Reset TCP read info */
@@ -1089,7 +1107,7 @@
 
 	rqstp->rq_secure  = ntohs(rqstp->rq_addr.sin_port) < 1024;
 	rqstp->rq_userset = 0;
-	rqstp->rq_verfed  = 0;
+	rqstp->rq_chandle.defer = svc_defer;
 
 	svc_getu32(&rqstp->rq_argbuf, rqstp->rq_xid);
 	svc_putu32(&rqstp->rq_resbuf, rqstp->rq_xid);
@@ -1165,6 +1183,7 @@
 	svsk->sk_owspace = inet->write_space;
 	svsk->sk_server = serv;
 	svsk->sk_lastrecv = CURRENT_TIME;
+	INIT_LIST_HEAD(&svsk->sk_deferred);
 
 	/* Initialize the socket */
 	if (sock->type == SOCK_DGRAM)
@@ -1305,3 +1324,97 @@
 	return svc_create_socket(serv, protocol, &sin);
 }
 
+/*
+ * Handle defer and revisit of requests 
+ */
+
+static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
+{
+	struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle);
+	struct svc_serv *serv = dr->serv;
+	struct svc_sock *svsk;
+
+	if (too_many) {
+		svc_sock_put(dr->svsk);
+		kfree(dr);
+		return;
+	}
+	dprintk("revisit queued\n");
+	svsk = dr->svsk;
+	dr->svsk = NULL;
+	spin_lock(&serv->sv_lock);
+	list_add(&dr->handle.recent, &svsk->sk_deferred);
+	spin_unlock(&serv->sv_lock);
+	set_bit(SK_DEFERRED, &svsk->sk_flags);
+	svc_sock_enqueue(svsk);
+	svc_sock_put(svsk);
+}
+
+static struct cache_deferred_req *
+svc_defer(struct cache_req *req)
+{
+	struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle);
+	int size = sizeof(struct svc_deferred_req) + (rqstp->rq_argbuf.buflen << 2);
+	struct svc_deferred_req *dr;
+
+	if (rqstp->rq_deferred) {
+		dr = rqstp->rq_deferred;
+		rqstp->rq_deferred = NULL;
+	} else {
+		/* FIXME maybe discard if size too large */
+		dr = kmalloc(size<<2, GFP_KERNEL);
+		if (dr == NULL)
+			return NULL;
+
+		dr->serv = rqstp->rq_server;
+		dr->prot = rqstp->rq_prot;
+		dr->addr = rqstp->rq_addr;
+		dr->argslen = rqstp->rq_argbuf.buflen;
+		memcpy(dr->args, rqstp->rq_argbuf.base, dr->argslen<<2);
+	}
+	spin_lock(&rqstp->rq_server->sv_lock);
+	rqstp->rq_sock->sk_inuse++;
+	dr->svsk = rqstp->rq_sock;
+	spin_unlock(&rqstp->rq_server->sv_lock);
+
+	dr->handle.revisit = svc_revisit;
+	return &dr->handle;
+}
+
+/*
+ * recv data from a defered request into an active one
+ */
+static int svc_deferred_recv(struct svc_rqst *rqstp)
+{
+	struct svc_deferred_req *dr = rqstp->rq_deferred;
+
+	rqstp->rq_argbuf.base = dr->args;
+	rqstp->rq_argbuf.buf  = dr->args;
+	rqstp->rq_argbuf.len  = dr->argslen;
+	rqstp->rq_argbuf.buflen = dr->argslen;
+	rqstp->rq_prot        = dr->prot;
+	rqstp->rq_addr        = dr->addr;
+	return dr->argslen<<2;
+}
+
+
+static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
+{
+	struct svc_deferred_req *dr = NULL;
+	struct svc_serv	*serv = svsk->sk_server;
+	
+	if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
+		return NULL;
+	spin_lock(&serv->sv_lock);
+	clear_bit(SK_DEFERRED, &svsk->sk_flags);
+	if (!list_empty(&svsk->sk_deferred)) {
+		dr = list_entry(svsk->sk_deferred.next,
+				struct svc_deferred_req,
+				handle.recent);
+		list_del_init(&dr->handle.recent);
+		set_bit(SK_DEFERRED, &svsk->sk_flags);
+	}
+	spin_unlock(&serv->sv_lock);
+	svc_sock_received(svsk);
+	return dr;
+}
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Fri Oct 11 21:23:01 2002
+++ b/net/sunrpc/xprt.c	Fri Oct 11 21:23:01 2002
@@ -89,7 +89,7 @@
 static void	xprt_conn_status(struct rpc_task *task);
 static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap,
 						struct rpc_timeout *to);
-static struct socket *xprt_create_socket(int, struct rpc_timeout *);
+static struct socket *xprt_create_socket(int, struct rpc_timeout *, int);
 static void	xprt_bind_socket(struct rpc_xprt *, struct socket *);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
@@ -442,7 +442,7 @@
 	 * Start by resetting any existing state.
 	 */
 	xprt_close(xprt);
-	if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) {
+	if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout, xprt->resvport))) {
 		/* couldn't create socket or bind to reserved port;
 		 * this is likely a permanent error, so cause an abort */
 		task->tk_status = -EIO;
@@ -1446,6 +1446,8 @@
 		sk->no_check = UDP_CSUM_NORCV;
 		xprt_set_connected(xprt);
 	} else {
+		struct tcp_opt *tp = tcp_sk(sk);
+		tp->nonagle = 1;	/* disable Nagle's algorithm */
 		sk->data_ready = tcp_data_ready;
 		sk->state_change = tcp_state_change;
 		xprt_clear_connected(xprt);
@@ -1490,7 +1492,7 @@
  * and connect stream sockets.
  */
 static struct socket *
-xprt_create_socket(int proto, struct rpc_timeout *to)
+xprt_create_socket(int proto, struct rpc_timeout *to, int resvport)
 {
 	struct socket	*sock;
 	int		type, err;
@@ -1506,7 +1508,7 @@
 	}
 
 	/* If the caller has the capability, bind to a reserved port */
-	if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0) {
+	if (resvport && xprt_bindresvport(sock) < 0) {
 		printk("RPC: can't bind to reserved port.\n");
 		goto failed;
 	}
@@ -1528,29 +1530,25 @@
 
 	xprt = xprt_setup(proto, sap, to);
 	if (!xprt)
-		goto out;
+		goto out_bad;
 
+	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
 	if (!xprt->stream) {
-		struct socket *sock = xprt_create_socket(proto, to);
-		if (sock)
-			xprt_bind_socket(xprt, sock);
-		else {
-			rpc_free(xprt);
-			xprt = NULL;
-		}
-	} else
-		/*
-		 * Don't allow a TCP service user unless they have
-		 * enough capability to bind a reserved port.
-		 */
-		if (!capable(CAP_NET_BIND_SERVICE)) {
-			rpc_free(xprt);
-			xprt = NULL;
-		}
+		struct socket *sock;
+
+		sock = xprt_create_socket(proto, to, xprt->resvport);
+		if (!sock)
+			goto out_bad;
+		xprt_bind_socket(xprt, sock);
+	}
 
- out:
 	dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
 	return xprt;
+ out_bad:
+	dprintk("RPC:      xprt_create_proto failed\n");
+	if (xprt)
+		rpc_free(xprt);
+	return NULL;
 }
 
 /*
diff -Nru a/net/x25/x25_dev.c b/net/x25/x25_dev.c
--- a/net/x25/x25_dev.c	Fri Oct 11 21:22:57 2002
+++ b/net/x25/x25_dev.c	Fri Oct 11 21:22:57 2002
@@ -70,7 +70,7 @@
 
 		skb->h.raw = skb->data;
 		bh_lock_sock(sk);
-		if (!sk->lock.users) {
+		if (!sock_owned_by_user(sk)) {
 			queued = x25_process_rx_frame(sk, skb);
 		} else {
 			sk_add_backlog(sk, skb);
diff -Nru a/net/x25/x25_timer.c b/net/x25/x25_timer.c
--- a/net/x25/x25_timer.c	Fri Oct 11 21:22:53 2002
+++ b/net/x25/x25_timer.c	Fri Oct 11 21:22:53 2002
@@ -131,7 +131,7 @@
 	struct sock *sk = (struct sock *)param;
 
         bh_lock_sock(sk);
-        if (sk->lock.users) /* can currently only occur in state 3 */ 
+        if (sock_owned_by_user(sk)) /* can currently only occur in state 3 */ 
 		goto restart_heartbeat;
 
 	switch (x25_sk(sk)->state) {
@@ -193,7 +193,7 @@
 	struct sock *sk = (struct sock *)param;
 
 	bh_lock_sock(sk);
-	if (sk->lock.users) { /* can currently only occur in state 3 */
+	if (sock_owned_by_user(sk)) { /* can currently only occur in state 3 */
 		if (x25_sk(sk)->state == X25_STATE_3)
 			x25_start_t2timer(sk);
 	} else
diff -Nru a/scripts/Menuconfig b/scripts/Menuconfig
--- a/scripts/Menuconfig	Fri Oct 11 21:22:54 2002
+++ b/scripts/Menuconfig	Fri Oct 11 21:22:54 2002
@@ -73,6 +73,10 @@
 # - Support for multiple conditions in dep_tristate().
 # - Implemented new functions: define_tristate(), define_int(), define_hex(),
 #   define_string(), dep_bool().
+#
+# 12 November 2001, Keith Owens <kaos@ocs.com.au>
+# Escape double quotes on eval so the quotes are still there on the second
+# evaluation, required to handle strings with special characters.
 # 
 
 
@@ -105,11 +109,11 @@
     eval x=\$$1
     if [ -z "$x" ]; then
 	eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" arch/$ARCH/defconfig`
-	eval x=\${$1:-"$2"}
+	eval x=\${$1:-\"$2\"}
 	eval $1=$x
 	eval INFO_$1="' (NEW)'"
     fi
-    eval info="\$INFO_$1"
+    eval info=\"\$INFO_$1\"
 }
 
 #
@@ -151,7 +155,7 @@
 }
 
 function define_string () {
-	eval $1="$2"
+	eval $1=\"$2\"
 }
 
 #
@@ -333,7 +337,7 @@
 
 	while [ -n "$2" ]
 	do
-		if eval [ "_\$$2" = "_y" ]
+		if eval [ \"_\$$2\" = \"_y\" ]
 		then
 			current=$1
 			break
@@ -543,9 +547,9 @@
 			# we avoid them:
 			if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
 			then
-				eval $2="$answer"
+				eval $2=\"$answer\"
 			else
-				eval $2="$3"
+				eval $2=\"$3\"
 				echo -en "\007"
 				${DIALOG} --backtitle "$backtitle" \
 					--infobox "You have made an invalid entry." 3 43
@@ -576,9 +580,9 @@
 
 			if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null
 			then
-				eval $2="$answer"
+				eval $2=\"$answer\"
 			else
-				eval $2="$3"
+				eval $2=\"$3\"
 				echo -en "\007"
 				${DIALOG} --backtitle "$backtitle" \
 					--infobox "You have made an invalid entry." 3 43
@@ -676,9 +680,9 @@
 	do
 		if [ "$2" = "$choice" ]
 		then
-			eval $2="y"
+			eval $2=\"y\"
 		else
-			eval $2="n"
+			eval $2=\"n\"
 		fi
 		
 		shift ; shift
@@ -941,9 +945,9 @@
 
 			[ "_" = "_$ALT_CONFIG" ] && break
 
-			if eval [ -r "$ALT_CONFIG" ]
+			if eval [ -r \"$ALT_CONFIG\" ]
 			then
-				eval load_config_file "$ALT_CONFIG"
+				eval load_config_file \"$ALT_CONFIG\"
 				break
 			else
 				echo -ne "\007"
@@ -1067,12 +1071,12 @@
 	#
 	function bool () {
 		set_x_info "$2" "n"
-		eval define_bool "$2" "$x"
+		eval define_bool \"$2\" \"$x\"
 	}
 
 	function tristate () {
 		set_x_info "$2" "n"
-		eval define_tristate "$2" "$x"
+		eval define_tristate \"$2\" \"$x\"
 	}
 
 	function dep_tristate () {
@@ -1138,19 +1142,19 @@
 	}
 
 	function define_hex () {
-		eval $1="$2"
+		eval $1=\"$2\"
                	echo "$1=$2"			>>$CONFIG
 		echo "#define $1 0x${2##*[x,X]}"	>>$CONFIG_H
 	}
 
 	function define_int () {
-		eval $1="$2"
+		eval $1=\"$2\"
 		echo "$1=$2" 			>>$CONFIG
 		echo "#define $1 ($2)"		>>$CONFIG_H
 	}
 
 	function define_string () {
-		eval $1="$2"
+		eval $1=\"$2\"
 		echo "$1=\"$2\""		>>$CONFIG
 		echo "#define $1 \"$2\""	>>$CONFIG_H
 	}
@@ -1160,7 +1164,7 @@
 	}
 
 	function define_tristate () {
-		eval $1="$2"
+		eval $1=\"$2\"
 
    		case "$2" in
          	y)
@@ -1199,7 +1203,7 @@
 		set -- $choices
 		while [ -n "$2" ]
 		do
-			if eval [ "_\$$2" = "_y" ]
+			if eval [ \"_\$$2\" = \"_y\" ]
 			then
 				current=$1
 				break
diff -Nru a/scripts/fixdep.c b/scripts/fixdep.c
--- a/scripts/fixdep.c	Fri Oct 11 21:22:58 2002
+++ b/scripts/fixdep.c	Fri Oct 11 21:22:58 2002
@@ -61,7 +61,7 @@
  *
  * It is invoked as
  *
- *   fixdep <depfile> <target> <topdir> <cmdline>
+ *   fixdep <depfile> <target> <cmdline>
  *
  * and will read the dependency file <depfile>
  *
@@ -111,7 +111,6 @@
 #define INT_NFIG ntohl(0x4e464947)
 #define INT_FIG_ ntohl(0x4649475f)
 
-char *topdir;
 char *target;
 char *depfile;
 char *cmdline;
@@ -119,7 +118,7 @@
 void usage(void)
 
 {
-	fprintf(stderr, "Usage: fixdep <depfile> <target> <topdir> <cmdline>\n");
+	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
 	exit(1);
 }
 
@@ -364,13 +363,12 @@
 {
 	traps();
 
-	if (argc != 5)
+	if (argc != 4)
 		usage();
 		
 	depfile = argv[1];
 	target = argv[2];
-	topdir = argv[3];
-	cmdline = argv[4];
+	cmdline = argv[3];
 
 	print_cmdline();
 	print_deps();
diff -Nru a/scripts/mkspec b/scripts/mkspec
--- a/scripts/mkspec	Fri Oct 11 21:22:51 2002
+++ b/scripts/mkspec	Fri Oct 11 21:22:51 2002
@@ -6,6 +6,16 @@
 #	The only gothic bit here is redefining install_post to avoid 
 #	stripping the symbols from files in the kernel which we want
 #
+#	Patched for non-x86 by Opencon (L) 2002 <opencon@rio.skydome.net>
+#
+# That's the voodoo to see if it's a x86.
+ISX86=`arch | grep -ie i.86`
+if [ ! -z $ISX86 ]; then
+	PC=1
+else
+	PC=0
+fi
+# starting to output the spec
 if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
 	PROVIDES=kernel-drm
 fi
@@ -35,12 +45,24 @@
 echo "%setup -q"
 echo ""
 echo "%build"
-echo "make oldconfig dep clean bzImage modules"
+# This is the first 'disagreement' between x86 and other archs.
+if [ $PC = 1 ]; then 
+	echo "make oldconfig dep clean bzImage modules"
+else
+	echo "make oldconfig dep clean vmlinux modules"
+fi
+# Back on track
 echo ""
 echo "%install"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib $RPM_BUILD_ROOT/lib/modules'
 echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make modules_install'
-echo 'cp arch/i386/boot/bzImage $RPM_BUILD_ROOT'"/boot/vmlinuz-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+# And that's the second
+if [ $PC = 1 ]; then
+	echo 'cp arch/i386/boot/bzImage $RPM_BUILD_ROOT'"/boot/vmlinuz-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+else
+	echo 'cp vmlinux $RPM_BUILD_ROOT'"/boot/vmlinux-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+fi
+# Back on track, again
 echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
 echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
 echo ""
diff -Nru a/security/capability.c b/security/capability.c
--- a/security/capability.c	Fri Oct 11 21:22:55 2002
+++ b/security/capability.c	Fri Oct 11 21:22:55 2002
@@ -679,6 +679,41 @@
 	return;
 }
 
+static int cap_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
+{
+	return 0;
+}
+
+static int cap_msg_queue_alloc_security (struct msg_queue *msq)
+{
+	return 0;
+}
+
+static void cap_msg_queue_free_security (struct msg_queue *msq)
+{
+	return;
+}
+
+static int cap_shm_alloc_security (struct shmid_kernel *shp)
+{
+	return 0;
+}
+
+static void cap_shm_free_security (struct shmid_kernel *shp)
+{
+	return;
+}
+
+static int cap_sem_alloc_security (struct sem_array *sma)
+{
+	return 0;
+}
+
+static void cap_sem_free_security (struct sem_array *sma)
+{
+	return;
+}
+
 static int cap_register (const char *name, struct security_operations *ops)
 {
 	return -EINVAL;
@@ -781,6 +816,17 @@
 	.task_prctl =			cap_task_prctl,
 	.task_kmod_set_label =		cap_task_kmod_set_label,
 	.task_reparent_to_init =	cap_task_reparent_to_init,
+
+	.ipc_permission =		cap_ipc_permission,
+
+	.msg_queue_alloc_security =	cap_msg_queue_alloc_security,
+	.msg_queue_free_security =	cap_msg_queue_free_security,
+	
+	.shm_alloc_security =		cap_shm_alloc_security,
+	.shm_free_security =		cap_shm_free_security,
+	
+	.sem_alloc_security =		cap_sem_alloc_security,
+	.sem_free_security =		cap_sem_free_security,
 
 	.register_security =		cap_register,
 	.unregister_security =		cap_unregister,
diff -Nru a/security/dummy.c b/security/dummy.c
--- a/security/dummy.c	Fri Oct 11 21:22:54 2002
+++ b/security/dummy.c	Fri Oct 11 21:22:54 2002
@@ -493,6 +493,42 @@
 	return;
 }
 
+static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
+{
+	return 0;
+}
+
+
+static int dummy_msg_queue_alloc_security (struct msg_queue *msq)
+{
+	return 0;
+}
+
+static void dummy_msg_queue_free_security (struct msg_queue *msq)
+{
+	return;
+}
+
+static int dummy_shm_alloc_security (struct shmid_kernel *shp)
+{
+	return 0;
+}
+
+static void dummy_shm_free_security (struct shmid_kernel *shp)
+{
+	return;
+}
+
+static int dummy_sem_alloc_security (struct sem_array *sma)
+{
+	return 0;
+}
+
+static void dummy_sem_free_security (struct sem_array *sma)
+{
+	return;
+}
+
 static int dummy_register (const char *name, struct security_operations *ops)
 {
 	return -EINVAL;
@@ -595,6 +631,17 @@
 	.task_prctl =			dummy_task_prctl,
 	.task_kmod_set_label =		dummy_task_kmod_set_label,
 	.task_reparent_to_init =	dummy_task_reparent_to_init,
+
+	.ipc_permission =		dummy_ipc_permission,
+	
+	.msg_queue_alloc_security =	dummy_msg_queue_alloc_security,
+	.msg_queue_free_security =	dummy_msg_queue_free_security,
+	
+	.shm_alloc_security =		dummy_shm_alloc_security,
+	.shm_free_security =		dummy_shm_free_security,
+	
+	.sem_alloc_security =		dummy_sem_alloc_security,
+	.sem_free_security =		dummy_sem_free_security,
 
 	.register_security =		dummy_register,
 	.unregister_security =		dummy_unregister,
diff -Nru a/sound/isa/als100.c b/sound/isa/als100.c
--- a/sound/isa/als100.c	Fri Oct 11 21:22:53 2002
+++ b/sound/isa/als100.c	Fri Oct 11 21:22:53 2002
@@ -23,7 +23,6 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/wait.h>
-#include <linux/sched.h>
 #include <linux/time.h>
 #ifndef LINUX_ISAPNP_H
 #include <linux/isapnp.h>
diff -Nru a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
--- a/sound/isa/opl3sa2.c	Fri Oct 11 21:23:04 2002
+++ b/sound/isa/opl3sa2.c	Fri Oct 11 21:23:04 2002
@@ -22,6 +22,7 @@
 #include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 #ifndef LINUX_ISAPNP_H
diff -Nru a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c
--- a/sound/oss/aedsp16.c	Fri Oct 11 21:22:58 2002
+++ b/sound/oss/aedsp16.c	Fri Oct 11 21:22:58 2002
@@ -1,5 +1,5 @@
 /*
-   drivers/sound/lowlevel/aedsp16.c
+   sound/oss/aedsp16.c
 
    Audio Excel DSP 16 software configuration routines
    Copyright (C) 1995,1996,1997,1998  Riccardo Facchetti (fizban@tin.it)
diff -Nru a/sound/oss/bin2hex.c b/sound/oss/bin2hex.c
--- a/sound/oss/bin2hex.c	Fri Oct 11 21:22:59 2002
+++ b/sound/oss/bin2hex.c	Fri Oct 11 21:22:59 2002
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 
 int main( int argc, const char * argv [] )
 {
diff -Nru a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
--- a/sound/oss/cs46xx.c	Fri Oct 11 21:22:50 2002
+++ b/sound/oss/cs46xx.c	Fri Oct 11 21:22:50 2002
@@ -3239,7 +3239,7 @@
 			memset(state, 0, sizeof(struct cs_state));
 			init_MUTEX(&state->sem);
 			dmabuf = &state->dmabuf;
-			dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
+			dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 			if(dmabuf->pbuf==NULL)
 			{
 				kfree(state);
@@ -3310,7 +3310,7 @@
 			memset(state, 0, sizeof(struct cs_state));
 			init_MUTEX(&state->sem);
 			dmabuf = &state->dmabuf;
-			dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
+			dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 			if(dmabuf->pbuf==NULL)
 			{
 				kfree(state);
diff -Nru a/sound/oss/maestro3.c b/sound/oss/maestro3.c
--- a/sound/oss/maestro3.c	Fri Oct 11 21:23:03 2002
+++ b/sound/oss/maestro3.c	Fri Oct 11 21:23:03 2002
@@ -192,8 +192,8 @@
     int max;
 };
 
-int external_amp = 1;
-int gpio_pin = -1;
+static int external_amp = 1;
+static int gpio_pin = -1;
 
 struct m3_state {
     unsigned int magic;
diff -Nru a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
--- a/sound/oss/opl3sa2.c	Fri Oct 11 21:22:50 2002
+++ b/sound/oss/opl3sa2.c	Fri Oct 11 21:22:50 2002
@@ -978,7 +978,7 @@
 
 static int opl3sa2_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
 {
-	unsigned char mode = (unsigned  char)data;
+	unsigned long mode = (unsigned  long)data;
 
 	switch (rqst) {
 		case PM_SUSPEND:
diff -Nru a/sound/oss/os.h b/sound/oss/os.h
--- a/sound/oss/os.h	Fri Oct 11 21:23:05 2002
+++ b/sound/oss/os.h	Fri Oct 11 21:23:05 2002
@@ -18,7 +18,6 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/param.h>
-#include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
diff -Nru a/sound/oss/vidc.c b/sound/oss/vidc.c
--- a/sound/oss/vidc.c	Fri Oct 11 21:22:52 2002
+++ b/sound/oss/vidc.c	Fri Oct 11 21:22:52 2002
@@ -451,7 +451,7 @@
 		goto mixer_failed;
 
 	for (i = 0; i < 2; i++) {
-		dma_buf[i] = get_free_page(GFP_KERNEL);
+		dma_buf[i] = get_zeroed_page(GFP_KERNEL);
 		if (!dma_buf[i]) {
 			printk(KERN_ERR "%s: can't allocate required buffers\n",
 				name);
diff -Nru a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
--- a/sound/oss/vwsnd.c	Fri Oct 11 21:22:59 2002
+++ b/sound/oss/vwsnd.c	Fri Oct 11 21:22:59 2002
@@ -535,7 +535,7 @@
 {
 	unsigned long later = jiffies + 2;
 	while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY)
-		if (jiffies >= later)
+		if (time_after_eq(jiffies, later))
 			return -EBUSY;
 	return 0;
 }
@@ -1358,7 +1358,7 @@
 	later = jiffies + HZ / 2;	/* roughly half a second */
 	DBGDO(shut_up++);
 	while (ad1843_read_bits(lith, &ad1843_PDNO)) {
-		if (jiffies > later) {
+		if (time_after(jiffies, later)) {
 			printk(KERN_ERR
 			       "vwsnd audio: AD1843 won't power up\n");
 			return -EIO;
